summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRodrigo Arias Mallo <rodarima@gmail.com>2024-12-10 22:30:12 +0100
committerRodrigo Arias Mallo <rodarima@gmail.com>2024-12-10 22:30:12 +0100
commit429d5f88b94ff28416cbfc6420b6389fa284df97 (patch)
treefb6fdaf7731de1ef396f98b748c56f3149801c84
Import RTFL 0.1.1v0.1.1
-rw-r--r--.gitignore12
-rw-r--r--AUTHORS3
-rw-r--r--COPYING674
-rw-r--r--ChangeLog149
-rw-r--r--INSTALL370
-rw-r--r--Makefile.am21
-rw-r--r--NEWS1
-rw-r--r--README149
-rw-r--r--common/Makefile.am30
-rw-r--r--common/about.cc109
-rw-r--r--common/about.hh30
-rw-r--r--common/fltk_lines.cc140
-rw-r--r--common/fltk_lines.hh52
-rw-r--r--common/lines.cc362
-rw-r--r--common/lines.hh121
-rw-r--r--common/parser.cc250
-rw-r--r--common/parser.hh47
-rw-r--r--common/rtfl_findrepeat.cc534
-rw-r--r--common/rtfl_tee.c249
-rw-r--r--common/tools.cc264
-rw-r--r--common/tools.hh80
-rw-r--r--configure.ac299
-rw-r--r--debug_rtfl.hh461
-rw-r--r--debug_rtfl.hh.in310
-rw-r--r--doc/Makefile.am4
-rw-r--r--doc/object-box-01.pngbin0 -> 18626 bytes
-rw-r--r--doc/rtfl.html997
-rw-r--r--doc/tipsandtricks.html415
-rw-r--r--dw/Makefile.am57
-rw-r--r--dw/core.hh60
-rw-r--r--dw/events.hh83
-rw-r--r--dw/findtext.cc307
-rw-r--r--dw/findtext.hh84
-rw-r--r--dw/fltkcore.hh36
-rw-r--r--dw/fltkimgbuf.cc584
-rw-r--r--dw/fltkimgbuf.hh93
-rw-r--r--dw/fltkmisc.cc58
-rw-r--r--dw/fltkmisc.hh22
-rw-r--r--dw/fltkplatform.cc739
-rw-r--r--dw/fltkplatform.hh186
-rw-r--r--dw/fltkpreview.cc316
-rw-r--r--dw/fltkpreview.hh95
-rw-r--r--dw/fltkui.cc1395
-rw-r--r--dw/fltkui.hh505
-rw-r--r--dw/fltkviewbase.cc744
-rw-r--r--dw/fltkviewbase.hh141
-rw-r--r--dw/fltkviewport.cc558
-rw-r--r--dw/fltkviewport.hh84
-rw-r--r--dw/imgbuf.hh229
-rw-r--r--dw/imgrenderer.cc77
-rw-r--r--dw/imgrenderer.hh87
-rw-r--r--dw/iterator.cc920
-rw-r--r--dw/iterator.hh271
-rw-r--r--dw/layout.cc1445
-rw-r--r--dw/layout.hh532
-rw-r--r--dw/platform.hh171
-rw-r--r--dw/preview.xbm5
-rw-r--r--dw/selection.cc494
-rw-r--r--dw/selection.hh241
-rw-r--r--dw/style.cc1468
-rw-r--r--dw/style.hh907
-rw-r--r--dw/types.cc367
-rw-r--r--dw/types.hh238
-rw-r--r--dw/ui.cc519
-rw-r--r--dw/ui.hh592
-rw-r--r--dw/view.hh211
-rw-r--r--dw/widget.cc1785
-rw-r--r--dw/widget.hh514
-rw-r--r--dwr/Makefile.am31
-rw-r--r--dwr/box.cc258
-rw-r--r--dwr/box.hh110
-rw-r--r--dwr/graph.cc642
-rw-r--r--dwr/graph.hh126
-rw-r--r--dwr/graph2.cc505
-rw-r--r--dwr/graph2.hh122
-rw-r--r--dwr/graph2_iterator.cc139
-rw-r--r--dwr/hbox.cc123
-rw-r--r--dwr/hbox.hh31
-rw-r--r--dwr/hideable.cc104
-rw-r--r--dwr/hideable.hh39
-rw-r--r--dwr/label.cc378
-rw-r--r--dwr/label.hh87
-rw-r--r--dwr/toggle.cc402
-rw-r--r--dwr/toggle.hh77
-rw-r--r--dwr/tools.cc243
-rw-r--r--dwr/tools.hh24
-rw-r--r--dwr/vbox.cc164
-rw-r--r--dwr/vbox.hh35
-rw-r--r--java/Hello.java21
-rw-r--r--java/Makefile.am46
-rw-r--r--java/README40
-rw-r--r--java/TestRtflObjects1.java50
-rw-r--r--java/class.c39
-rw-r--r--java/class.h9
-rw-r--r--java/field.c156
-rw-r--r--java/field.h12
-rw-r--r--java/main.c68
-rw-r--r--java/method.c111
-rw-r--r--java/method.h12
-rw-r--r--java/misc.c191
-rw-r--r--java/misc.h41
-rw-r--r--lout/Makefile.am21
-rw-r--r--lout/container.cc813
-rw-r--r--lout/container.hh551
-rw-r--r--lout/debug.hh381
-rw-r--r--lout/identity.cc141
-rw-r--r--lout/identity.hh149
-rw-r--r--lout/misc.cc197
-rw-r--r--lout/misc.hh652
-rw-r--r--lout/msg.h39
-rw-r--r--lout/object.cc395
-rw-r--r--lout/object.hh238
-rw-r--r--lout/signal.cc180
-rw-r--r--lout/signal.hh310
-rw-r--r--lout/unicode.cc190
-rw-r--r--lout/unicode.hh30
-rw-r--r--ltmain.sh11156
-rw-r--r--m4/libtool.m48388
-rw-r--r--m4/ltoptions.m4437
-rw-r--r--m4/ltsugar.m4124
-rw-r--r--m4/ltversion.m423
-rw-r--r--m4/lt~obsolete.m499
-rw-r--r--objects/Makefile.am67
-rw-r--r--objects/objcount_controller.cc114
-rw-r--r--objects/objcount_controller.hh50
-rw-r--r--objects/objcount_window.cc445
-rw-r--r--objects/objcount_window.hh118
-rw-r--r--objects/objdelete_controller.cc204
-rw-r--r--objects/objdelete_controller.hh78
-rw-r--r--objects/objects_buffer.cc281
-rw-r--r--objects/objects_buffer.hh88
-rw-r--r--objects/objects_parser.cc401
-rw-r--r--objects/objects_parser.hh115
-rw-r--r--objects/objects_writer.cc145
-rw-r--r--objects/objects_writer.hh44
-rw-r--r--objects/objident_controller.cc339
-rw-r--r--objects/objident_controller.hh192
-rw-r--r--objects/objview_commands.cc773
-rw-r--r--objects/objview_commands.hh349
-rw-r--r--objects/objview_controller.cc171
-rw-r--r--objects/objview_controller.hh51
-rw-r--r--objects/objview_graph.cc984
-rw-r--r--objects/objview_graph.hh305
-rw-r--r--objects/objview_stacktrace.cc127
-rw-r--r--objects/objview_stacktrace.hh60
-rw-r--r--objects/objview_window.cc707
-rw-r--r--objects/objview_window.hh189
-rw-r--r--objects/rtfl_objbase.cc45
-rw-r--r--objects/rtfl_objcount.cc40
-rw-r--r--objects/rtfl_objview.cc218
-rw-r--r--scripts/Makefile.am6
-rw-r--r--scripts/rtfl-check-objects60
-rw-r--r--scripts/rtfl-filter-out-classes63
-rwxr-xr-xscripts/rtfl-objfilter110
-rw-r--r--scripts/rtfl-objtail134
-rwxr-xr-xscripts/rtfl-stacktraces117
-rw-r--r--tests/Makefile.am137
-rw-r--r--tests/rtfl_cat.c53
-rw-r--r--tests/rtfl_trickle.c55
-rw-r--r--tests/simple_sink.cc61
-rw-r--r--tests/simple_sink.hh30
-rw-r--r--tests/test_fltk_1.cc64
-rw-r--r--tests/test_fltk_2.cc47
-rw-r--r--tests/test_graphviz_1.c46
-rw-r--r--tests/test_pipes_1.c76
-rw-r--r--tests/test_rtfl_objects_1.cc118
-rw-r--r--tests/test_rtfl_objects_1_with_rtfl.cc2
-rw-r--r--tests/test_rtfl_objects_2.cc69
-rw-r--r--tests/test_rtfl_objects_2_with_rtfl.cc2
-rw-r--r--tests/test_rtfl_objects_3.cc85
-rw-r--r--tests/test_rtfl_objects_3_with_rtfl.cc2
-rw-r--r--tests/test_rtfl_stats_1.cc54
-rw-r--r--tests/test_rtfl_stats_1_with_rtfl.cc2
-rw-r--r--tests/test_select_1.c67
-rw-r--r--tests/test_tools_1.cc97
-rw-r--r--tests/test_tools_2.cc26
-rw-r--r--tests/test_tools_3.cc16
-rw-r--r--tests/test_tools_4.cc19
-rw-r--r--tests/test_tools_5.cc37
-rw-r--r--tests/test_tools_6.cc29
-rw-r--r--tests/test_version_cmp.c49
-rw-r--r--tests/test_widget_b_splines.cc123
-rw-r--r--tests/test_widgets_1.cc142
-rw-r--r--tests/test_widgets_2.cc97
-rw-r--r--tests/test_widgets_3.cc97
-rw-r--r--tests/testtools.cc49
-rw-r--r--tests/testtools.hh14
187 files changed, 61258 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..e01432e
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,12 @@
+config.*
+autom4te.cache
+Makefile
+Makefile.in
+configure
+compile
+build
+aclocal.m4
+depcomp
+install-sh
+stamp-h1
+missing
diff --git a/AUTHORS b/AUTHORS
new file mode 100644
index 0000000..a1c94c9
--- /dev/null
+++ b/AUTHORS
@@ -0,0 +1,3 @@
+Author of RTFL is Sebastian Geerken (sgeerken-at-dillo.org). Parts are
+copied from dillo, namely "lout" and "dw", whose main author is also
+Sebastian Geerken.
diff --git a/COPYING b/COPYING
new file mode 100644
index 0000000..94a9ed0
--- /dev/null
+++ b/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>.
diff --git a/ChangeLog b/ChangeLog
new file mode 100644
index 0000000..1f2d56c
--- /dev/null
+++ b/ChangeLog
@@ -0,0 +1,149 @@
+Version 0.1.1 (Jul 31 2016)
+---------------------------
+General changes:
+- New "general" protocol module, with one command, "time".
+- Programs always read a file ".rtfl" in the current directory.
+- New program "rtfl-objbase".
+
+Rtfl-objview:
+- Some work on Graph2 (updated to Graphviz version 2.38.0, fixed rendering bug,
+ draw edges as b-splines, better library detection by configure script). It is
+ now the default.
+- Ids of deleted objects are now forgotten.
+- "obj-create" is now navigable.
+- New option "-b"/"-B".
+- Fixed bug when displaying stack trace.
+
+Miscellaneous:
+- Scripts now honour optional return values of "obj-leave".
+
+New:
+- Started work on JVM agent, which automates many RTFL messages.
+
+Internal Changes:
+- ObjectsController (and implementations), LinesSource, LinesSink.
+
+
+Version 0.1 (Feb 05 2015)
+-------------------------
+General changes:
+- Versioning of protocol modules.
+- Quoting in the protocol, so that a literal ':' is possible.
+- Macros for "obj-mark", DBG_OBJ_MARK and DBG_OBJ_MARKF.
+- "obj-leave" now supports optional return values; new macro DBG_OBJ_LEAVE_VAL.
+
+Rtfl-objview:
+- Class patterns in "obj-class-color" are now sorted by specifity.
+- Fixed redrawing and scrolling problem.
+- Fixed sorting of attributes.
+- "Switch between related" now also supports "obj-msg-start" and "obj-msg-end".
+- Attributes with no children (sub-attributes or "obj-set" commands) are now
+ hidden.
+- Colorful stacktrace.
+
+Internal changes:
+- Updated to newer version of dillo widget (revision 3948:0769a58d63f9
+ from <http://hg.dillo.org/dillo>).
+- The ascent of VBox is now the ascent of the first *visible* child.
+
+
+Version 0.0.9 (Oct 26 2014)
+---------------------------
+- New scripts "rtfl-stacktraces" and "rtfl-objfilter".
+- New filters "rtfl-findrepeat" and "rtfl-tee".
+- Updated other scripts: "obj-enter" and "obj-leave" are now regarded.
+- Options "-a" and "-A" for "rtfl-objtail".
+- Fixed parser bug.
+- New command "obj-mark".
+- New command "obj-object-color"; renamed "obj-color" to "obj-class-color".
+- Updated parser of rtfl-objcount (eventually by the common parser).
+- DBG_OBJ_COLOR: order of arguments has changed from (color, class) to
+ (class, color).
+- Rtfl-objview: Experimental graph widget based on Graphviz ("./configure
+ --enable-graph2").
+- Rtfl-objview: Attributes are sorted alphabetically on the first level.
+
+Internal changes:
+- General method Container::size() in lout::container.
+- Methods "equal" and "hashValue" work now partly for containers.
+- Common parser for objects module.
+
+
+Version 0.0.8 (Jul 20 2014)
+---------------------------
+- Scripts are now part of the RTFL package.
+- New commands "obj-enter" and "obj-leave" (and respective macros)
+- "Show strack trace" in rtfl-objview.
+- "Switch between related" commands (currently "obj-enter" and "obj-leave")
+
+
+Version 0.0.7 (May 26 2014)
+---------------------------
+- Renamed "debug.hh" to "debug_rtfl.hh" and moved it to root directory.
+- New macros DBG_OBJ_ARRATTRSET_*.
+- "obj-msg-start" and "obj-msg-end" add messages (hidden by default).
+- All navigable commands can be hidden, selectable by type.
+- Hide all/show all commands; view code of command.
+- Command line arguments.
+- Corrected macros (DBG_OBJ_MSG_START and DBG_OBJ_MSG_END).
+- Tests now in two versions: with and without RTFL messages active.
+- Fixed (or worked around) overflow error in graph widget (arrow heads).
+- Fixed overflow error in hbox and vbox widget.
+- Fixed some memory problems.
+
+
+Version 0.0.6 (Dec 29 2013)
+---------------------------
+- "\n" at the beginning of RTFL messages.
+- Fixed a bug introduced with 0.0.5 (indented messages).
+
+
+Version 0.0.5 (Dec 26 2013)
+---------------------------
+Important note: "rtfl-objects" has been renamed to "rtfl-objview", so you
+should delete the old "rtfl-objects" from the target directory (typically
+/usr/local/bin).
+
+Furthermore:
+- UI changes (menu bar).
+- Selectable and navigable command.
+- Filtering of "obj-msg".
+- New protocol command "obj-delete".
+- Fixed a bug related to "obj-ident".
+- New viewer "rtfl-objcount".
+
+Internal changes:
+- Fixed bug in dw related to inverse backgrounds.
+- Fixed handling zero size children in rtfl::dw::HBox and rtfl::dw::VBox.
+- Added link handling in rtfl::dw::Label.
+
+
+Version 0.0.4 (Dec 12 2013)
+---------------------------
+- Fixed a bug (parser) introduced by 0.0.3.
+
+
+Version 0.0.3 (Dec 12 2013)
+---------------------------
+- Numbers are preceeded to some commands.
+- Fixed two I/O related bugs (buffered reading of commands, cpu hogging).
+
+Internal changes:
+- Made parser more robust (should not crash anymore).
+
+
+Version 0.0.2 (Dec 09 2013)
+---------------------------
+- Fixed some flaws in tests/debug.hh.
+- Implemented "obj-color".
+- New command "obj-ident" and macro DBG_OBJ_BASECLASS.
+- Documentation "rtfl.html".
+
+Internal changes:
+- Some work on widgets (rtfl::dw): removeChild, registration of class names.
+- ObjectsGraph: list of commands, which can be undone (partly incomplete).
+
+
+Version 0.0.1 (Dec 01 2013)
+---------------------------
+- Initial release.
diff --git a/INSTALL b/INSTALL
new file mode 100644
index 0000000..2099840
--- /dev/null
+++ b/INSTALL
@@ -0,0 +1,370 @@
+Installation Instructions
+*************************
+
+Copyright (C) 1994-1996, 1999-2002, 2004-2013 Free Software Foundation,
+Inc.
+
+ Copying and distribution of this file, with or without modification,
+are permitted in any medium without royalty provided the copyright
+notice and this notice are preserved. This file is offered as-is,
+without warranty of any kind.
+
+Basic Installation
+==================
+
+ Briefly, the shell command `./configure && make && make install'
+should configure, build, and install this package. The following
+more-detailed instructions are generic; see the `README' file for
+instructions specific to this package. Some packages provide this
+`INSTALL' file but do not implement all of the features documented
+below. The lack of an optional feature in a given package is not
+necessarily a bug. More recommendations for GNU packages can be found
+in *note Makefile Conventions: (standards)Makefile Conventions.
+
+ The `configure' shell script attempts to guess correct values for
+various system-dependent variables used during compilation. It uses
+those values to create a `Makefile' in each directory of the package.
+It may also create one or more `.h' files containing system-dependent
+definitions. Finally, it creates a shell script `config.status' that
+you can run in the future to recreate the current configuration, and a
+file `config.log' containing compiler output (useful mainly for
+debugging `configure').
+
+ It can also use an optional file (typically called `config.cache'
+and enabled with `--cache-file=config.cache' or simply `-C') that saves
+the results of its tests to speed up reconfiguring. Caching is
+disabled by default to prevent problems with accidental use of stale
+cache files.
+
+ If you need to do unusual things to compile the package, please try
+to figure out how `configure' could check whether to do them, and mail
+diffs or instructions to the address given in the `README' so they can
+be considered for the next release. If you are using the cache, and at
+some point `config.cache' contains results you don't want to keep, you
+may remove or edit it.
+
+ The file `configure.ac' (or `configure.in') is used to create
+`configure' by a program called `autoconf'. You need `configure.ac' if
+you want to change it or regenerate `configure' using a newer version
+of `autoconf'.
+
+ The simplest way to compile this package is:
+
+ 1. `cd' to the directory containing the package's source code and type
+ `./configure' to configure the package for your system.
+
+ Running `configure' might take a while. While running, it prints
+ some messages telling which features it is checking for.
+
+ 2. Type `make' to compile the package.
+
+ 3. Optionally, type `make check' to run any self-tests that come with
+ the package, generally using the just-built uninstalled binaries.
+
+ 4. Type `make install' to install the programs and any data files and
+ documentation. When installing into a prefix owned by root, it is
+ recommended that the package be configured and built as a regular
+ user, and only the `make install' phase executed with root
+ privileges.
+
+ 5. Optionally, type `make installcheck' to repeat any self-tests, but
+ this time using the binaries in their final installed location.
+ This target does not install anything. Running this target as a
+ regular user, particularly if the prior `make install' required
+ root privileges, verifies that the installation completed
+ correctly.
+
+ 6. You can remove the program binaries and object files from the
+ source code directory by typing `make clean'. To also remove the
+ files that `configure' created (so you can compile the package for
+ a different kind of computer), type `make distclean'. There is
+ also a `make maintainer-clean' target, but that is intended mainly
+ for the package's developers. If you use it, you may have to get
+ all sorts of other programs in order to regenerate files that came
+ with the distribution.
+
+ 7. Often, you can also type `make uninstall' to remove the installed
+ files again. In practice, not all packages have tested that
+ uninstallation works correctly, even though it is required by the
+ GNU Coding Standards.
+
+ 8. Some packages, particularly those that use Automake, provide `make
+ distcheck', which can by used by developers to test that all other
+ targets like `make install' and `make uninstall' work correctly.
+ This target is generally not run by end users.
+
+Compilers and Options
+=====================
+
+ Some systems require unusual options for compilation or linking that
+the `configure' script does not know about. Run `./configure --help'
+for details on some of the pertinent environment variables.
+
+ You can give `configure' initial values for configuration parameters
+by setting variables in the command line or in the environment. Here
+is an example:
+
+ ./configure CC=c99 CFLAGS=-g LIBS=-lposix
+
+ *Note Defining Variables::, for more details.
+
+Compiling For Multiple Architectures
+====================================
+
+ You can compile the package for more than one kind of computer at the
+same time, by placing the object files for each architecture in their
+own directory. To do this, you can use GNU `make'. `cd' to the
+directory where you want the object files and executables to go and run
+the `configure' script. `configure' automatically checks for the
+source code in the directory that `configure' is in and in `..'. This
+is known as a "VPATH" build.
+
+ With a non-GNU `make', it is safer to compile the package for one
+architecture at a time in the source code directory. After you have
+installed the package for one architecture, use `make distclean' before
+reconfiguring for another architecture.
+
+ On MacOS X 10.5 and later systems, you can create libraries and
+executables that work on multiple system types--known as "fat" or
+"universal" binaries--by specifying multiple `-arch' options to the
+compiler but only a single `-arch' option to the preprocessor. Like
+this:
+
+ ./configure CC="gcc -arch i386 -arch x86_64 -arch ppc -arch ppc64" \
+ CXX="g++ -arch i386 -arch x86_64 -arch ppc -arch ppc64" \
+ CPP="gcc -E" CXXCPP="g++ -E"
+
+ This is not guaranteed to produce working output in all cases, you
+may have to build one architecture at a time and combine the results
+using the `lipo' tool if you have problems.
+
+Installation Names
+==================
+
+ By default, `make install' installs the package's commands under
+`/usr/local/bin', include files under `/usr/local/include', etc. You
+can specify an installation prefix other than `/usr/local' by giving
+`configure' the option `--prefix=PREFIX', where PREFIX must be an
+absolute file name.
+
+ You can specify separate installation prefixes for
+architecture-specific files and architecture-independent files. If you
+pass the option `--exec-prefix=PREFIX' to `configure', the package uses
+PREFIX as the prefix for installing programs and libraries.
+Documentation and other data files still use the regular prefix.
+
+ In addition, if you use an unusual directory layout you can give
+options like `--bindir=DIR' to specify different values for particular
+kinds of files. Run `configure --help' for a list of the directories
+you can set and what kinds of files go in them. In general, the
+default for these options is expressed in terms of `${prefix}', so that
+specifying just `--prefix' will affect all of the other directory
+specifications that were not explicitly provided.
+
+ The most portable way to affect installation locations is to pass the
+correct locations to `configure'; however, many packages provide one or
+both of the following shortcuts of passing variable assignments to the
+`make install' command line to change installation locations without
+having to reconfigure or recompile.
+
+ The first method involves providing an override variable for each
+affected directory. For example, `make install
+prefix=/alternate/directory' will choose an alternate location for all
+directory configuration variables that were expressed in terms of
+`${prefix}'. Any directories that were specified during `configure',
+but not in terms of `${prefix}', must each be overridden at install
+time for the entire installation to be relocated. The approach of
+makefile variable overrides for each directory variable is required by
+the GNU Coding Standards, and ideally causes no recompilation.
+However, some platforms have known limitations with the semantics of
+shared libraries that end up requiring recompilation when using this
+method, particularly noticeable in packages that use GNU Libtool.
+
+ The second method involves providing the `DESTDIR' variable. For
+example, `make install DESTDIR=/alternate/directory' will prepend
+`/alternate/directory' before all installation names. The approach of
+`DESTDIR' overrides is not required by the GNU Coding Standards, and
+does not work on platforms that have drive letters. On the other hand,
+it does better at avoiding recompilation issues, and works well even
+when some directory options were not specified in terms of `${prefix}'
+at `configure' time.
+
+Optional Features
+=================
+
+ If the package supports it, you can cause programs to be installed
+with an extra prefix or suffix on their names by giving `configure' the
+option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
+
+ Some packages pay attention to `--enable-FEATURE' options to
+`configure', where FEATURE indicates an optional part of the package.
+They may also pay attention to `--with-PACKAGE' options, where PACKAGE
+is something like `gnu-as' or `x' (for the X Window System). The
+`README' should mention any `--enable-' and `--with-' options that the
+package recognizes.
+
+ For packages that use the X Window System, `configure' can usually
+find the X include and library files automatically, but if it doesn't,
+you can use the `configure' options `--x-includes=DIR' and
+`--x-libraries=DIR' to specify their locations.
+
+ Some packages offer the ability to configure how verbose the
+execution of `make' will be. For these packages, running `./configure
+--enable-silent-rules' sets the default to minimal output, which can be
+overridden with `make V=1'; while running `./configure
+--disable-silent-rules' sets the default to verbose, which can be
+overridden with `make V=0'.
+
+Particular systems
+==================
+
+ On HP-UX, the default C compiler is not ANSI C compatible. If GNU
+CC is not installed, it is recommended to use the following options in
+order to use an ANSI C compiler:
+
+ ./configure CC="cc -Ae -D_XOPEN_SOURCE=500"
+
+and if that doesn't work, install pre-built binaries of GCC for HP-UX.
+
+ HP-UX `make' updates targets which have the same time stamps as
+their prerequisites, which makes it generally unusable when shipped
+generated files such as `configure' are involved. Use GNU `make'
+instead.
+
+ On OSF/1 a.k.a. Tru64, some versions of the default C compiler cannot
+parse its `<wchar.h>' header file. The option `-nodtk' can be used as
+a workaround. If GNU CC is not installed, it is therefore recommended
+to try
+
+ ./configure CC="cc"
+
+and if that doesn't work, try
+
+ ./configure CC="cc -nodtk"
+
+ On Solaris, don't put `/usr/ucb' early in your `PATH'. This
+directory contains several dysfunctional programs; working variants of
+these programs are available in `/usr/bin'. So, if you need `/usr/ucb'
+in your `PATH', put it _after_ `/usr/bin'.
+
+ On Haiku, software installed for all users goes in `/boot/common',
+not `/usr/local'. It is recommended to use the following options:
+
+ ./configure --prefix=/boot/common
+
+Specifying the System Type
+==========================
+
+ There may be some features `configure' cannot figure out
+automatically, but needs to determine by the type of machine the package
+will run on. Usually, assuming the package is built to be run on the
+_same_ architectures, `configure' can figure that out, but if it prints
+a message saying it cannot guess the machine type, give it the
+`--build=TYPE' option. TYPE can either be a short name for the system
+type, such as `sun4', or a canonical name which has the form:
+
+ CPU-COMPANY-SYSTEM
+
+where SYSTEM can have one of these forms:
+
+ OS
+ KERNEL-OS
+
+ See the file `config.sub' for the possible values of each field. If
+`config.sub' isn't included in this package, then this package doesn't
+need to know the machine type.
+
+ If you are _building_ compiler tools for cross-compiling, you should
+use the option `--target=TYPE' to select the type of system they will
+produce code for.
+
+ If you want to _use_ a cross compiler, that generates code for a
+platform different from the build platform, you should specify the
+"host" platform (i.e., that on which the generated programs will
+eventually be run) with `--host=TYPE'.
+
+Sharing Defaults
+================
+
+ If you want to set default values for `configure' scripts to share,
+you can create a site shell script called `config.site' that gives
+default values for variables like `CC', `cache_file', and `prefix'.
+`configure' looks for `PREFIX/share/config.site' if it exists, then
+`PREFIX/etc/config.site' if it exists. Or, you can set the
+`CONFIG_SITE' environment variable to the location of the site script.
+A warning: not all `configure' scripts look for a site script.
+
+Defining Variables
+==================
+
+ Variables not defined in a site shell script can be set in the
+environment passed to `configure'. However, some packages may run
+configure again during the build, and the customized values of these
+variables may be lost. In order to avoid this problem, you should set
+them in the `configure' command line, using `VAR=value'. For example:
+
+ ./configure CC=/usr/local2/bin/gcc
+
+causes the specified `gcc' to be used as the C compiler (unless it is
+overridden in the site shell script).
+
+Unfortunately, this technique does not work for `CONFIG_SHELL' due to
+an Autoconf limitation. Until the limitation is lifted, you can use
+this workaround:
+
+ CONFIG_SHELL=/bin/bash ./configure CONFIG_SHELL=/bin/bash
+
+`configure' Invocation
+======================
+
+ `configure' recognizes the following options to control how it
+operates.
+
+`--help'
+`-h'
+ Print a summary of all of the options to `configure', and exit.
+
+`--help=short'
+`--help=recursive'
+ Print a summary of the options unique to this package's
+ `configure', and exit. The `short' variant lists options used
+ only in the top level, while the `recursive' variant lists options
+ also present in any nested packages.
+
+`--version'
+`-V'
+ Print the version of Autoconf used to generate the `configure'
+ script, and exit.
+
+`--cache-file=FILE'
+ Enable the cache: use and save the results of the tests in FILE,
+ traditionally `config.cache'. FILE defaults to `/dev/null' to
+ disable caching.
+
+`--config-cache'
+`-C'
+ Alias for `--cache-file=config.cache'.
+
+`--quiet'
+`--silent'
+`-q'
+ Do not print messages saying which checks are being made. To
+ suppress all normal output, redirect it to `/dev/null' (any error
+ messages will still be shown).
+
+`--srcdir=DIR'
+ Look for the package's source code in directory DIR. Usually
+ `configure' can determine that directory automatically.
+
+`--prefix=DIR'
+ Use DIR as the installation prefix. *note Installation Names::
+ for more details, including other options available for fine-tuning
+ the installation locations.
+
+`--no-create'
+`-n'
+ Run the configure checks, but stop before creating any output
+ files.
+
+`configure' also accepts some other, not widely useful, options. Run
+`configure --help' for more details.
diff --git a/Makefile.am b/Makefile.am
new file mode 100644
index 0000000..acee8ce
--- /dev/null
+++ b/Makefile.am
@@ -0,0 +1,21 @@
+SUBDIRS = lout common dw dwr objects scripts tests doc
+
+if HAS_JAVA
+ SUBDIRS += java
+endif
+
+ACLOCAL_AMFLAGS=-I m4
+
+# "debug_rtfl.hh" is generated from "debug_rtfl.hh.in". When calling
+# "make", the subdirectories are processed before "debug_rtfl.hh" is
+# generated, so it may be that you have to generate it explicitly by
+# calling "make debug_rtfl.hh".
+
+# For convenience, "debug_rtfl.hh" is included into the distribution.
+# Furthermore (mainly because of the problem mentioned above), it is
+# also added to the SVN repository.
+
+EXTRA_DIST = debug_rtfl.hh debug_rtfl.hh.in
+
+debug_rtfl.hh: debug_rtfl.hh.in create-debug_rtfl-hh
+ ./create-debug_rtfl-hh < debug_rtfl.hh.in > debug_rtfl.hh
diff --git a/NEWS b/NEWS
new file mode 100644
index 0000000..898a3da
--- /dev/null
+++ b/NEWS
@@ -0,0 +1 @@
+See ChangeLog.
diff --git a/README b/README
new file mode 100644
index 0000000..2d09acb
--- /dev/null
+++ b/README
@@ -0,0 +1,149 @@
+Overview
+--------
+RTFL, which stands for "Read The Figurative Logfile", is a both a
+protocol for structured debug messages, as well as a collection of
+programs (currently two) displaying these debug messages in a
+semi-graphical way, so that it becomes simpler to determine what the
+debugged program does.
+
+Programs are prepared to print these special debug messages to
+standard output, which are then passed to a viewer program like
+"rtfl-objcount" or "rtfl-objview".
+
+See "doc/rtfl.html" for a comprehensive description.
+
+
+Copyright
+---------
+RTFL is free software, released under the GPL version 3 or later (see
+COPYING for details), with the following exception:
+
+The copyright holders of RTFL give you permission to link the program
+rtfl-objview statically or dynamically against all versions of the
+graphviz library, which are published by AT&T Corp. under one of the
+following licenses:
+
+- Common Public License version 1.0 as published by International
+ Business Machines Corporation (IBM), or
+- Eclipse Public License version 1.0 as published by the Eclipse
+ Foundation.
+
+Both the protocol and the header file "debug_rtfl.hh", which provides
+macros for the protocol, are not protected at all, but in the public
+domain. This means that are no restrictions for the programs being
+debugged using RTFL.
+
+Some (informal) notes about the exception:
+
+1. Graphviz, which is used by the Graph2 widget, is published under
+ the Eclipse Public License version 1.0, older versions are
+ published under the Common Public License version 1.0. Both
+ licenses are free software licenses, but weak copyleft licenses,
+ and so incompatible with any version the GNU General Public
+ License. See [1] and [2] for details. The license exception solves
+ this.
+
+2. Since the CPL and EPL are *weak* copyleft licenses, there is no
+ problem in the other direction.
+
+3. All parts of RTFL are still compatible with the GNU GPL.
+
+4. I want to restrict this license exception to free libraries; this
+ is the reason that the CPL and the EPL are explicitly mentioned. If
+ you have some "technical" problems with this limitation, feel free
+ to contact me (see below).
+
+
+Building
+--------
+As usual: "./configure && make && make install" (or "install-strip");
+see "INSTALL" for details. If you are using the version from SVN
+instead of the release tarball, you have to run "libtoolize && aclocal
+&& autoconf && automake" before.
+
+You need FLTK version 1.3 (try "fltk-config --version"). Get it from
+<http://fltk.org/software.php>, or install a package suitable for your
+operating system (on Debian: "apt-get install libfltk1.3-dev").
+
+There is a widget, Graph2, which enhances the graph layouting of
+rtfl-objview, as compared to the older Graph widget, and it has
+matured enough to become the default. It depends on the Graphviz
+library (see <http://www.graphviz.org/Download.php> or install a
+suitable package, e. g. "libgraphviz-dev" on Debian), version 2.38.0
+or later. If you use an older version, try to modify "configure.ac";
+if you succeed, drop me a note.
+
+If Graphviz is not installed, the old Graph widget is used. If you
+want to use the old Graph widget in any case, run "./configure" with
+"--disable-graph2" to use the old widget.
+
+Furthermore, there has been some work on a Java VM agent, which
+automates generation of RTFL messages by Java programs. The JDK is
+searched according to following rules:
+
+ (i) If "--disable-java" is passed to "./configure", the JVM agent is
+ not build at all.
+ (ii) The root of the JDK (under which "bin", "include" etc. are
+ found) may be passed explicitly by "--with-java-home=...".
+(iii) Otherwise, "javac" is found in the path, its symbolic links are
+ followed, and so the root of the JDK is searched.
+
+Of course, if "javac" is not found, or some crucial files within the
+JDK are missing, the agent is neither build.
+
+See java/README for more details.
+
+
+Hacking
+-------
+RTFL uses parts of the dillo widget from the dillo web browser
+(<http://www.dillo.org/>); see "lout" and "dw" directory. The current
+version was taken on Oct 27 2014 from the repository
+<http://hg.dillo.org/dillo>, revision 3948:0769a58d63f9. Few changes
+are generally made:
+
+- the parts of "libDw-widgets.a" are removed, they are not needed in
+ RTFL;
+
+- dw::fltk::ui:ComplexButtonResource and related classes and files
+ (FltkFlatView and ComplexButton) are removed, since they are not
+ needed, and (this is actually the main reason) the copyright of
+ ComplexButton is a bit unclear [3];
+
+- the copyright notices are modified by adding the license exception
+ (this is automated with the script "update_copyright" which is part
+ of the SVN repository, albeit not release tarball).
+
+Smaller changes to "lout" and "dw" can be made within RTFL; from time
+to time, these changes should be back-ported, before a new version of
+"lout" and "dw" is copied to RTFL.
+
+The directory "dwr" provides some general dillo widgets used in RTFL,
+and "common" base code for all viewers and protocol modules. Specific
+viewers and protocol modules have there own directory (currently only
+"objects": may become subject to change.)
+
+
+Future
+------
+First of all, there are numerous bugs, flaws, and things to
+improve. (No list yet.)
+
+For more, see the file <http://home.gna.org/rtfl/future.html".
+
+
+Contact
+-------
+Write to Sebastian Geerken <sgeerken-at-dillo.org>. See
+<http://home.gna.org/rtfl/> for news.
+
+
+Footnotes
+---------
+[1] http://www.gnu.org/philosophy/license-list.html#CommonPublicLicense10
+
+[2] http://www.gnu.org/philosophy/license-list.html#EPL
+
+[3] Nothing serious; ComplexButton is a derivate of the Button widget
+ of FLTK, which is released under the GNU LGPL, so that linking
+ with the graphviz library should not cause a problem.
diff --git a/common/Makefile.am b/common/Makefile.am
new file mode 100644
index 0000000..b8e1313
--- /dev/null
+++ b/common/Makefile.am
@@ -0,0 +1,30 @@
+# Notes about libraries: "librtfl-tools.a" contains everything not
+# depending on FLTK, which can so be used in command line tools;
+# "librtfl-common.a" depens on FLTK, and also on the former.
+
+AM_CPPFLAGS = \
+ -I$(top_srcdir)
+
+noinst_LIBRARIES = librtfl-common.a librtfl-tools.a
+
+bin_PROGRAMS = rtfl-findrepeat rtfl-tee
+
+librtfl_common_a_SOURCES = \
+ about.hh \
+ about.cc \
+ fltk_lines.hh \
+ fltk_lines.cc
+
+librtfl_tools_a_SOURCES = \
+ lines.hh \
+ lines.cc \
+ parser.hh \
+ parser.cc \
+ tools.hh \
+ tools.cc
+
+rtfl_findrepeat_SOURCES = rtfl_findrepeat.cc
+
+rtfl_findrepeat_LDADD = librtfl-tools.a ../lout/liblout.a
+
+rtfl_tee_SOURCES = rtfl_tee.c
diff --git a/common/about.cc b/common/about.cc
new file mode 100644
index 0000000..01ad3ac
--- /dev/null
+++ b/common/about.cc
@@ -0,0 +1,109 @@
+/*
+ * RTFL
+ *
+ * Copyright 2013-2015 Sebastian Geerken <sgeerken@dillo.org>
+ *
+ * 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; with the following exception:
+ *
+ * The copyright holders of RTFL give you permission to link this file
+ * statically or dynamically against all versions of the graphviz
+ * library, which are published by AT&T Corp. under one of the following
+ * licenses:
+ *
+ * - Common Public License version 1.0 as published by International
+ * Business Machines Corporation (IBM), or
+ * - Eclipse Public License version 1.0 as published by the Eclipse
+ * Foundation.
+ *
+ * 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/>.
+ */
+
+#include "about.hh"
+
+#include "config.h"
+
+#include <FL/Fl_Return_Button.H>
+#include <FL/Fl_Box.H>
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <ctype.h>
+
+namespace rtfl {
+
+namespace common {
+
+void AboutWindow::close (Fl_Widget *widget, void *data)
+{
+ ((AboutWindow*)data)->hide ();
+}
+
+
+AboutWindow::AboutWindow (const char *prgName, const char *licenceException,
+ int height) :
+ Fl_Window (WIDTH, height, "")
+{
+
+ const char *titleFmt = "RTFL: About %s";
+ const char *textFmt =
+ "%s " VERSION "\n"
+ "\n"
+ "%s is part of RTFL (Read The Figurative Logfile).\n"
+ "\n"
+ "Copyright 2013-2015 Sebastian Geerken <sgeerken@@dillo.org>\n"
+ "\n"
+ "RTFL 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%s.\n"
+ "\n"
+ "With RTFL comes some documentation, see “doc/rtfl.html” in the "
+ "tarball. For more informations, updates etc. see "
+ "<http://home.gna.org/rtfl/>.";
+
+ int titleLen = strlen (titleFmt) - 2 + strlen (prgName) + 1;
+ title = new char [titleLen];
+ snprintf (title, titleLen, titleFmt, prgName);
+ label (title);
+
+ char *capName = strdup (prgName);
+ capName[0] = toupper (capName[0]);
+ int textLen =
+ strlen (textFmt) - 2 + strlen (prgName) - 2 + strlen (capName) + 1
+ - 2 + strlen (licenceException);
+ text = new char[textLen];
+ snprintf (text, textLen, textFmt, prgName, capName, licenceException);
+ free (capName);
+
+ Fl_Box *textWidget =
+ new Fl_Box(SPACE, SPACE, WIDTH - 2 * SPACE,
+ height - 3 * SPACE - BUTTON_HEIGHT, text);
+ textWidget->box(FL_NO_BOX);
+ textWidget->align(FL_ALIGN_WRAP);
+
+ Fl_Return_Button *close =
+ new Fl_Return_Button(WIDTH - BUTTON_WIDTH - SPACE,
+ height - BUTTON_HEIGHT - SPACE, BUTTON_WIDTH,
+ BUTTON_HEIGHT, "Close");
+ close->callback (AboutWindow::close, this);
+}
+
+AboutWindow::~AboutWindow ()
+{
+ delete[] title;
+ delete[] text;
+}
+
+} // namespace common
+
+} // namespace rtfl
diff --git a/common/about.hh b/common/about.hh
new file mode 100644
index 0000000..2a46483
--- /dev/null
+++ b/common/about.hh
@@ -0,0 +1,30 @@
+#ifndef __COMMON_ABOUT_HH__
+#define __COMMON_ABOUT_HH__
+
+#include <FL/Fl_Window.H>
+
+namespace rtfl {
+
+namespace common {
+
+class AboutWindow: public Fl_Window
+{
+private:
+ char *title, *text;
+
+ static void close (Fl_Widget *widget, void *data);
+
+ enum { WIDTH = 450, BUTTON_WIDTH = 80, BUTTON_HEIGHT = 25, SPACE = 10 };
+
+public:
+ enum { HEIGHT_SIMPLE = 300, HEIGHT_EXCEPTION = 480 };
+
+ AboutWindow (const char *prgName, const char *licenceException, int height);
+ ~AboutWindow ();
+};
+
+} // namespace common
+
+} // namespace rtfl
+
+#endif // __COMMON_ABOUT_HH__
diff --git a/common/fltk_lines.cc b/common/fltk_lines.cc
new file mode 100644
index 0000000..5bf4b00
--- /dev/null
+++ b/common/fltk_lines.cc
@@ -0,0 +1,140 @@
+/*
+ * RTFL
+ *
+ * Copyright 2013-2015 Sebastian Geerken <sgeerken@dillo.org>
+ *
+ * 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; with the following exception:
+ *
+ * The copyright holders of RTFL give you permission to link this file
+ * statically or dynamically against all versions of the graphviz
+ * library, which are published by AT&T Corp. under one of the following
+ * licenses:
+ *
+ * - Common Public License version 1.0 as published by International
+ * Business Machines Corporation (IBM), or
+ * - Eclipse Public License version 1.0 as published by the Eclipse
+ * Foundation.
+ *
+ * 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/>.
+ */
+
+#include "fltk_lines.hh"
+
+#include <stdio.h>
+#include <fcntl.h>
+#include <Fl/Fl.H>
+
+using namespace lout::container::typed;
+
+namespace rtfl {
+
+namespace common {
+
+// -------------------------
+// FltkLinesSource
+// -------------------------
+
+FltkLinesSource::TimeoutInfo::TimeoutInfo (FltkLinesSource *source, int type)
+{
+ this->source = source;
+ this->type = type;
+}
+
+FltkLinesSource::FltkLinesSource ()
+{
+ timeoutInfos = new List<TimeoutInfo> (true);
+}
+
+FltkLinesSource::~FltkLinesSource ()
+{
+ delete timeoutInfos;
+}
+
+void FltkLinesSource::staticProcessInputCallback (int fd, void *data)
+{
+ ((FltkLinesSource*)data)->processInputCallback (fd);
+}
+
+void FltkLinesSource::processInputCallback (int fd)
+{
+ int n = processInput (fd);
+
+ if (n == 0) {
+ // We read non-blocking, so -1 is returned and (errno set to
+ // EAGAIN) when no data is currently available. When 0 is
+ // returned, this means that there is permanently no data
+ // (typically that the tested program has terminated). For some
+ // reasons, the cpu is hogged then; this is avoided by removing
+ // the read function again.
+ Fl::remove_fd(0, FL_READ);
+ getSink()->finish ();
+ }
+}
+
+void FltkLinesSource::setup (tools::LinesSink *sink)
+{
+ setSink (sink);
+
+ int flags = fcntl(0, F_GETFL, 0);
+ fcntl(0, F_SETFL, flags | O_NONBLOCK);
+
+ Fl::add_fd(0, FL_READ, staticProcessInputCallback, (void*)this);
+}
+
+void FltkLinesSource::addTimeout (double secs, int type)
+{
+ TimeoutInfo *timeoutInfo = new TimeoutInfo (this, type);
+ timeoutInfos->append (timeoutInfo);
+ Fl::add_timeout(secs, timeoutCallback, timeoutInfo);
+}
+
+void FltkLinesSource::timeoutCallback (void *data)
+{
+ TimeoutInfo *timeoutInfo = (TimeoutInfo*) data;
+ timeoutInfo->getSource()->getSink()->timeout (timeoutInfo->getType ());
+ timeoutInfo->getSource()->timeoutInfos->removeRef (timeoutInfo);
+}
+
+void FltkLinesSource::removeTimeout (int type)
+{
+ // Iterators will not work when the set is modified; hence this nested loop.
+ bool found;
+ do {
+ found = false;
+ for (Iterator<TimeoutInfo> it = timeoutInfos->iterator ();
+ !found && it.hasNext (); ) {
+ TimeoutInfo *timeout = it.getNext();
+ if (timeout->getType () == type) {
+ found = true;
+ Fl::remove_timeout(timeoutCallback, timeout);
+ timeoutInfos->removeRef (timeout);
+ }
+ }
+ } while (found);
+}
+
+// ---------------------------
+// FltkDefaultSource
+// ---------------------------
+
+FltkDefaultSource::FltkDefaultSource (): LinesSourceSequence (true)
+{
+ int fd = open (".rtfl", O_RDONLY);
+ if (fd != -1)
+ add (new tools::BlockingLinesSource (fd));
+
+ add (new FltkLinesSource ());
+}
+
+} // namespace objects
+
+} // namespace rtfl
diff --git a/common/fltk_lines.hh b/common/fltk_lines.hh
new file mode 100644
index 0000000..424ab82
--- /dev/null
+++ b/common/fltk_lines.hh
@@ -0,0 +1,52 @@
+#ifndef __COMMON_FLTK_LINES_HH__
+#define __COMMON_FLTK_LINES_HH__
+
+#include "lines.hh"
+
+namespace rtfl {
+
+namespace common {
+
+class FltkLinesSource: public tools::FileLinesSource
+{
+ class TimeoutInfo: public lout::object::Object
+ {
+ private:
+ FltkLinesSource *source;
+ int type;
+
+ public:
+ TimeoutInfo (FltkLinesSource *source, int type);
+
+ inline FltkLinesSource *getSource () { return source; }
+ inline int getType () { return type; }
+ };
+
+ lout::container::typed::List<TimeoutInfo> *timeoutInfos;
+
+ static void staticProcessInputCallback (int fd, void *data);
+ static void timeoutCallback (void *data);
+ void processInputCallback (int fd);
+
+public:
+ FltkLinesSource ();
+ ~FltkLinesSource ();
+
+ void setup (tools::LinesSink *sink);
+ void addTimeout (double secs, int type);
+ void removeTimeout (int type);
+};
+
+
+class FltkDefaultSource: public tools::LinesSourceSequence
+{
+public:
+ FltkDefaultSource ();
+};
+
+
+} // namespace common
+
+} // namespace rtfl
+
+#endif // __COMMON_FLTK_LINES_HH__
diff --git a/common/lines.cc b/common/lines.cc
new file mode 100644
index 0000000..e6fa8c2
--- /dev/null
+++ b/common/lines.cc
@@ -0,0 +1,362 @@
+/*
+ * RTFL
+ *
+ * Copyright 2015 Sebastian Geerken <sgeerken@dillo.org>
+ *
+ * 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; with the following exception:
+ *
+ * The copyright holders of RTFL give you permission to link this file
+ * statically or dynamically against all versions of the graphviz
+ * library, which are published by AT&T Corp. under one of the following
+ * licenses:
+ *
+ * - Common Public License version 1.0 as published by International
+ * Business Machines Corporation (IBM), or
+ * - Eclipse Public License version 1.0 as published by the Eclipse
+ * Foundation.
+ *
+ * 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/>.
+ */
+
+#include "lines.hh"
+#include "tools.hh"
+
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/select.h>
+#include <sys/timeb.h>
+
+#if 0
+# define PRINT(fmt) printf ("---- [%p] " fmt "\n", this)
+# define PRINTF(fmt, ...) printf ("---- [%p] " fmt "\n", this, __VA_ARGS__)
+#else
+# define PRINT(fmt)
+# define PRINTF(fmt, ...)
+#endif
+
+using namespace lout::container::typed;
+using namespace lout::misc;
+
+namespace rtfl {
+
+namespace tools {
+
+// -----------------------------
+// LinesSourceSequence
+// -----------------------------
+
+LinesSourceSequence::VirtualSink::VirtualSink ()
+{
+}
+
+void LinesSourceSequence::VirtualSink::processLine (char *line)
+{
+ sequence->sink->processLine (line);
+}
+
+void LinesSourceSequence::VirtualSink::setLinesSource (LinesSource *source)
+{
+}
+
+void LinesSourceSequence::VirtualSink::finish ()
+{
+ // If a child source calls sink->finish() within setup(), this is
+ // called recursively, but this does not cause problems.
+
+ if (sequence->iterator.hasNext ()) {
+ LinesSource *source = sequence->iterator.getNext ();
+ source->setup (this);
+ } else {
+ sequence->sink->finish ();
+ }
+}
+
+void LinesSourceSequence::VirtualSink::timeout (int type)
+{
+ sequence->sink->timeout (type);
+}
+
+LinesSourceSequence::LinesSourceSequence (bool ownerOfSources)
+{
+ virtualSink.sequence = this;
+ sources = new List<LinesSource> (ownerOfSources);
+ setupCalled = false;
+}
+
+LinesSourceSequence::~LinesSourceSequence ()
+{
+ delete sources;
+}
+
+void LinesSourceSequence::add (LinesSource *source)
+{
+ assert (!setupCalled);
+ sources->append (source);
+}
+
+void LinesSourceSequence::setup (LinesSink *sink)
+{
+ this->sink = sink;
+ sink->setLinesSource (this);
+ setupCalled = true;
+ iterator = sources->iterator ();
+ virtualSink.finish ();
+}
+
+void LinesSourceSequence::addTimeout (double secs, int type)
+{
+ // TODO: After calling this, no source should be added.
+ // TODO: Processed timeouts must be removed from other sources as well?
+
+ // Sent to all, even if only one child source will actually trigger the
+ // timeout; but we do not know which one.
+
+ // In the real world, LinesSourceSequence is used for ".rtfl" and stdin, so
+ // we do not have to worry too much about correctly handling timeouts.
+
+ for (Iterator<LinesSource> it = sources->iterator (); it.hasNext (); ) {
+ it.getNext()->addTimeout (secs, type);
+ }
+}
+
+void LinesSourceSequence::removeTimeout (int type)
+{
+ for (Iterator<LinesSource> it = sources->iterator (); it.hasNext (); ) {
+ it.getNext()->removeTimeout (type);
+ }
+}
+
+// -------------------------
+// FileLinesSource
+// -------------------------
+
+FileLinesSource::FileLinesSource ()
+{
+ bufPos = 0;
+ completeLine = true;
+}
+
+int FileLinesSource::processInput (int fd)
+{
+ int n;
+ if ((n = read (fd, buf + bufPos, MAX_LINE_SIZE - bufPos)) > 0) {
+ int bytesAvail = bufPos + n;
+ int startOfLine = 0;
+ bool lineProcessed;
+
+ //printf ("--> %d bytes read, %d available\n", n, bytesAvail);
+
+ do {
+ lineProcessed = false;
+ for (int i = startOfLine; !lineProcessed && i < bytesAvail; i++) {
+ if (buf[i] == '\n') {
+ buf[i] = 0;
+
+ // If lines are too long (see below, where completeLine
+ // is set to false), they are not processed.
+ if (completeLine)
+ sink->processLine (buf + startOfLine);
+
+ lineProcessed = true;
+ startOfLine = i + 1;
+
+ completeLine = true;
+ }
+ }
+ } while (lineProcessed);
+
+ memmove (buf, buf + startOfLine, bytesAvail - startOfLine);
+ bufPos = bytesAvail - startOfLine;
+
+ PRINTF ("processInput: %d bytes left in buffer", bufPos);
+
+ // Handle case when line is to large (> MAX_LINE_SIZE
+ // bytes). The whole line is discarded (completeLine), so we
+ // empty the buffer by setting bufPos to 0.
+ if (bufPos == MAX_LINE_SIZE) {
+ bufPos = 0;
+ completeLine = false;
+ }
+
+ //printf (" --> %d processed, new pos: %d; will read %d\n",
+ // startOfLine, bufPos, MAX_LINE_SIZE - bufPos);
+ }
+
+ //printf (" --> read(2) returns %d\n", n);
+
+ return n;
+}
+
+// -----------------------------
+// BlockingLinesSource
+// -----------------------------
+
+BlockingLinesSource::TimeoutInfo::TimeoutInfo (long time, int type)
+{
+ this->time = time;
+ this->type = type;
+}
+
+bool BlockingLinesSource::TimeoutInfo::equals(Object *other)
+{
+ return time == ((TimeoutInfo*)other)->time &&
+ type == ((TimeoutInfo*)other)->type;
+}
+
+int BlockingLinesSource::TimeoutInfo::hashValue()
+{
+ // This should better be hidden in lout::objects. Cf. Pointer::hashValue().
+#if SIZEOF_LONG == 4
+ return (int)time ^ type;
+#else
+ return ((intptr_t)time >> 32) ^ ((intptr_t)time) ^ type;
+#endif
+}
+
+BlockingLinesSource::BlockingLinesSource (int fd)
+{
+ this->fd = fd;
+ timeoutInfos = new HashSet<TimeoutInfo> (true);
+}
+
+BlockingLinesSource::~BlockingLinesSource ()
+{
+ delete timeoutInfos;
+}
+
+void BlockingLinesSource::setup (LinesSink *sink)
+{
+ setSink (sink);
+
+ // We read non-blocking so that select(2) will work properly.
+ // (FileLinesSource::processInput would block otherwise.)
+ int flags = fcntl(0, F_GETFL, 0);
+ fcntl(0, F_SETFL, flags | O_NONBLOCK);
+
+ bool eos = false;
+ while (!eos) {
+ fd_set readfds;
+ FD_ZERO (&readfds);
+ FD_SET (fd, &readfds);
+
+ TimeoutInfo *nextTimeout = getNextTimeoutInfo ();
+
+ struct timeval tv, *tvp;
+ if (nextTimeout == NULL) {
+ tvp = NULL;
+ PRINT ("no timeout");
+ } else {
+ long tdelta = max (nextTimeout->getTime () - getCurrentTime (), 0L);
+ tv.tv_sec = tdelta / 1000;
+ tv.tv_usec = (tdelta % 1000) * 1000;
+ tvp = &tv;
+ PRINTF ("waiting %ld (%ld, %ld)", tdelta, tv.tv_sec, tv.tv_usec);
+ }
+
+ PRINT (">> processTimeouts");
+ processTimeouts ();
+ PRINT ("<< processTimeouts");
+
+ PRINT (">> select");
+ if (select (fd + 1, &readfds, NULL, NULL, tvp) == -1)
+ syserr ("select failed");
+ PRINT ("<< select");
+
+ processTimeouts ();
+
+ if (FD_ISSET (fd, &readfds)) {
+ PRINT (">> processInput");
+ int n = processInput (fd);
+ PRINT ("<< processInput");
+ if (n == 0) {
+ eos = true;
+ }
+ }
+ }
+
+ close (fd);
+ sink->finish ();
+}
+
+void BlockingLinesSource::addTimeout (double secs, int type)
+{
+ PRINTF ("addTimeout (%g, %d)", secs, type);
+ timeoutInfos->put (new TimeoutInfo (getCurrentTime () + secs * 1000, type));
+}
+
+void BlockingLinesSource::removeTimeout (int type)
+{
+ PRINTF ("removeTimeout (%d)", type);
+
+ // Iterators will not work when the set is modified; hence this nested loop.
+ bool found;
+ do {
+ found = false;
+ for (Iterator<TimeoutInfo> it = timeoutInfos->iterator ();
+ !found && it.hasNext (); ) {
+ TimeoutInfo *timeout = it.getNext();
+ if (timeout->getType () == type) {
+ found = true;
+ timeoutInfos->remove (timeout);
+ }
+ }
+ } while (found);
+}
+
+long BlockingLinesSource::getCurrentTime ()
+{
+ struct timeb t;
+ if (ftime (&t) == -1)
+ syserr ("ftime() failed");
+ return t.time * 1000L + t.millitm;
+}
+
+BlockingLinesSource::TimeoutInfo *BlockingLinesSource::getNextTimeoutInfo ()
+{
+ TimeoutInfo *nextTimeout = NULL;
+
+ for (Iterator<TimeoutInfo> it = timeoutInfos->iterator ();
+ it.hasNext (); ) {
+ TimeoutInfo *timeout = it.getNext();
+ if (nextTimeout == NULL ||
+ timeout->getTime () < nextTimeout->getTime ())
+ nextTimeout = timeout;
+ }
+
+ return nextTimeout;
+}
+
+void BlockingLinesSource::processTimeouts ()
+{
+ long currentTime = getCurrentTime ();
+
+ while (true) {
+ TimeoutInfo *nextTimeout = getNextTimeoutInfo ();
+ if (nextTimeout == NULL)
+ break;
+
+ PRINTF ("processTimeouts: %ld > %ld? %s",
+ nextTimeout->getTime (), currentTime,
+ nextTimeout->getTime () > currentTime ? "yes" : "no");
+ if (nextTimeout->getTime () > currentTime)
+ break;
+
+ PRINT ("processTimeouts: call timeout");
+
+ getSink()->timeout (nextTimeout->getType ());
+ timeoutInfos->remove (nextTimeout);
+ }
+}
+
+} // namespace tools
+
+} // namespace rtfl
diff --git a/common/lines.hh b/common/lines.hh
new file mode 100644
index 0000000..d3bfc75
--- /dev/null
+++ b/common/lines.hh
@@ -0,0 +1,121 @@
+#ifndef __COMMON_LINES_HH__
+#define __COMMON_LINES_HH__
+
+#include "lout/object.hh"
+#include "lout/container.hh"
+
+namespace rtfl {
+
+namespace tools {
+
+class LinesSource;
+
+class LinesSink: public lout::object::Object
+{
+public:
+ virtual void setLinesSource (LinesSource *source) = 0;
+ virtual void processLine (char *line) = 0;
+ virtual void timeout (int type) = 0;
+ virtual void finish () = 0;
+};
+
+
+class LinesSource: public lout::object::Object
+{
+public:
+ virtual void setup (LinesSink *sink) = 0;
+ virtual void addTimeout (double secs, int type) = 0;
+ virtual void removeTimeout (int type) = 0;
+};
+
+
+class LinesSourceSequence: public LinesSource
+{
+private:
+ class VirtualSink: public LinesSink
+ {
+ public:
+ LinesSourceSequence *sequence;
+
+ VirtualSink ();
+ void setLinesSource (LinesSource *source);
+ void processLine (char *line);
+ void timeout (int type);
+ void finish ();
+ };
+
+ VirtualSink virtualSink;
+ LinesSink *sink;
+ lout::container::typed::List<LinesSource> *sources;
+ bool setupCalled;
+ lout::container::typed::Iterator<LinesSource> iterator;
+
+public:
+ LinesSourceSequence (bool ownerOfSources);
+ ~LinesSourceSequence ();
+ void add (LinesSource *source);
+ void setup (LinesSink *sink);
+ void addTimeout (double secs, int type);
+ void removeTimeout (int type);
+};
+
+
+class FileLinesSource: public LinesSource
+{
+private:
+ enum { MAX_LINE_SIZE = 1000 };
+
+ tools::LinesSink *sink;
+ char buf[MAX_LINE_SIZE + 1];
+ int bufPos;
+ bool completeLine;
+
+protected:
+ FileLinesSource ();
+
+ int processInput (int fd);
+ inline void setSink (LinesSink *sink) {
+ this->sink = sink; sink->setLinesSource (this); }
+ inline LinesSink *getSink () { return sink; }
+};
+
+
+class BlockingLinesSource: public FileLinesSource
+{
+private:
+ class TimeoutInfo: public lout::object::Object
+ {
+ private:
+ long time;
+ int type;
+
+ public:
+ TimeoutInfo (long time, int type);
+ bool equals(Object *other);
+ int hashValue();
+
+ inline long getTime () { return time; }
+ inline int getType () { return type; }
+ };
+
+ int fd;
+ lout::container::typed::HashSet<TimeoutInfo> *timeoutInfos;
+
+ long getCurrentTime ();
+ TimeoutInfo *getNextTimeoutInfo ();
+ void processTimeouts ();
+
+public:
+ BlockingLinesSource (int fd);
+ ~BlockingLinesSource ();
+ void setup (LinesSink *sink);
+ void addTimeout (double secs, int type);
+ void removeTimeout (int type);
+};
+
+
+} // namespace tools
+
+} // namespace rtfl
+
+#endif // __COMMON_LINES_HH__
diff --git a/common/parser.cc b/common/parser.cc
new file mode 100644
index 0000000..3311e45
--- /dev/null
+++ b/common/parser.cc
@@ -0,0 +1,250 @@
+/*
+ * RTFL
+ *
+ * Copyright 2013-2015 Sebastian Geerken <sgeerken@dillo.org>
+ *
+ * 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; with the following exception:
+ *
+ * The copyright holders of RTFL give you permission to link this file
+ * statically or dynamically against all versions of the graphviz
+ * library, which are published by AT&T Corp. under one of the following
+ * licenses:
+ *
+ * - Common Public License version 1.0 as published by International
+ * Business Machines Corporation (IBM), or
+ * - Eclipse Public License version 1.0 as published by the Eclipse
+ * Foundation.
+ *
+ * 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/>.
+ */
+
+#include "parser.hh"
+
+#include <string.h>
+#include <ctype.h>
+
+namespace rtfl {
+
+namespace tools {
+
+void Parser::setLinesSource (LinesSource *source)
+{
+}
+
+void Parser::processLine (char *line)
+{
+ char *lineCopy = strdup (line);
+
+ if (strncmp (lineCopy, "[rtfl]", 6) == 0) {
+ // Pre-version: starts with "[rtfl]".
+
+ char **parts = split (lineCopy + 6, 5);
+
+ if (parts[1] && parts[2] && parts[3]) {
+ // Notice that parts[4] (arguments) is allowed to be NULL here.
+ CommonLineInfo info =
+ { parts[0], atoi(parts[1]), atoi(parts[2]), line };
+ processCommand (&info, parts[3], parts[4]);
+ } else
+ fprintf (stderr, "Incomplete line:\n%s\n", line);
+
+ freeSplit (parts);
+ } else if (strncmp (lineCopy, "[rtfl-", 6) == 0) {
+ // Versioned: starts with "[rtfl-<module>-<major>.<minor>]".
+
+ int i = 6;
+ while (isalpha (lineCopy[i]))
+ i++;
+
+ if (lineCopy[i] != '-')
+ fprintf (stderr, "Expected '-' after module:\n%s\n", line);
+ else {
+ char *module = new char[i - 6 + 1];
+ memcpy (module, lineCopy + 6, (i - 6) * sizeof (char));
+ module[i - 6] = 0;
+
+ i++;
+ if (!isdigit (lineCopy[i]))
+ fprintf (stderr, "Missing major version:\n%s\n", line);
+ else {
+ int majorVersion = 0, minorVersion = 0;
+
+ while (isdigit (lineCopy[i])) {
+ majorVersion = 10 * majorVersion + (lineCopy[i] - '0');
+ i++;
+ }
+
+ if (majorVersion == 0)
+ fprintf (stderr, "Major version must be positive:\n%s\n", line);
+ else if (lineCopy[i] != '.')
+ fprintf (stderr, "Expected '.' after major version:\n%s\n",
+ line);
+ else if (!isdigit (lineCopy[i + 1]))
+ fprintf (stderr, "Missing minor version:\n%s\n", line);
+ else {
+ i++;
+ while (isdigit (lineCopy[i])) {
+ minorVersion = 10 * minorVersion + (lineCopy[i] - '0');
+ i++;
+ }
+
+ if (lineCopy[i] != ']')
+ fprintf (stderr, "Expected ']' after minor version:\n%s\n",
+ line);
+ else {
+ char **parts = splitEscaped (lineCopy + i + 1);
+
+ if (parts[1] && parts[2] && parts[3]) {
+ // Notice that parts[4] (first argument) is allowed to be
+ // NULL here.
+ CommonLineInfo info = { parts[0], atoi(parts[1]),
+ atoi(parts[2]), line };
+ processVCommand (&info, module, majorVersion, minorVersion,
+ parts[3], parts + 4);
+ } else
+ fprintf (stderr, "Incomplete line:\n%s\n", line);
+
+ freeSplitEscaped (parts);
+ }
+ }
+ }
+
+ delete[] module;
+ }
+ }
+
+ free (lineCopy);
+}
+
+void Parser::finish ()
+{
+}
+
+void Parser::timeout (int type)
+{
+}
+
+char **Parser::splitEscaped (char *txt)
+{
+ int numParts;
+ char **parts;
+
+ scanSplit (txt, &numParts, NULL);
+ parts = new char*[numParts + 1];
+ scanSplit (txt, NULL, parts);
+ parts[numParts] = NULL;
+
+ for (int i = 0; i < numParts; i++)
+ unquote (parts[i]);
+
+ return parts;
+}
+
+void Parser::scanSplit (char *txt, int *numParts, char **parts)
+{
+ int iChar, iPart;
+ bool quoted;
+
+ if (numParts)
+ *numParts = 1;
+
+ if (parts)
+ parts[0] = txt;
+
+ for (iChar = 0, iPart = 1; txt[iChar]; iChar++) {
+ if (txt[iChar] == '\\' && txt[iChar + 1]) {
+ iChar++;
+ quoted = true;
+ } else
+ quoted = false;
+
+ if (!quoted && txt[iChar] == ':') {
+ if (parts) {
+ txt[iChar] = 0;
+ parts[iPart] = txt + iChar + 1;
+ }
+
+ iPart++;
+
+ if (numParts)
+ (*numParts)++;
+ }
+ }
+}
+
+void Parser::unquote (char *txt)
+{
+ int i, j;
+ for (i = 0, j = 0; txt[i]; i++, j++) {
+ if (txt[i] == '\\' && txt[i + 1])
+ i++;
+ txt[j] = txt[i];
+ }
+ txt[j] = 0;
+}
+
+// Free result of splitEscaped().
+void Parser::freeSplitEscaped (char **parts)
+{
+ delete[] parts;
+}
+
+// Split without escaping.
+char **Parser::split (char *txt, int maxNum)
+{
+ // Only maxNum splits. If less parts are found, less parts are
+ // returned, so the caller should check the result (first part is
+ // always defined). Notice that the original text buffer (txt) is
+ // destroyed, for speed.
+
+ //printf ("===> split ('%s', %d)\n", txt, maxNum);
+
+ char **parts = new char*[maxNum + 1];
+
+ char *start = txt;
+ int i = 0;
+ while (i < maxNum) {
+ char *end = start;
+ while (*end != 0 && *end != ':') end++;
+ int endOfTxt = *end == 0;
+
+ //printf (" start '%s'\n", start);
+ //printf (" end '%s' (%d character(s))\n",
+ // end, (int)(end - start));
+
+ parts[i] = start;
+
+ if (i < maxNum -1)
+ *end = 0;
+
+ //printf ("---> %d: '%s'\n", i, start);
+
+ i++;
+ if (endOfTxt)
+ break;
+
+ start = endOfTxt ? end : end + 1;
+ }
+
+ parts[i] = NULL;
+ return parts;
+}
+
+// Free result of split().
+void Parser::freeSplit (char **parts)
+{
+ delete[] parts;
+}
+
+} // namespace tools
+
+} // namespace rtfl
diff --git a/common/parser.hh b/common/parser.hh
new file mode 100644
index 0000000..30cf02d
--- /dev/null
+++ b/common/parser.hh
@@ -0,0 +1,47 @@
+#ifndef __COMMON_PARSER_HH__
+#define __COMMON_PARSER_HH__
+
+#include "lines.hh"
+
+namespace rtfl {
+
+namespace tools {
+
+struct CommonLineInfo
+{
+ char *fileName;
+ int lineNo;
+ int processId;
+ char *completeLine;
+};
+
+class Parser: public LinesSink
+{
+private:
+ char **splitEscaped (char *txt);
+ void scanSplit (char *txt, int *numParts, char **parts);
+ static void unquote (char *txt);
+ void freeSplitEscaped (char **parts);
+
+protected:
+ char **split (char *txt, int maxNum);
+ void freeSplit (char **parts);
+
+ virtual void processCommand (CommonLineInfo *info, char *cmd, char *args)
+ = 0;
+ virtual void processVCommand (CommonLineInfo *info, const char *module,
+ int majorVersion, int minorVersion,
+ const char *cmd, char **args) = 0;
+
+public:
+ void setLinesSource (LinesSource *source);
+ void processLine (char *line);
+ void finish ();
+ void timeout (int type);
+};
+
+} // namespace common
+
+} // namespace rtfl
+
+#endif // __COMMON_PARSER_HH__
diff --git a/common/rtfl_findrepeat.cc b/common/rtfl_findrepeat.cc
new file mode 100644
index 0000000..d464db8
--- /dev/null
+++ b/common/rtfl_findrepeat.cc
@@ -0,0 +1,534 @@
+/*
+ * RTFL
+ *
+ * Copyright 2014, 2015 Sebastian Geerken <sgeerken@dillo.org>
+ *
+ * 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/>.
+ */
+
+/*
+ * This program searches for identical sequences in a stream of RTFL
+ * messages (actually, any stream) and marks the beginnings and ends
+ * with an RTFL mark (obj-mark). You should first filter out other
+ * lines, so run
+ *
+ * $ ... | grep '^\[rtfl[^\]]*\]' | rtfl-findrepeat
+ *
+ * or use the script rtfl-objfilter.
+ *
+ * For options, see printHelp().
+ *
+ * Warning: This program is highly experimental, and especially rather
+ * inefficient. Some ideas:
+ *
+ * - When finding a suitable lenght ("-l find"), a smaller number of
+ * lines is in many cases sufficient, so use "head".
+ *
+ * - Unless the length is searched for ("-l find"), hashing multiple
+ * lines (as many as are searched as minimum), as done in the
+ * searching algorithm by Rabin and Karp, may increase the speed.
+ */
+
+#include <unistd.h>
+#include <string.h>
+#include <stdio.h>
+#include "tools.hh"
+#include "../lout/object.hh"
+#include "../lout/container.hh"
+
+using namespace lout::misc;
+using namespace lout::object;
+using namespace lout::container::typed;
+
+enum { MAX_LINE_SIZE = 1000 };
+
+class Region: public Comparable
+{
+ int first, num;
+
+public:
+ inline Region (int first, int num) { this->first = first; this->num = num; }
+
+ bool equals (Object *other);
+ int hashValue ();
+ void intoStringBuffer (StringBuffer *sb);
+ int compareTo(Comparable *other);
+
+ inline int getFirst () { return first; }
+ inline int getNum () { return num; }
+ inline Region *cloneRegion () { return new Region (first, num); }
+
+ inline bool subSetOf (Region *other)
+ { return first >= other->first && first + num <= other->first + other->num; }
+};
+
+class Mark: public Object
+{
+public:
+ enum Type { START, END };
+
+private:
+ Type type;
+ int majorNo, minorNo, length;
+
+public:
+ inline Mark (Type type, int majorNo, int minorNo, int length)
+ { this->type = type; this->majorNo = majorNo; this->minorNo = minorNo;
+ this->length = length; }
+
+ void intoStringBuffer (StringBuffer *sb);
+
+ inline Type getType () { return type; }
+ inline int getMajorNo () { return majorNo; }
+ inline int getMinorNo () { return minorNo; }
+ inline int getLength () { return length; }
+};
+
+bool Region::equals (Object *other)
+{
+ Region *otherRegion = (Region*)other;
+ return first == otherRegion->first && num == otherRegion->num;
+}
+
+int Region::hashValue ()
+{
+ return first ^ num;
+}
+
+void Region::intoStringBuffer (StringBuffer *sb)
+{
+ char buf[32];
+
+ sb->append ("(");
+ snprintf (buf, 32, "%d", first);
+ sb->append (buf);
+ sb->append ("...");
+ snprintf (buf, 32, "%d", first + num - 1);
+ sb->append (buf);
+ sb->append (")");
+}
+
+void Mark::intoStringBuffer (StringBuffer *sb)
+{
+ char buf[32];
+
+
+ sb->append ("(");
+ sb->append (type == START ? "START" : "END");
+ sb->append (" / ");
+ snprintf (buf, 32, "%d", majorNo);
+ sb->append (buf);
+ sb->append (" / ");
+ snprintf (buf, 32, "%d", minorNo);
+ sb->append (buf);
+ sb->append (")");
+}
+
+int Region::compareTo(Comparable *other)
+{
+ Region *otherRegion = (Region*)other;
+ return first - otherRegion->first;
+}
+
+// ----------------------------------------------------------------------
+
+static bool debug = false;
+
+static void printHelp (const char *argv0)
+{
+ fprintf
+ (stderr, "Usage: %s <options>\n"
+ "\n"
+ "Options:\n"
+ " -l <n> Search for sequence of at least <n> lines.\n"
+ " -c <n> Search for sequence repeated at least <n> times.\n"
+ "\n"
+ "If an arguments is 'f' or 'find', the maximal value for this is\n"
+ "determined (possibly with the other argument set to a concrete\n"
+ "number).\n"
+ "\n"
+ "See RTFL documentation for more details.\n",
+ argv0);
+}
+
+// ----------------------------------------------------------------------
+
+static void readFile (FILE *file, Vector<String> *lines,
+ HashTable<String, Vector<Integer> > *lineNosByLines)
+{
+ char buf[MAX_LINE_SIZE + 1];
+
+ for (int lineNo = 0; fgets (buf, MAX_LINE_SIZE + 1, file); lineNo++) {
+ size_t l = strlen (buf);
+ if (buf[l - 1] == '\n') buf[l - 1] = 0;
+
+ String *line = new String (buf);
+
+ Vector<Integer> *lineNos = lineNosByLines->get (line);
+ if (lineNos == NULL) {
+ lineNos = new Vector<Integer> (1, true);
+ // Note: key is dublicated.
+ lineNosByLines->put (new String (buf), lineNos);
+ }
+ lineNos->put (new Integer (lineNo));
+
+ lines->put (line);
+ }
+}
+
+static int findRegions (Vector<String> *lines,
+ HashTable<String, Vector<Integer> > *lineNosByLines,
+ List <HashSet<Region> > *allSetsOfRegions,
+ int minLength, int minCount)
+{
+ int effMinLength = minLength == -1 ? 2 :minLength;
+ int effMinCount = minCount == -1 ? 2 : minCount;
+ int maxLength = 0, maxCount = 0;
+
+ HashTable<Region, HashSet<Region> > *setsOfRegionsByRegion =
+ new HashTable<Region, HashSet<Region> > (false, false);
+
+ List <HashSet<Region> > *tmpAllSetsOfRegions =
+ new List<HashSet<Region> > (false);
+
+ for (int lineNo1 = 0; lineNo1 < lines->size (); lineNo1++) {
+ String *line = lines->get (lineNo1);
+ Vector<Integer> *lineNos = lineNosByLines->get (line);
+
+ // Examine only lines after this.
+ Integer lineNo1Key (lineNo1);
+
+ for (int linesNoIndex = lineNos->bsearch (&lineNo1Key, true) + 1;
+ linesNoIndex < lineNos->size (); linesNoIndex++) {
+ int lineNo2 = lineNos->get(linesNoIndex)->getValue ();
+ int numMatching = 1;
+ while (lineNo2 + numMatching < lines->size () &&
+ lines->get(lineNo1 + numMatching)->equals
+ (lines->get(lineNo2 + numMatching))) {
+ numMatching++;
+
+ if (numMatching >= effMinLength) {
+ //printf ("equal: (%d...%d) and (%d...%d)\n",
+ // lineNo1, lineNo1 + numMatching - 1,
+ // lineNo2, lineNo2 + numMatching - 1);
+
+ Region r1 (lineNo1, numMatching), r2 (lineNo2, numMatching);
+ HashSet<Region> *setOfRegions;
+
+ if ((setOfRegions = setsOfRegionsByRegion->get (&r1))) {
+ if (!setsOfRegionsByRegion->contains (&r2)) {
+ assert (!setOfRegions->contains (&r2));
+ Region *rr2 = r2.cloneRegion ();
+ setOfRegions->put (rr2);
+ setsOfRegionsByRegion->put (rr2, setOfRegions);
+ }
+ } else if ((setOfRegions = setsOfRegionsByRegion->get (&r2))) {
+ if (!setsOfRegionsByRegion->contains (&r1)) {
+ assert (!setOfRegions->contains (&r1));
+ Region *rr1 = r1.cloneRegion ();
+ setOfRegions->put (rr1);
+ setsOfRegionsByRegion->put (rr1, setOfRegions);
+ }
+ } else {
+ Region *rr1 = r1.cloneRegion (), *rr2 = r2.cloneRegion ();
+ setOfRegions = new HashSet<Region> (false);
+ setOfRegions->put (rr1);
+ setOfRegions->put (rr2);
+ setsOfRegionsByRegion->put (rr1, setOfRegions);
+ setsOfRegionsByRegion->put (rr2, setOfRegions);
+ tmpAllSetsOfRegions->append (setOfRegions);
+ }
+
+ if (debug) {
+ StringBuffer sb;
+ setsOfRegionsByRegion->intoStringBuffer (&sb);
+ printf ("findRegions: setsOfRegionsByRegion = %s\n",
+ sb.getChars ());
+ }
+ }
+ }
+ }
+ }
+
+ delete setsOfRegionsByRegion;
+
+ for (Iterator<HashSet<Region> > it1 = tmpAllSetsOfRegions->iterator ();
+ it1.hasNext (); ) {
+ HashSet<Region> *set = it1.getNext ();
+ if (set->size () >= effMinCount) {
+ allSetsOfRegions->append (set);
+ maxCount = max (maxCount, set->size ());
+
+ if (minLength == -1) {
+ for (Iterator<Region> it2 = set->iterator (); it2.hasNext (); ) {
+ Region *r = it2.getNext ();
+ maxLength = max (maxLength, r->getNum ());
+ }
+ }
+ } else
+ delete set;
+ }
+
+ delete tmpAllSetsOfRegions;
+
+ if (minLength == -1)
+ return maxLength;
+ else if (minCount == -1)
+ return maxCount;
+ else
+ return -1;
+}
+
+static void sortListsOfRegions (List <HashSet<Region> > *allSetsOfRegions,
+ List <Vector<Region> > *allListsOfRegions)
+{
+ for (Iterator<HashSet<Region> > it1 = allSetsOfRegions->iterator ();
+ it1.hasNext (); ) {
+ HashSet<Region> *set = it1.getNext ();
+ Vector<Region> *list = new Vector<Region> (1, true);
+
+ for (Iterator<Region> it2 = set->iterator (); it2.hasNext (); ) {
+ Region *r = it2.getNext ();
+ list->put (r);
+ }
+
+ if (debug) {
+ StringBuffer sb;
+ list->intoStringBuffer (&sb);
+ printf ("sortListsOfRegions: list = %s\n", sb.getChars ());
+ }
+
+ list->sort ();
+ allListsOfRegions->append (list);
+ }
+}
+
+static void cleanupRegions (List <Vector <Region> > *allListsOfRegions)
+{
+ HashTable<List<Integer>, Vector<Vector<Region> > > *allListsOfLists =
+ new HashTable<List<Integer>, Vector<Vector<Region> > > (true, true);
+
+ for (Iterator<Vector <Region> > it = allListsOfRegions->iterator ();
+ it.hasNext (); ) {
+ Vector<Region> *list = it.getNext ();
+
+ List<Integer> *key = new List<Integer> (true);
+ for (int i = 1; i < list->size (); i++)
+ key->append (new Integer (list->get(i)->getFirst () -
+ list->get(i - 1)->getFirst ()));
+
+ Vector<Vector<Region> > *listOfLists = allListsOfLists->get (key);
+ if (listOfLists)
+ delete key;
+ else {
+ listOfLists = new Vector<Vector<Region> > (1, false);
+ allListsOfLists->put (key, listOfLists);
+ }
+
+ listOfLists->put (list);
+ }
+
+ allListsOfRegions->clear ();
+
+ if (debug) {
+ StringBuffer sb;
+ allListsOfLists->intoStringBuffer (&sb);
+ printf ("cleanupRegions: allListsOfLists = %s\n", sb.getChars ());
+ }
+
+ for (Iterator<List<Integer> > it = allListsOfLists->iterator ();
+ it.hasNext (); ) {
+ List<Integer> *key = it.getNext ();
+ Vector<Vector<Region> > *listOfLists = allListsOfLists->get (key);
+
+ if (debug) {
+ StringBuffer sb;
+ listOfLists->intoStringBuffer (&sb);
+ printf ("cleanupRegions: listOfLists = %s\n", sb.getChars ());
+ }
+
+ for (int i = 0; i < listOfLists->size (); i++) {
+ Vector<Region> *list1 = listOfLists->get (i);
+ Region *r1 = list1->get (0);
+ bool redundant = false;
+ for (int j = 0; j < listOfLists->size () && !redundant; j++) {
+ if (i != j) {
+ Vector<Region> *list2 = listOfLists->get (j);
+ if (list2 != NULL) {
+ Region *r2 = list2->get (0);
+ if (r1->subSetOf (r2))
+ redundant = true;
+ }
+ }
+ }
+
+ if (redundant) {
+ listOfLists->put (NULL, i);
+ delete list1;
+ } else
+ allListsOfRegions->append (list1);
+ }
+ }
+
+ delete allListsOfLists;
+}
+
+// ----------------------------------------------------------------------
+
+int main (int argc, char *argv[])
+{
+ int minLength = 2, minCount = 2;
+ int opt;
+
+ while ((opt = getopt(argc, argv, "c:dl:")) != -1) {
+ switch (opt) {
+ case 'c':
+ if (strcmp (optarg, "f") == 0 || strcmp (optarg, "find") == 0)
+ minCount = -1;
+ else
+ minCount = atoi (optarg);
+ break;
+
+ case 'd':
+ debug = true;
+ break;
+
+ case 'l':
+ if (strcmp (optarg, "f") == 0 || strcmp (optarg, "find") == 0)
+ minLength = -1;
+ else
+ minLength = atoi (optarg);
+ break;
+
+ default:
+ printHelp (argv[0]);
+ return 1;
+ }
+ }
+
+ Vector<String> *lines = new Vector<String> (8, true);
+ HashTable<String, Vector<Integer> > *lineNosByLines =
+ new HashTable<String, Vector<Integer> > (true, true);
+
+ readFile (stdin, lines, lineNosByLines);
+
+ List <HashSet<Region> > *allSetsOfRegions =
+ new List<HashSet<Region> > (true);
+
+ int numFound = findRegions (lines, lineNosByLines, allSetsOfRegions,
+ minLength, minCount);
+
+ if (debug) {
+ StringBuffer sb;
+ allSetsOfRegions->intoStringBuffer (&sb);
+ printf ("main: allSetsOfRegions = %s\n", sb.getChars ());
+ }
+
+ delete lineNosByLines;
+
+ if (numFound != -1) {
+ delete allSetsOfRegions;
+ printf ("%d\n", numFound);
+ } else {
+ List <Vector<Region> > *allListsOfRegions =
+ new List <Vector<Region> > (false); // TODO Memory leak!
+
+ sortListsOfRegions (allSetsOfRegions, allListsOfRegions);
+
+ delete allSetsOfRegions;
+
+ if (debug) {
+ StringBuffer sb;
+ allListsOfRegions->intoStringBuffer (&sb);
+ printf ("(a) main: allListsOfRegions = %s\n", sb.getChars ());
+ }
+
+ cleanupRegions (allListsOfRegions);
+
+ if (debug) {
+ StringBuffer sb;
+ allListsOfRegions->intoStringBuffer (&sb);
+ printf ("(b) main: allListsOfRegions = %s\n", sb.getChars ());
+ }
+
+ HashTable<Integer, List<Mark> > *marksByLineNo =
+ new HashTable<Integer, List<Mark> > (true, true);
+
+ int majorNo = 0;
+ for (Iterator<Vector<Region> > it1 = allListsOfRegions->iterator ();
+ it1.hasNext (); ) {
+ Vector<Region> *list = it1.getNext ();
+ int minorNo = 0;
+
+ for (Iterator<Region> it2 = list->iterator (); it2.hasNext (); ) {
+ Region *r = it2.getNext ();
+
+ for (int typeNo = 0; typeNo < 2; typeNo++) {
+ Mark::Type type = typeNo == 0 ? Mark::START : Mark::END;
+ int lineNo =
+ r->getFirst () + (type == Mark::START ? 0 : r->getNum ());
+ Integer lineNoKey (lineNo);
+
+ List<Mark> *list = marksByLineNo->get (&lineNoKey);
+ if (list == NULL) {
+ list = new List<Mark> (true);
+ marksByLineNo->put (new Integer (lineNo), list);
+ }
+
+ list->append (new Mark (type, majorNo, minorNo, r->getNum ()));
+ }
+
+
+ minorNo++;
+ }
+
+ majorNo++;
+ }
+
+ delete allListsOfRegions;
+
+ if (debug) {
+ StringBuffer sb;
+ marksByLineNo->intoStringBuffer (&sb);
+ printf ("main: marksByLineNo = %s\n", sb.getChars ());
+ }
+
+ for (int lineNo = 0; lineNo < lines->size (); lineNo++) {
+ Integer lineNoKey (lineNo);
+ List<Mark> *list = marksByLineNo->get (&lineNoKey);
+ if (list) {
+ for (Iterator<Mark> it = list->iterator (); it.hasNext (); ) {
+ Mark *m = it.getNext ();
+ char buf[200];
+ rtfl::tools::numToRoman (m->getMajorNo () + 1, buf,
+ sizeof (buf));
+ // Certainly no ':' or '\' in the message, so no quoting
+ // necessary.
+ printf ("[rtfl-obj-1.0]n:0:0:mark:findrepeat:findrepeat:0:"
+ "Sequence %s (length %d), %d%s occurence -- %s\n",
+ buf, m->getLength (), m->getMinorNo () + 1,
+ rtfl::tools::numSuffix (m->getMinorNo () + 1),
+ m->getType () == Mark::START ? "start" : "end");
+ }
+ }
+
+ String *line = lines->get (lineNo);
+ puts (line->chars ());
+ }
+
+ delete marksByLineNo;
+ }
+
+ delete lines;
+}
diff --git a/common/rtfl_tee.c b/common/rtfl_tee.c
new file mode 100644
index 0000000..4911b73
--- /dev/null
+++ b/common/rtfl_tee.c
@@ -0,0 +1,249 @@
+/*
+ * RTFL
+ *
+ * Copyright 2014 Sebastian Geerken <sgeerken@dillo.org>
+ *
+ * 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/>.
+ */
+
+/*
+ * Like tee(1), this program duplicates a stream; however, it does not
+ * write the copy to a file, but instead sends it via pipe to another
+ * program. Example:
+ *
+ * $ foo | rtfl-tee bar | qix
+ *
+ * Here, the standard output of "foo" is passed to the standard input
+ * of both "bar" and "qix".
+ *
+ * More informations in doc/rtfl.html.
+ *
+ * TODO: Something like "echo -n foo | rtfl-tee -b cat" does not work;
+ * since the line of the first "foo" is never finished, the copy of
+ * "foo" is never printed.
+ */
+
+#include <unistd.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/select.h>
+
+#define min(a, b) ((a) < (b) ? (a) : (b))
+#define max(a, b) ((a) > (b) ? (a) : (b))
+
+static void usrerr (const char *fmt, ...)
+{
+ va_list args;
+ va_start (args, fmt);
+ vfprintf (stderr, fmt, args);
+ fprintf (stderr, "\n");
+ exit (1);
+}
+
+static void syserr (const char *fmt, ...)
+{
+ va_list args;
+ va_start (args, fmt);
+ vfprintf (stderr, fmt, args);
+ fprintf (stderr, ": %s\n", strerror (errno));
+ exit (1);
+}
+
+static ssize_t ewrite(int fd, const void *buf, size_t count)
+{
+ ssize_t w;
+ if ((w = write (fd, buf, count)) == -1)
+ syserr ("write(%d, ...) failed", fd);
+ return w;
+}
+
+static void writestdout (int orig, char *buf, size_t count)
+{
+ // Basic idea: "orig" denotes to 0 (stdin of rtfl-tee) or 1 (stdout
+ // of the called program). "curorig" refers to the origin which is
+ // currently printed, so than the data from the other origin must
+ // be buffered. "startline" is set to 1 at the beginning, or iff
+ // the last printed character was '\n'. (In this case, switching is
+ // simply possible.)
+
+ static int curorig = 0, startline = 1;
+ static char obuf[2048];
+ static size_t ocount = 0;
+
+ //printf ("\nwritestdout: %d, '%c...' (%d)\n",
+ // orig, count > 0 ? buf[0] : '.', (int)count);
+ //printf ("===> curorig = %d, ocount = %d, startline = %d\n",
+ // curorig, (int)ocount, startline);
+
+ if (count > 0) {
+ if (orig != curorig) {
+ if (startline) {
+ // Simple switching case.
+ ewrite (1, obuf, ocount);
+ ocount = 0;
+ curorig = orig;
+ ewrite (1, buf, count);
+ startline = buf[count - 1] == '\n';
+ } else {
+ // Buffer.
+ size_t odiff = min (count, ocount - sizeof (obuf));
+ memcpy (obuf + ocount, buf, odiff);
+ ocount += odiff;
+ }
+ } else {
+ if (ocount == 0) {
+ // Nothing buffered: simply print all data.
+ ewrite (1, buf, count);
+ startline = buf[count - 1] == '\n';
+ } else {
+ // Only print everything until the last newline character.
+ // (Note: printing everything until the *first* newline
+ // character whould make a larger buffer necessary, but,
+ // on the other hand, preserve better the original
+ // (temporal) order of the lines.)
+ ssize_t i, nl;
+ for (nl = -1, i = count - 1; nl == -1 && i >= 0; i--)
+ if (buf[i] == '\n') nl = i;
+
+ if (nl == -1) {
+ // No newline: no switch.
+ ewrite (1, buf, count);
+ startline = 0;
+ } else {
+ // Newline: switch.
+ ewrite (1, buf, nl + 1);
+ ewrite (1, obuf, ocount);
+ startline = obuf[ocount - 1] == '\n';
+ ocount = min (sizeof (obuf), count - (nl + 1));
+ memcpy (obuf, buf + nl + 1, ocount);
+ curorig = 1 - curorig;
+ }
+ }
+ }
+ }
+}
+
+int main (int argc, char *argv[])
+{
+ int parent2child[2], child2parent[2], i, offsetcmd, bypass = 0, erroropt = 0;
+ char *argv2[argc - 1 + 1];
+ int done1, done2;
+
+ for (offsetcmd = 1; offsetcmd < argc && argv[offsetcmd][0] == '-';
+ offsetcmd++) {
+ if (argv[offsetcmd][1] == 'b')
+ bypass = 1;
+ else if (argv[offsetcmd][1] == '-') {
+ offsetcmd++;
+ break;
+ } else
+ erroropt = 1;
+ }
+
+ if (erroropt || offsetcmd >= argc)
+ usrerr ("Usage: %s [-b] [--] <program> [<program options>]", argv[0]);
+
+ if (pipe (parent2child) == -1) syserr ("pipe failed");
+ if (bypass && pipe (child2parent) == -1) syserr ("pipe failed");
+
+ switch (fork ()) {
+ case -1:
+ syserr ("fork failed");
+ break;
+
+ case 0:
+ if (close (parent2child[1]) == -1)
+ syserr ("close(%d) failed", parent2child[0]);
+ if (close (0) == -1) syserr ("close(0) failed");
+ if (dup2 (parent2child[0], 0) == -1)
+ syserr ("dup2(%d, 0) failed", parent2child[0]);
+ if (close (parent2child[0]) == -1)
+ syserr ("close(%d) failed", parent2child[0]);
+
+ if (bypass) {
+ if (close (child2parent[0]) == -1)
+ syserr ("close(%d) failed", child2parent[1]);
+ if (close (1) == -1) syserr ("close(1) failed");
+ if (dup2 (child2parent[1], 1) == -1)
+ syserr ("dup2(%d, 1) failed", child2parent[1]);
+ if (close (child2parent[1]) == -1)
+ syserr ("close(%d) failed", child2parent[1]);
+ }
+
+ for (i = 0; i < argc - offsetcmd; i++) argv2[i] = argv[i + offsetcmd];
+ argv2[argc - offsetcmd] = NULL;
+ if (execvp (argv2[0], argv2) == -1)
+ syserr ("execvp(\"%s\", ...) failed", argv2[0]);
+ break;
+
+ default:
+ if (close (parent2child[0]) == -1)
+ syserr ("close(%d) failed", parent2child[0]);
+ if (bypass && close (child2parent[1]) == -1)
+ syserr ("close(%d) failed", child2parent[1]);
+
+ done1 = 0;
+ done2 = !bypass;
+ while (!done1 || !done2) {
+ //printf ("==> done1 = %d, done2 = %d\n", done1, done2);
+
+ fd_set set;
+ FD_ZERO (&set);
+
+ if (!done1) FD_SET (0, &set);
+ if (!done2) FD_SET (child2parent[0], &set);
+
+ int s = select ((!done2 ? child2parent[0] : 0) + 1,
+ &set, NULL, NULL, NULL);
+
+ //printf ("==> s = %d\n", s);
+
+ if (s == -1) syserr ("select failed");
+ else if (s > 0) {
+ char buf[2048];
+ ssize_t n;
+
+ if (!done1 && FD_ISSET(0, &set)) {
+ if ((n = read (0, buf, sizeof (buf))) == -1)
+ syserr ("read failed");
+ else if (n == 0) {
+ if (close (parent2child[1]) == -1)
+ syserr ("close(%d) failed", parent2child[1]);
+ done1 = 1;
+ } else if (n > 0) {
+ ewrite (parent2child[1], buf, n);
+ writestdout (0, buf, n);
+ }
+ }
+
+ if (!done2 && FD_ISSET (child2parent[0], &set)) {
+ if ((n = read (child2parent[0], buf, sizeof (buf))) == -1)
+ syserr ("read failed");
+ else if (n == 0) {
+ if (close (child2parent[0]) == -1)
+ syserr ("close(%d) failed", child2parent[0]);
+ done2 = 1;
+ } else if (n > 0)
+ writestdout (1, buf, n);
+ }
+ }
+ }
+ break;
+ }
+
+ return 0;
+}
diff --git a/common/tools.cc b/common/tools.cc
new file mode 100644
index 0000000..7dfb412
--- /dev/null
+++ b/common/tools.cc
@@ -0,0 +1,264 @@
+/*
+ * RTFL
+ *
+ * Copyright 2013-2015 Sebastian Geerken <sgeerken@dillo.org>
+ *
+ * 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; with the following exception:
+ *
+ * The copyright holders of RTFL give you permission to link this file
+ * statically or dynamically against all versions of the graphviz
+ * library, which are published by AT&T Corp. under one of the following
+ * licenses:
+ *
+ * - Common Public License version 1.0 as published by International
+ * Business Machines Corporation (IBM), or
+ * - Eclipse Public License version 1.0 as published by the Eclipse
+ * Foundation.
+ *
+ * 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/>.
+ */
+
+#include "tools.hh"
+
+#include <stdio.h>
+#include <errno.h>
+
+using namespace lout::object;
+using namespace lout::container::untyped;
+
+namespace rtfl {
+
+namespace tools {
+
+const char *numSuffix (int n)
+{
+ if (n % 10 == 1 && n != 11)
+ return "st";
+ else if (n % 10 == 2 && n != 12)
+ return "nd";
+ else if (n % 10 == 3 && n != 13)
+ return "rd";
+ else
+ return "th";
+}
+
+static const char
+ *const roman_I0[] = { "","I","II","III","IV","V","VI","VII","VIII","IX" },
+ *const roman_I1[] = { "","X","XX","XXX","XL","L","LX","LXX","LXXX","XC" },
+ *const roman_I2[] = { "","C","CC","CCC","CD","D","DC","DCC","DCCC","CM" },
+ *const roman_I3[] = { "","M","MM","MMM","MMMM" };
+
+void numToRoman (int num, char *buf, int buflen)
+{
+ int i3, i2, i1, i0;
+
+ if (buflen <= 0)
+ return;
+
+ i0 = num;
+ i1 = i0/10; i2 = i1/10; i3 = i2/10;
+ i0 %= 10; i1 %= 10; i2 %= 10;
+ if (num < 0 || i3 > 4) /* more than 4999 elements ? */
+ snprintf(buf, buflen, "****");
+ else
+ snprintf(buf, buflen, "%s%s%s%s", roman_I3[i3], roman_I2[i2],
+ roman_I1[i1], roman_I0[i0]);
+}
+
+void syserr (const char *fmt, ...)
+{
+ va_list args;
+ va_start (args, fmt);
+ vfprintf (stderr, fmt, args);
+ fprintf (stderr, ": %s\n", strerror (errno));
+ exit (1);
+}
+
+// ----------------------------------------------------------------------
+
+EquivalenceRelation::RefTarget::RefTarget (Object *object, bool ownerOfObject)
+{
+ this->object = object;
+ this->ownerOfObject = ownerOfObject;
+ refCount = 1;
+ allKeys = new HashSet (false);
+}
+
+EquivalenceRelation::RefTarget::~RefTarget ()
+{
+ if (ownerOfObject)
+ delete object;
+ delete allKeys;
+}
+
+// ----------------------------------------------------------------------
+
+EquivalenceRelation::RefSource::RefSource (Object *key, RefTarget *target)
+{
+ this->target = target;
+ this->key = key;
+ refTarget ();
+}
+
+EquivalenceRelation::RefSource::~RefSource ()
+{
+ unrefTarget ();
+}
+
+void EquivalenceRelation::RefSource::refTarget ()
+{
+ if (target) {
+ target->ref ();
+ target->putKey (key);
+ }
+}
+
+void EquivalenceRelation::RefSource::unrefTarget ()
+{
+ if (target) {
+ target->removeKey (key);
+ target->unref ();
+ target = NULL;
+ }
+}
+
+void EquivalenceRelation::RefSource::setTarget (RefTarget *target)
+{
+ if (target != this->target) {
+ unrefTarget ();
+ this->target = target;
+ refTarget ();
+ }
+}
+
+// ----------------------------------------------------------------------
+
+EquivalenceRelation::EquivalenceRelation (bool ownerOfKeys, bool ownerOfValues)
+{
+ this->ownerOfKeys = ownerOfKeys;
+ this->ownerOfValues = ownerOfValues;
+ sources = new HashTable (ownerOfKeys, true);
+}
+
+EquivalenceRelation::~EquivalenceRelation ()
+{
+ delete sources;
+}
+
+void EquivalenceRelation::put (Object *key, Object *value)
+{
+ assert (!contains(key));
+
+ RefTarget *target = new RefTarget (value, ownerOfValues);
+ RefSource *source = new RefSource (key, target);
+ target->unref ();
+ sources->put (key, source);
+}
+
+Object *EquivalenceRelation::get (Object *key) const
+{
+ RefSource *source = (RefSource*) sources->get(key);
+ if (source) {
+ Object *object = source->getTarget()->getObject ();
+ return object;
+ } else
+ return NULL;
+}
+
+bool EquivalenceRelation::contains (Object *key) const
+{
+ return sources->contains (key);
+}
+
+Iterator EquivalenceRelation::iterator ()
+{
+ return sources->iterator ();
+}
+
+Iterator EquivalenceRelation::relatedIterator (Object *key)
+{
+ assert (contains (key));
+
+ RefSource *source = (RefSource*) sources->get (key);
+ RefTarget *target = source->getTarget ();
+ return target->getAllKeys()->iterator ();
+}
+
+void EquivalenceRelation::relate (Object *key1, Object *key2)
+{
+ assert (contains(key1) && contains(key2));
+
+ RefSource *source1 = (RefSource*) sources->get (key1);
+ RefSource *source2 = (RefSource*) sources->get (key2);
+ if (source1->getTarget () != source2->getTarget ()) {
+ // The first value is kept, the second destroyed. The caller has
+ // to care about the order.
+
+ // Consider all keys already related to `key2`; this is possible by
+ // iterating over `RefTarget::allKeys`. To avoid accessing freed memory,
+ // copy all keys to a new temporary set.
+
+ HashSet target2Keys (false);
+ for (Iterator it = source2->getTarget()->getAllKeys()->iterator ();
+ it.hasNext (); )
+ target2Keys.put (it.getNext ());
+
+ for (Iterator it = target2Keys.iterator (); it.hasNext (); ) {
+ RefSource *otherSource = (RefSource*) sources->get (it.getNext ());
+ otherSource->setTarget (source1->getTarget ());
+ }
+ }
+}
+
+void EquivalenceRelation::putRelated (Object *oldKey, Object *newKey)
+{
+ assert (contains(oldKey) && !contains(newKey));
+
+ RefSource *oldSource = (RefSource*) sources->get (oldKey);
+ RefSource *newSource = new RefSource (newKey, oldSource->getTarget ());
+ sources->put (newKey, newSource);
+}
+
+void EquivalenceRelation::removeSimple (lout::object::Object *key)
+{
+ // The order is important: a simple "sources->remove (key)" will
+ // cause an access to freed memory.
+
+ RefSource *source = (RefSource*) sources->get (key);
+ source->setTarget (NULL); // Will unref() the target.
+ sources->remove (key);
+}
+
+void EquivalenceRelation::remove (Object *key)
+{
+ assert (contains (key));
+
+ RefSource *source = (RefSource*) sources->get (key);
+ RefTarget *target = source->getTarget ();
+ target->ref ();
+
+ for (Iterator it = target->getAllKeys()->iterator (); it.hasNext (); ) {
+ Object *otherKey = it.getNext ();
+
+ // The order is important: see removeSimple().
+ RefSource *otherSource = (RefSource*) sources->get (otherKey);
+ otherSource->setTarget (NULL); // Will unref() the target.
+ sources->remove (otherKey);
+ }
+
+ target->unref ();
+}
+
+
+} // namespace tools
+
+} // namespace dw
diff --git a/common/tools.hh b/common/tools.hh
new file mode 100644
index 0000000..af8e5e9
--- /dev/null
+++ b/common/tools.hh
@@ -0,0 +1,80 @@
+#ifndef __COMMON_TOOLS_HH__
+#define __COMMON_TOOLS_HH__
+
+#include "lout/object.hh"
+#include "lout/container.hh"
+
+namespace rtfl {
+
+namespace tools {
+
+const char *numSuffix (int n);
+void numToRoman (int num, char *buf, int buflen);
+void syserr (const char *fmt, ...);
+
+class EquivalenceRelation: public lout::object::Object {
+private:
+ class RefTarget: public lout::object::Object {
+ private:
+ bool ownerOfObject;
+ int refCount;
+ lout::object::Object *object;
+ lout::container::untyped::HashSet *allKeys;
+
+ public:
+ RefTarget (lout::object::Object *object, bool ownerOfObject);
+ ~RefTarget ();
+
+ inline lout::object::Object *getObject () { return object; }
+ inline void ref () { refCount++; }
+ inline void unref () { if (--refCount == 0) delete this; }
+
+ inline lout::container::untyped::HashSet *getAllKeys ()
+ { return allKeys; }
+ inline void putKey (Object *key) { allKeys->put (key); }
+ inline void removeKey (Object *key) { allKeys->remove (key); }
+ };
+
+
+ class RefSource: public lout::object::Object {
+ RefTarget *target;
+ lout::object::Object *key;
+
+ void refTarget ();
+ void unrefTarget ();
+
+ public:
+ RefSource (lout::object::Object *key, RefTarget *target);
+ ~RefSource ();
+
+ inline RefTarget *getTarget () { return target; }
+ void setTarget (RefTarget *target);
+ };
+
+ bool ownerOfKeys, ownerOfValues;
+ lout::container::untyped::HashTable *sources;
+
+ lout::container::untyped::HashSet *initSet (lout::object::Object *o);
+
+ public:
+ EquivalenceRelation (bool ownerOfKeys, bool ownerOfValues);
+ ~EquivalenceRelation ();
+
+ void put (lout::object::Object *key, lout::object::Object *value);
+ lout::object::Object *get (lout::object::Object *key) const;
+ bool contains (lout::object::Object *key) const;
+ lout::container::untyped::Iterator iterator ();
+ lout::container::untyped::Iterator relatedIterator (Object *key);
+
+ void relate (lout::object::Object *key1, lout::object::Object *key2);
+ void putRelated (lout::object::Object *oldKey, lout::object::Object *newKey);
+
+ void removeSimple (lout::object::Object *key);
+ void remove (lout::object::Object *key);
+};
+
+} // namespace tools
+
+} // namespace rtfl
+
+#endif // __COMMON_TOOLS_HH__
diff --git a/configure.ac b/configure.ac
new file mode 100644
index 0000000..86b30b9
--- /dev/null
+++ b/configure.ac
@@ -0,0 +1,299 @@
+dnl Process this file with aclocal, autoconf and automake.
+
+AC_INIT([rtfl], [0.1.1])
+
+dnl Detect the canonical target build environment
+AC_CANONICAL_TARGET
+
+AM_INIT_AUTOMAKE
+AC_CONFIG_SRCDIR([objects/rtfl_objview.cc])
+AC_CONFIG_HEADERS([config.h])
+AC_CONFIG_MACRO_DIR([m4])
+
+dnl Options
+
+JAVA_HOME=""
+WARN_GRAPH=no
+
+AC_ARG_ENABLE(efence, [ --enable-efence Try to compile and run with Electric Fence],
+ , enable_efence=no)
+AC_ARG_ENABLE(gprof, [ --enable-gprof Try to compile and run with profiling enabled],
+ , enable_gprof=no)
+AC_ARG_ENABLE(insure, [ --enable-insure Try to compile and run with Insure++],
+ , enable_insure=no)
+AC_ARG_ENABLE(rtfl, [ --enable-rtfl Build with RTFL messages (for debugging rendering)])
+AC_ARG_ENABLE(graph2, [ --disable-graph2 Use simple Graph widget instead of Graph2])
+AC_ARG_ENABLE(java, [ --disable-java Build RTFL java agent])
+AC_ARG_WITH(java-home,[ --with-java-home=DIR Specify where to find the JDK], JAVA_HOME=$withval)
+
+AC_PROG_CC
+AC_PROG_CXX
+AC_PROG_CPP
+AC_PROG_LIBTOOL
+
+dnl ----------------------------
+dnl Check our char and int types
+dnl ----------------------------
+dnl
+AC_CHECK_SIZEOF(char)
+AC_CHECK_SIZEOF(short)
+AC_CHECK_SIZEOF(long)
+AC_CHECK_SIZEOF(int)
+AC_CHECK_SIZEOF(void *)
+
+AC_TYPE_INT16_T
+AC_TYPE_UINT16_T
+AC_TYPE_INT32_T
+AC_TYPE_UINT32_T
+
+dnl -----------------------------------------------------------------
+dnl Check for absolute path of working directory.
+dnl This is needed for RTFL, to get full the full paths of the source
+dnl file names
+dnl -----------------------------------------------------------------
+dnl
+BASE_CUR_WORKING_DIR=`pwd`
+
+dnl --------------------------------------
+dnl Check whether to add /usr/local or not
+dnl (this is somewhat a religious problem)
+dnl --------------------------------------
+dnl
+if test "`$CPP -v < /dev/null 2>&1 | grep '/usr/local/include' 2>&1`" = ""; then
+ CPPFLAGS="$CPPFLAGS -I/usr/local/include"
+ LDFLAGS="$LDFLAGS -L/usr/local/lib"
+fi
+
+dnl ----------------------
+dnl Test for FLTK 1.3 library
+dnl ----------------------
+dnl
+dnl For debugging and to be user friendly
+AC_MSG_CHECKING([FLTK 1.3])
+fltk_version="`fltk-config --version 2>/dev/null`"
+case $fltk_version in
+ 1.3.*) AC_MSG_RESULT(yes)
+ LIBFLTK_CXXFLAGS=`fltk-config --cxxflags`
+ LIBFLTK_LIBS=`fltk-config --ldflags`;;
+ ?*) AC_MSG_RESULT(no)
+ AC_MSG_ERROR(FLTK 1.3 required; version found: $fltk_version);;
+ *) AC_MSG_RESULT(no)
+ AC_MSG_ERROR(FLTK 1.3 required; fltk-config not found)
+esac
+
+dnl -------------------------
+dnl Test for Graphviz library
+dnl -------------------------
+AC_MSG_CHECKING([Graphviz library >= 2.38.0])
+AC_RUN_IFELSE([AC_LANG_PROGRAM([[
+#include <graphviz/graphviz_version.h>
+#include <ctype.h>
+#include <stdlib.h>
+
+static int version_cmp (const char *v1, const char *v2)
+{
+ const char *s1 = v1, *s2 = v2;
+ while (*s1 && *s2) {
+ if (isdigit (*s1) && isdigit (*s2)) {
+ char buf1[10], buf2[10];
+ int n1 = 0, n2 = 0;
+
+ while (isdigit (*s1)) {
+ if (n1 < 9) buf1[n1++] = *s1;
+ s1++;
+ }
+
+ while (isdigit (*s2)) {
+ if (n2 < 9) buf2[n2++] = *s2;
+ s2++;
+ }
+
+ buf1[n1] = buf2[n2] = 0;
+ int c = atoi (buf1) - atoi (buf2);
+ if (c != 0)
+ return c;
+ } else {
+ if (*s1 != *s2)
+ return *s1 - *s2;
+ s1++;
+ s2++;
+ }
+ }
+
+ return *s1 - *s2;
+}
+]],[[
+if(version_cmp (PACKAGE_VERSION, "2.38.0") >= 0)
+ return 0;
+else
+ return 1;
+]])],
+[AC_MSG_RESULT(yes)
+ HAS_GRAPHVIZ=yes
+ AM_CONDITIONAL([HAS_GRAPHVIZ], [true])
+ GRAPHVIZ_LIBS="-lcgraph -lgvc"],
+[AC_MSG_RESULT(no)
+ HAS_GRAPHVIZ=no
+ AM_CONDITIONAL([HAS_GRAPHVIZ], [false])]
+[AC_MSG_RESULT(no)
+ HAS_GRAPHVIZ=no
+ AM_CONDITIONAL([HAS_GRAPHVIZ], [false])
+ AC_MSG_WARN([Testing Graphviz library not possible when cross-compiling.])])
+
+dnl ------------
+dnl Test for JDK
+dnl ------------
+AC_MSG_CHECKING([JDK])
+if test "$enable_java" = no ; then
+ AC_MSG_RESULT(disabled)
+ AM_CONDITIONAL([HAS_JAVA], [false])
+ JAVA_HOME=""
+else
+ # Follow symbolic links of javac in $PATH.
+ if test -z "$JAVA_HOME"; then
+ if which javac >/dev/null; then
+ javac=$(which javac)
+ while test -n "$javac"; do
+ nextjavac=$(readlink $javac)
+ if test -z "$nextjavac"; then
+ JAVA_HOME=${javac%/bin/javac}
+ if test $JAVA_HOME = $javac; then
+ AC_MSG_RESULT(no)
+ AC_MSG_WARN([Javac found at $javac, which is strange.])
+ AM_CONDITIONAL([HAS_JAVA], [false])
+ JAVA_HOME=""
+ fi
+ fi
+ javac=$nextjavac
+ done
+ else
+ AC_MSG_RESULT(no)
+ AM_CONDITIONAL([HAS_JAVA], [false])
+ JAVA_HOME=""
+ fi
+ fi
+fi
+
+if test -n "$JAVA_HOME"; then
+ if test '!' -e $JAVA_HOME/include/jvmti.h; then
+ AC_MSG_RESULT(no)
+ AC_MSG_WARN([$JAVA_HOME/include/jvmti.h not found: JDK not usable.])
+ AM_CONDITIONAL([HAS_JAVA], [false])
+ JAVA_HOME=""
+ else
+ AC_MSG_RESULT(yes)
+ AM_CONDITIONAL([HAS_JAVA], [true])
+ # Hopefully only simple directory names ...
+ JAVA_CFLAGS="-I$JAVA_HOME/include"
+ if test '!' -e $JAVA_HOME/include/jni_md.h; then
+ # For some JDKs, "jni_md.h" is only in a OS specific directory.
+ JAVA_CFLAGS=$JAVA_CFLAGS" -I"`find $JAVA_HOME/include/ -name jni_md.h \
+ | head -1 | xargs dirname`
+ fi
+ fi
+fi
+
+dnl --------------------
+dnl Command line options
+dnl --------------------
+dnl
+if test "x$enable_efence" = "xyes" ; then
+ LIBS="-lefence $LIBS"
+fi
+if test "x$enable_gprof" = "xyes" ; then
+ CXXFLAGS="$CXXFLAGS -pg"
+fi
+if test "x$enable_insure" = "xyes" ; then
+ CC="insure -Zoi \"compiler $CC\""
+ LIBS="$LIBS -lstdc++-2-libc6.1-1-2.9.0"
+fi
+if test "x$enable_rtfl" = "xyes" ; then
+ CXXFLAGS="$CXXFLAGS -DDBG_RTFL"
+fi
+if test "$enable_graph2" = no ; then
+ AM_CONDITIONAL([USE_GRAPH2], [false])
+else
+ if test $HAS_GRAPHVIZ = yes ; then
+ AM_CONDITIONAL([USE_GRAPH2], [true])
+ CXXFLAGS="$CXXFLAGS -DUSE_GRAPH2"
+ else
+ AM_CONDITIONAL([USE_GRAPH2], [false])
+ AC_MSG_WARN([Graphviz library >= 2.38.0 not found. Graph2 is not enabled.])
+ WARN_GRAPH=yes
+ fi
+fi
+
+dnl -----------------------
+dnl Checks for header files
+dnl -----------------------
+dnl
+AC_CHECK_HEADERS(fcntl.h unistd.h sys/uio.h)
+
+dnl --------------------------
+dnl Check for compiler options
+dnl --------------------------
+dnl
+if eval "test x$GCC = xyes"; then
+ if test "`echo $CFLAGS | grep '\-D_REENTRANT' 2> /dev/null`" = ""; then
+ CFLAGS="$CFLAGS -D_REENTRANT"
+ fi
+ if test "`echo $CFLAGS | grep '\-D_THREAD_SAFE' 2> /dev/null`" = ""; then
+ CFLAGS="$CFLAGS -D_THREAD_SAFE"
+ fi
+ if test "`echo $CFLAGS | grep '\-Wall' 2> /dev/null`" = ""; then
+ CFLAGS="$CFLAGS -Wall"
+ fi
+ if test "`echo $CFLAGS | grep -e '-W ' -e '-W$' 2> /dev/null`" = ""; then
+ CFLAGS="$CFLAGS -W"
+ fi
+ if test "`echo $CFLAGS | grep '\-Wno-unused-parameter' 2> /dev/null`" = ""; then
+ CFLAGS="$CFLAGS -Wno-unused-parameter"
+ fi
+ if test "`echo $CFLAGS | grep '\-Waggregate-return' 2> /dev/null`" = ""; then
+ CFLAGS="$CFLAGS -Waggregate-return"
+ fi
+fi
+
+dnl -----------
+dnl CXX options
+dnl -----------
+dnl
+if eval "test x$GCC = xyes"; then
+ CXXFLAGS="$CXXFLAGS -Wall -W -Wno-unused-parameter -fno-rtti -fno-exceptions"
+fi
+
+AC_SUBST(BASE_CUR_WORKING_DIR)
+AC_SUBST(LIBFLTK_CXXFLAGS)
+AC_SUBST(GRAPHVIZ_LIBS)
+AC_SUBST(LIBFLTK_LIBS)
+AC_SUBST(JAVA_HOME)
+AC_SUBST(JAVA_CFLAGS)
+AC_SUBST(datadir)
+
+AC_CONFIG_FILES([
+ Makefile
+ lout/Makefile
+ common/Makefile
+ dw/Makefile
+ dwr/Makefile
+ objects/Makefile
+ tests/Makefile
+ scripts/Makefile
+ doc/Makefile
+ java/Makefile
+])
+
+AC_OUTPUT
+
+dnl --------------------------
+dnl Some more notable messages
+dnl --------------------------
+
+if test "$WARN_GRAPH" = yes; then
+ echo '----------------------------------------------------------------------'
+ echo 'NOTE: No Graphviz library >= 2.38.0 was found, and you did not'
+ echo 'explicitly disable the Graph2 widget, which depends on Graphviz. It is'
+ echo 'recommend to install the Graphviz library and thus enable Graph2 which'
+ echo 'greatly improves rendering of rtfl-objview. See README for details.'
+ echo '----------------------------------------------------------------------'
+fi
diff --git a/debug_rtfl.hh b/debug_rtfl.hh
new file mode 100644
index 0000000..a4b5bca
--- /dev/null
+++ b/debug_rtfl.hh
@@ -0,0 +1,461 @@
+// WARNING: This file has been generated. Do not edit!
+
+/*
+ * This file is part of RTFL, see <http://home.gna.org/rtfl/>
+ * for details.
+ *
+ * This file (but not RTFL itself) is in the public domain, since it is only a
+ * simple implementation of a protocol, containing nothing more than trivial
+ * work. However, it would be nice to keep this notice, along with the URL
+ * above.
+ *
+ * ----------------------------------------------------------------------------
+ *
+ * Defines macros for printing RTFL commands. See documentation for detail
+ * (online at <http://home.gna.org/rtfl/doc/rtfl.html>). These macros are only
+ * active, when the pre-processor variable DBG_RTFL is defined. If not,
+ * alternatives are defined, which have no effect.
+ *
+ * This variant assumes that __FILE__ is only the base of the source file name,
+ * so, to get the full path, CUR_WORKING_DIR has to be defined. See RTFL
+ * documentation for more details.
+ */
+
+#ifndef __DEBUG_RTFL_HH__
+#define __DEBUG_RTFL_HH__
+
+#ifdef DBG_RTFL
+
+// =======================================
+// Used by all modules
+// =======================================
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <unistd.h>
+#include <sys/time.h>
+
+#define DBG_IF_RTFL if(1)
+
+#define STMT_START do
+#define STMT_END while (0)
+
+// Prints an RTFL message to stdout. "fmt" contains simple format
+// characters how to deal with the additional arguments (no "%"
+// preceeding, as in printf) or "q" (which additionally
+// (double-)quotes quotation marks) or "c" (short for "#%06x" and used
+// for colors), or other characters, which are simply printed. No
+// quoting: this function cannot be used to print the characters "d",
+// "p", "s" and "q" directly.
+
+inline void rtfl_print (const char *module, const char *version,
+ const char *file, int line, int processId,
+ const char *fmt, ...)
+{
+ // "\n" at the beginning just in case that the previous line is not
+ // finished yet.
+ printf ("\n[rtfl-%s-%s]%s:%d:%d:", module, version, file, line, processId);
+
+ va_list args;
+ va_start (args, fmt);
+
+ for (int i = 0; fmt[i]; i++) {
+ int n;
+ void *p;
+ char *s;
+
+ switch (fmt[i]) {
+ case 'd':
+ n = va_arg(args, int);
+ printf ("%d", n);
+ break;
+
+ case 'p':
+ p = va_arg(args, void*);
+ printf ("%p", p);
+ break;
+
+ case 's':
+ s = va_arg (args, char*);
+ for (int j = 0; s[j]; j++) {
+ if (s[j] == ':' || s[j] == '\\')
+ putchar ('\\');
+ putchar (s[j]);
+ }
+ break;
+
+ case 'q':
+ s = va_arg (args, char*);
+ for (int j = 0; s[j]; j++) {
+ if (s[j] == ':' || s[j] == '\\')
+ putchar ('\\');
+ else if (s[j] == '\"')
+ printf ("\\\\"); // a quoted quoting character
+ putchar (s[j]);
+ }
+ break;
+
+ case 'c':
+ n = va_arg(args, int);
+ printf ("#%06x", n);
+ break;
+
+ default:
+ putchar (fmt[i]);
+ break;
+ }
+ }
+
+ va_end (args);
+
+ putchar ('\n');
+ fflush (stdout);
+}
+
+#define RTFL_PRINT(module, version, cmd, fmt, ...) \
+ rtfl_print (module, version, CUR_WORKING_DIR "/" __FILE__, __LINE__, \
+ getpid (), "s:" fmt, cmd, __VA_ARGS__)
+
+
+// ==================================
+// General module
+// ==================================
+
+#define RTFL_GEN_VERSION "1.0"
+
+#define RTFL_GEN_PRINT(cmd, fmt, ...) \
+ RTFL_PRINT ("gen", RTFL_GEN_VERSION, cmd, fmt, __VA_ARGS__)
+
+#define DBG_GEN_TIME() \
+ STMT_START { \
+ struct timeval tv; \
+ gettimeofday(&tv, NULL); \
+ char buf[32]; \
+ snprintf (buf, sizeof (buf), "%ld%06ld", tv.tv_sec, tv.tv_usec); \
+ RTFL_GEN_PRINT ("time", "s", buf); \
+ } STMT_END
+
+
+// ==================================
+// Objects module
+// ==================================
+
+#define RTFL_OBJ_VERSION "1.0"
+
+#define RTFL_OBJ_PRINT(cmd, fmt, ...) \
+ RTFL_PRINT ("obj", RTFL_OBJ_VERSION, cmd, fmt, __VA_ARGS__)
+
+#define DBG_OBJ_MSG(aspect, prio, msg) \
+ DBG_OBJ_MSG_O (aspect, prio, this, msg)
+
+#define DBG_OBJ_MSG_O(aspect, prio, obj, msg) \
+ RTFL_OBJ_PRINT ("msg", "p:s:d:s", obj, aspect, prio, msg)
+
+#define DBG_OBJ_MSGF(aspect, prio, fmt, ...) \
+ STMT_START { \
+ char msg[256]; \
+ snprintf (msg, sizeof (msg), fmt, __VA_ARGS__); \
+ DBG_OBJ_MSG (aspect, prio, msg); \
+ } STMT_END
+
+#define DBG_OBJ_MSGF_O(aspect, prio, obj, fmt, ...) \
+ STMT_START { \
+ char msg[256]; \
+ snprintf (msg, sizeof (msg), fmt, __VA_ARGS__); \
+ DBG_OBJ_MSG_O (aspect, prio, obj, msg); \
+ } STMT_END
+
+#define DBG_OBJ_MARK(aspect, prio, mark) \
+ DBG_OBJ_MARK_O (aspect, prio, this, mark)
+
+#define DBG_OBJ_MARK_O(aspect, prio, obj, mark) \
+ RTFL_OBJ_PRINT ("mark", "p:s:d:s", obj, aspect, prio, mark)
+
+#define DBG_OBJ_MARKF(aspect, prio, fmt, ...) \
+ STMT_START { \
+ char mark[256]; \
+ snprintf (mark, sizeof (mark), fmt, __VA_ARGS__); \
+ DBG_OBJ_MARK (aspect, prio, mark); \
+ } STMT_END
+
+#define DBG_OBJ_MARKF_O(aspect, prio, obj, fmt, ...) \
+ STMT_START { \
+ char mark[256]; \
+ snprintf (mark, sizeof (mark), fmt, __VA_ARGS__); \
+ DBG_OBJ_MARK_O (aspect, prio, obj, mark); \
+ } STMT_END
+
+#define DBG_OBJ_MSG_START() \
+ DBG_OBJ_MSG_START_O (this)
+
+#define DBG_OBJ_MSG_START_O(obj) \
+ RTFL_OBJ_PRINT ("msg-start", "p", obj)
+
+#define DBG_OBJ_MSG_END() \
+ DBG_OBJ_MSG_END_O (this)
+
+#define DBG_OBJ_MSG_END_O(obj) \
+ RTFL_OBJ_PRINT ("msg-end", "p", obj)
+
+#define DBG_OBJ_ENTER0(aspect, prio, funname) \
+ DBG_OBJ_ENTER0_O (aspect, prio, this, funname)
+
+#define DBG_OBJ_ENTER0_O(aspect, prio, obj, funname) \
+ RTFL_OBJ_PRINT ("enter", "p:s:d:s:", obj, aspect, prio, funname);
+
+#define DBG_OBJ_ENTER(aspect, prio, funname, fmt, ...) \
+ STMT_START { \
+ char args[256]; \
+ snprintf (args, sizeof (args), fmt, __VA_ARGS__); \
+ RTFL_OBJ_PRINT ("enter", "p:s:d:s:s", this, aspect, prio, funname, \
+ args); \
+ } STMT_END
+
+#define DBG_OBJ_ENTER_O(aspect, prio, obj, funname, fmt, ...) \
+ STMT_START { \
+ char args[256]; \
+ snprintf (args, sizeof (args), fmt, __VA_ARGS__); \
+ RTFL_OBJ_PRINT ("enter", "p:s:d:s:s", obj, aspect, prio, funname, \
+ args); \
+ } STMT_END
+
+#define DBG_OBJ_LEAVE() \
+ DBG_OBJ_LEAVE_O (this)
+
+#define DBG_OBJ_LEAVE_O(obj) \
+ RTFL_OBJ_PRINT ("leave", "p", obj);
+
+#define DBG_OBJ_LEAVE_VAL(fmt, ...) \
+ STMT_START { \
+ char vals[256]; \
+ snprintf (vals, sizeof (vals), fmt, __VA_ARGS__); \
+ RTFL_OBJ_PRINT ("leave", "p:s", this, vals); \
+ } STMT_END
+
+#define DBG_OBJ_LEAVE_VAL_O(obj, fmt, ...) \
+ STMT_START { \
+ char vals[256]; \
+ snprintf (vals, sizeof (vals), fmt, __VA_ARGS__); \
+ RTFL_OBJ_PRINT ("leave", "p:s", obj, vals); \
+ } STMT_END
+
+#define DBG_OBJ_LEAVE_VAL0(val) \
+ DBG_OBJ_LEAVE_VAL0_O (this, val)
+
+#define DBG_OBJ_LEAVE_VAL0_O(obj, val) \
+ RTFL_OBJ_PRINT ("leave", "p:s:", obj, val)
+
+#define DBG_OBJ_CREATE(klass) \
+ DBG_OBJ_CREATE_O (this, klass)
+
+#define DBG_OBJ_CREATE_O(obj, klass) \
+ RTFL_OBJ_PRINT ("create", "p:s", obj, klass);
+
+#define DBG_OBJ_DELETE() \
+ DBG_OBJ_DELETE_O (this)
+
+#define DBG_OBJ_DELETE_O(obj) \
+ RTFL_OBJ_PRINT ("delete", "p", obj);
+
+#define DBG_OBJ_BASECLASS(klass) \
+ RTFL_OBJ_PRINT ("ident", "p:p", this, (klass*)this);
+
+#define DBG_OBJ_ASSOC(parent, child) \
+ RTFL_OBJ_PRINT ("assoc", "p:p", parent, child); \
+
+#define DBG_OBJ_ASSOC_PARENT(parent) \
+ DBG_OBJ_ASSOC (parent, this);
+
+#define DBG_OBJ_ASSOC_CHILD(child) \
+ DBG_OBJ_ASSOC (this, child);
+
+#define DBG_OBJ_SET_NUM(var, val) \
+ DBG_OBJ_SET_NUM_O (this, var, val)
+
+#define DBG_OBJ_SET_NUM_O(obj, var, val) \
+ RTFL_OBJ_PRINT ("set", "p:s:d", obj, var, val)
+
+#define DBG_OBJ_SET_SYM(var, val) \
+ DBG_OBJ_SET_SYM_O (this, var, val)
+
+#define DBG_OBJ_SET_SYM_O(obj, var, val) \
+ RTFL_OBJ_PRINT ("set", "p:s:s", obj, var, val)
+
+#define DBG_OBJ_SET_BOOL(var, val) \
+ DBG_OBJ_SET_BOOL_O (this, var, val)
+
+#define DBG_OBJ_SET_BOOL_O(obj, var, val) \
+ RTFL_OBJ_PRINT ("set", "p:s:s", obj, var, (val) ? "true" : "false")
+
+#define DBG_OBJ_SET_STR(var, val) \
+ DBG_OBJ_SET_STR_O (this, var, val)
+
+#define DBG_OBJ_SET_STR_O(obj, var, val) \
+ RTFL_OBJ_PRINT ("set", "p:s:\"q\"", obj, var, val)
+
+#define DBG_OBJ_SET_PTR(var, val) \
+ DBG_OBJ_SET_PTR_O (this, var, val)
+
+#define DBG_OBJ_SET_PTR_O(obj, var, val) \
+ RTFL_OBJ_PRINT ("set", "p:s:p", obj, var, val)
+
+#define DBG_OBJ_SET_COL(var, val) \
+ DBG_OBJ_SET_COL_O (this, var, val)
+
+#define DBG_OBJ_SET_COL_O(obj, var, val) \
+ RTFL_OBJ_PRINT ("set", "p:s:c", obj, var, val)
+
+#define DBG_OBJ_ARRSET_NUM(var, ind, val) \
+ DBG_OBJ_ARRSET_NUM_O (this, var, ind, val)
+
+#define DBG_OBJ_ARRSET_NUM_O(obj, var, ind, val) \
+ RTFL_OBJ_PRINT ("set", "p:s.d:d", obj, var, ind, val)
+
+#define DBG_OBJ_ARRSET_SYM(var, ind, val) \
+ DBG_OBJ_ARRSET_SYM_O (this, var, ind, val)
+
+#define DBG_OBJ_ARRSET_SYM_O(obj, var, ind, val) \
+ RTFL_OBJ_PRINT ("set", "p:s.d:s", obj, var, ind, val)
+
+#define DBG_OBJ_ARRSET_BOOL(var, ind, val) \
+ DBG_OBJ_ARRSET_BOOL_O (this, var, ind, val)
+
+#define DBG_OBJ_ARRSET_BOOL_O(obj, var, ind, val) \
+ RTFL_OBJ_PRINT ("set", "p:s.d:s", obj, var, ind, (val) ? "true" : "false")
+
+#define DBG_OBJ_ARRSET_STR(var, ind, val) \
+ DBG_OBJ_ARRSET_STR_O (this, var, ind, val)
+
+#define DBG_OBJ_ARRSET_STR_O(obj, var, ind, val) \
+ RTFL_OBJ_PRINT ("set", "p:s.d:\"q\"", obj, var, ind, val)
+
+#define DBG_OBJ_ARRSET_PTR(var, ind, val) \
+ DBG_OBJ_ARRSET_PTR_O (this, var, ind, val)
+
+#define DBG_OBJ_ARRSET_PTR_O(obj, var, ind, val) \
+ RTFL_OBJ_PRINT ("set", "p:s.d:p", obj, var, ind, val)
+
+#define DBG_OBJ_ARRSET_COL(var, ind, val) \
+ DBG_OBJ_ARRSET_COL_O (this, var, ind, val)
+
+#define DBG_OBJ_ARRSET_COL_O(obj, var, ind, val) \
+ RTFL_OBJ_PRINT ("set", "p:s.d:c", obj, var, ind, val)
+
+#define DBG_OBJ_ARRATTRSET_NUM(var, ind, attr, val) \
+ DBG_OBJ_ARRATTRSET_NUM_O (this, var, ind, attr, val)
+
+#define DBG_OBJ_ARRATTRSET_NUM_O(obj, var, ind, attr, val) \
+ RTFL_OBJ_PRINT ("set", "p:s.d.s:d", obj, var, ind, attr, val)
+
+#define DBG_OBJ_ARRATTRSET_SYM(var, ind, attr, val) \
+ DBG_OBJ_ARRATTRSET_SYM_O (this, var, ind, attr, val)
+
+#define DBG_OBJ_ARRATTRSET_SYM_O(obj, var, ind, attr, val) \
+ RTFL_OBJ_PRINT ("set", "p:s.d.s:s", obj, var, ind, attr, val)
+
+#define DBG_OBJ_ARRATTRSET_BOOL(var, ind, attr, val) \
+ DBG_OBJ_ARRATTRSET_BOOL_O (this, var, ind, attr, val)
+
+#define DBG_OBJ_ARRATTRSET_BOOL_O(obj, var, ind, attr, val) \
+ RTFL_OBJ_PRINT ("set", "p:s.d.s:s", obj, var, ind, attr, \
+ (val) ? "true" : "false")
+
+#define DBG_OBJ_ARRATTRSET_STR(var, ind, attr, val) \
+ DBG_OBJ_ARRATTRSET_STR_O (this, var, ind, attr, val)
+
+#define DBG_OBJ_ARRATTRSET_STR_O(obj, var, ind, attr, val) \
+ RTFL_OBJ_PRINT ("set", "p:s.d.s:\"q\"", obj, var, ind, attr, val)
+
+#define DBG_OBJ_ARRATTRSET_PTR(var, ind, attr, val) \
+ DBG_OBJ_ARRATTRSET_PTR_O (this, var, ind, attr, val)
+
+#define DBG_OBJ_ARRATTRSET_PTR_O(obj, var, ind, attr, val) \
+ RTFL_OBJ_PRINT ("set", "p:s.d.s:p", obj, var, ind, attr, val)
+
+#define DBG_OBJ_ARRATTRSET_COL(var, ind, attr, val) \
+ DBG_OBJ_ARRATTRSET_COL_O (this, var, ind, attr, val)
+
+#define DBG_OBJ_ARRATTRSET_COL_O(obj, var, ind, attr, val) \
+ RTFL_OBJ_PRINT ("set", "p:s.d.s:c", obj, var, ind, attr, val)
+
+#define DBG_OBJ_CLASS_COLOR(klass, color) \
+ RTFL_OBJ_PRINT ("class-color", "s:s", klass, color)
+
+#else /* DBG_RTFL */
+
+#define STMT_NOP do { } while (0)
+
+#define DBG_IF_RTFL if(0)
+
+#define DBG_GEN_TIME() STMT_NOP
+#define DBG_OBJ_MSG(aspect, prio, msg) STMT_NOP
+#define DBG_OBJ_MSG_O(aspect, prio, obj, msg) STMT_NOP
+#define DBG_OBJ_MSGF(aspect, prio, fmt, ...) STMT_NOP
+#define DBG_OBJ_MSGF_O(aspect, prio, obj, fmt, ...) STMT_NOP
+#define DBG_OBJ_MARK(aspect, prio, mark) STMT_NOP
+#define DBG_OBJ_MARK_O(aspect, prio, obj, mark) STMT_NOP
+#define DBG_OBJ_MARKF(aspect, prio, fmt, ...) STMT_NOP
+#define DBG_OBJ_MARKF_O(aspect, prio, obj, fmt, ...) STMT_NOP
+#define DBG_OBJ_MSG_START() STMT_NOP
+#define DBG_OBJ_MSG_START_O(obj) STMT_NOP
+#define DBG_OBJ_MSG_END() STMT_NOP
+#define DBG_OBJ_MSG_END_O(obj) STMT_NOP
+#define DBG_OBJ_ENTER0(aspect, prio, funname) STMT_NOP
+#define DBG_OBJ_ENTER0_O(aspect, prio, obj, funname) STMT_NOP
+#define DBG_OBJ_ENTER(aspect, prio, funname, fmt, ...) STMT_NOP
+#define DBG_OBJ_ENTER_O(aspect, prio, obj, funname, fmt, ...) STMT_NOP
+#define DBG_OBJ_LEAVE() STMT_NOP
+#define DBG_OBJ_LEAVE_O(obj) STMT_NOP
+#define DBG_OBJ_LEAVE_VAL(fmt, ...) STMT_NOP
+#define DBG_OBJ_LEAVE_VAL_O(obj, fmt, ...) STMT_NOP
+#define DBG_OBJ_LEAVE_VAL0(val) STMT_NOP
+#define DBG_OBJ_LEAVE_VAL0_O(obj, val) STMT_NOP
+#define DBG_OBJ_CREATE(klass) STMT_NOP
+#define DBG_OBJ_CREATE_O(obj, klass) STMT_NOP
+#define DBG_OBJ_DELETE() STMT_NOP
+#define DBG_OBJ_DELETE_O(obj) STMT_NOP
+#define DBG_OBJ_BASECLASS(klass) STMT_NOP
+#define DBG_OBJ_ASSOC(parent, child) STMT_NOP
+#define DBG_OBJ_ASSOC_PARENT(parent) STMT_NOP
+#define DBG_OBJ_ASSOC_CHILD(child) STMT_NOP
+#define DBG_OBJ_SET_NUM(var, val) STMT_NOP
+#define DBG_OBJ_SET_NUM_O(obj, var, val) STMT_NOP
+#define DBG_OBJ_SET_SYM(var, val) STMT_NOP
+#define DBG_OBJ_SET_SYM_O(obj, var, val) STMT_NOP
+#define DBG_OBJ_SET_BOOL(var, val) STMT_NOP
+#define DBG_OBJ_SET_BOOL_O(obj, var, val) STMT_NOP
+#define DBG_OBJ_SET_STR(var, val) STMT_NOP
+#define DBG_OBJ_SET_STR_O(obj, var, val) STMT_NOP
+#define DBG_OBJ_SET_PTR(var, val) STMT_NOP
+#define DBG_OBJ_SET_PTR_O(obj, var, val) STMT_NOP
+#define DBG_OBJ_SET_COL(var, val) STMT_NOP
+#define DBG_OBJ_SET_COL_O(obj, var, val) STMT_NOP
+#define DBG_OBJ_ARRSET_NUM(var, ind, val) STMT_NOP
+#define DBG_OBJ_ARRSET_NUM_O(obj, var, ind, val) STMT_NOP
+#define DBG_OBJ_ARRSET_SYM(var, ind, val) STMT_NOP
+#define DBG_OBJ_ARRSET_SYM_O(obj, var, ind, val) STMT_NOP
+#define DBG_OBJ_ARRSET_BOOL(var, ind, val) STMT_NOP
+#define DBG_OBJ_ARRSET_BOOL_O(obj, var, ind, val) STMT_NOP
+#define DBG_OBJ_ARRSET_STR(var, ind, val) STMT_NOP
+#define DBG_OBJ_ARRSET_STR_O(obj, var, ind, val) STMT_NOP
+#define DBG_OBJ_ARRSET_PTR(var, ind, val) STMT_NOP
+#define DBG_OBJ_ARRSET_PTR_O(obj, var, ind, val) STMT_NOP
+#define DBG_OBJ_ARRSET_COL(var, ind, val) STMT_NOP
+#define DBG_OBJ_ARRSET_COL_O(obj, var, ind, val) STMT_NOP
+#define DBG_OBJ_ARRATTRSET_NUM(var, ind, attr, val) STMT_NOP
+#define DBG_OBJ_ARRATTRSET_NUM_O(obj, var, ind, attr, val) STMT_NOP
+#define DBG_OBJ_ARRATTRSET_SYM(var, ind, attr, val) STMT_NOP
+#define DBG_OBJ_ARRATTRSET_SYM_O(obj, var, ind, attr, val) STMT_NOP
+#define DBG_OBJ_ARRATTRSET_BOOL(var, ind, attr, val) STMT_NOP
+#define DBG_OBJ_ARRATTRSET_BOOL_O(obj, var, ind, attr, val) STMT_NOP
+#define DBG_OBJ_ARRATTRSET_STR(var, ind, attr, val) STMT_NOP
+#define DBG_OBJ_ARRATTRSET_STR_O(obj, var, ind, attr, val) STMT_NOP
+#define DBG_OBJ_ARRATTRSET_PTR(var, ind, attr, val) STMT_NOP
+#define DBG_OBJ_ARRATTRSET_PTR_O(obj, var, ind, attr, val) STMT_NOP
+#define DBG_OBJ_ARRATTRSET_COL(var, ind, attr, val) STMT_NOP
+#define DBG_OBJ_ARRATTRSET_COL_O(obj, var, ind, attr, val) STMT_NOP
+#define DBG_OBJ_CLASS_COLOR(klass, color) STMT_NOP
+
+#endif /* DBG_RTFL */
+
+#endif /* __DEBUG_RTFL_HH__ */
diff --git a/debug_rtfl.hh.in b/debug_rtfl.hh.in
new file mode 100644
index 0000000..9d9fd55
--- /dev/null
+++ b/debug_rtfl.hh.in
@@ -0,0 +1,310 @@
+/*
+ * This file is part of RTFL, see <http://home.gna.org/rtfl/>
+ * for details.
+ *
+ * This file (but not RTFL itself) is in the public domain, since it is only a
+ * simple implementation of a protocol, containing nothing more than trivial
+ * work. However, it would be nice to keep this notice, along with the URL
+ * above.
+ *
+ * ----------------------------------------------------------------------------
+ *
+ * Defines macros for printing RTFL commands. See documentation for detail
+ * (online at <http://home.gna.org/rtfl/doc/rtfl.html>). These macros are only
+ * active, when the pre-processor variable DBG_RTFL is defined. If not,
+ * alternatives are defined, which have no effect.
+ *
+ * This variant assumes that __FILE__ is only the base of the source file name,
+ * so, to get the full path, CUR_WORKING_DIR has to be defined. See RTFL
+ * documentation for more details.
+ */
+
+#ifndef __DEBUG_RTFL_HH__
+#define __DEBUG_RTFL_HH__
+
+#ifdef DBG_RTFL
+
+// =======================================
+// Used by all modules
+// =======================================
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <unistd.h>
+#include <sys/time.h>
+
+#define DBG_IF_RTFL if(1)
+
+#define STMT_START do
+#define STMT_END while (0)
+
+// Prints an RTFL message to stdout. "fmt" contains simple format
+// characters how to deal with the additional arguments (no "%"
+// preceeding, as in printf) or "q" (which additionally
+// (double-)quotes quotation marks) or "c" (short for "#%06x" and used
+// for colors), or other characters, which are simply printed. No
+// quoting: this function cannot be used to print the characters "d",
+// "p", "s" and "q" directly.
+
+inline void rtfl_print (const char *module, const char *version,
+ const char *file, int line, const char *fmt, ...)
+{
+ // "\n" at the beginning just in case that the previous line is not
+ // finished yet.
+ printf ("\n[rtfl-%s-%s]%s:%d:%d:", module, version, file, line, getpid ());
+
+ va_list args;
+ va_start (args, fmt);
+
+ for (int i = 0; fmt[i]; i++) {
+ int n;
+ void *p;
+ char *s;
+
+ switch (fmt[i]) {
+ case 'd':
+ n = va_arg(args, int);
+ printf ("%d", n);
+ break;
+
+ case 'p':
+ p = va_arg(args, void*);
+ printf ("%p", p);
+ break;
+
+ case 's':
+ s = va_arg (args, char*);
+ for (int j = 0; s[j]; j++) {
+ if (s[j] == ':' || s[j] == '\\')
+ putchar ('\\');
+ putchar (s[j]);
+ }
+ break;
+
+ case 'q':
+ s = va_arg (args, char*);
+ for (int j = 0; s[j]; j++) {
+ if (s[j] == ':' || s[j] == '\\')
+ putchar ('\\');
+ else if (s[j] == '\"')
+ printf ("\\\\"); // a quoted quoting character
+ putchar (s[j]);
+ }
+ break;
+
+ case 'c':
+ n = va_arg(args, int);
+ printf ("#%06x", n);
+ break;
+
+ default:
+ putchar (fmt[i]);
+ break;
+ }
+ }
+
+ va_end (args);
+
+ putchar ('\n');
+ fflush (stdout);
+}
+
+#define RTFL_PRINT(module, version, cmd, fmt, ...) \
+ rtfl_print (module, version, CUR_WORKING_DIR "/" __FILE__, __LINE__, \
+ "s:" fmt, cmd, __VA_ARGS__)
+
+
+// ==================================
+// General module
+// ==================================
+
+#define RTFL_GEN_VERSION "1.0"
+
+#define RTFL_GEN_PRINT(cmd, fmt, ...) \
+ RTFL_PRINT ("gen", RTFL_GEN_VERSION, cmd, fmt, __VA_ARGS__)
+
+#define DBG_GEN_TIME() \
+ STMT_START { \
+ struct timeval tv; \
+ gettimeofday(&tv, NULL); \
+ char buf[32]; \
+ snprintf (buf, sizeof (buf), "%ld%06ld", tv.tv_sec, tv.tv_usec); \
+ RTFL_GEN_PRINT ("time", "s", buf); \
+ } STMT_END
+
+
+// ==================================
+// Objects module
+// ==================================
+
+#define RTFL_OBJ_VERSION "1.0"
+
+#define RTFL_OBJ_PRINT(cmd, fmt, ...) \
+ RTFL_PRINT ("obj", RTFL_OBJ_VERSION, cmd, fmt, __VA_ARGS__)
+
+#define DBG_OBJ_MSG_O(aspect, prio, obj, msg) \
+ RTFL_OBJ_PRINT ("msg", "p:s:d:s", obj, aspect, prio, msg)
+
+#define DBG_OBJ_MSGF(aspect, prio, fmt, ...) \
+ STMT_START { \
+ char msg[256]; \
+ snprintf (msg, sizeof (msg), fmt, __VA_ARGS__); \
+ DBG_OBJ_MSG (aspect, prio, msg); \
+ } STMT_END
+
+#define DBG_OBJ_MSGF_O(aspect, prio, obj, fmt, ...) \
+ STMT_START { \
+ char msg[256]; \
+ snprintf (msg, sizeof (msg), fmt, __VA_ARGS__); \
+ DBG_OBJ_MSG_O (aspect, prio, obj, msg); \
+ } STMT_END
+
+#define DBG_OBJ_MARK_O(aspect, prio, obj, mark) \
+ RTFL_OBJ_PRINT ("mark", "p:s:d:s", obj, aspect, prio, mark)
+
+#define DBG_OBJ_MARKF(aspect, prio, fmt, ...) \
+ STMT_START { \
+ char mark[256]; \
+ snprintf (mark, sizeof (mark), fmt, __VA_ARGS__); \
+ DBG_OBJ_MARK (aspect, prio, mark); \
+ } STMT_END
+
+#define DBG_OBJ_MARKF_O(aspect, prio, obj, fmt, ...) \
+ STMT_START { \
+ char mark[256]; \
+ snprintf (mark, sizeof (mark), fmt, __VA_ARGS__); \
+ DBG_OBJ_MARK_O (aspect, prio, obj, mark); \
+ } STMT_END
+
+#define DBG_OBJ_MSG_START_O(obj) \
+ RTFL_OBJ_PRINT ("msg-start", "p", obj)
+
+#define DBG_OBJ_MSG_END_O(obj) \
+ RTFL_OBJ_PRINT ("msg-end", "p", obj)
+
+#define DBG_OBJ_ENTER0_O(aspect, prio, obj, funname) \
+ RTFL_OBJ_PRINT ("enter", "p:s:d:s:", obj, aspect, prio, funname);
+
+#define DBG_OBJ_ENTER(aspect, prio, funname, fmt, ...) \
+ STMT_START { \
+ char args[256]; \
+ snprintf (args, sizeof (args), fmt, __VA_ARGS__); \
+ RTFL_OBJ_PRINT ("enter", "p:s:d:s:s", this, aspect, prio, funname, \
+ args); \
+ } STMT_END
+
+#define DBG_OBJ_ENTER_O(aspect, prio, obj, funname, fmt, ...) \
+ STMT_START { \
+ char args[256]; \
+ snprintf (args, sizeof (args), fmt, __VA_ARGS__); \
+ RTFL_OBJ_PRINT ("enter", "p:s:d:s:s", obj, aspect, prio, funname, \
+ args); \
+ } STMT_END
+
+#define DBG_OBJ_LEAVE_O(obj) \
+ RTFL_OBJ_PRINT ("leave", "p", obj);
+
+#define DBG_OBJ_LEAVE_VAL(fmt, ...) \
+ STMT_START { \
+ char vals[256]; \
+ snprintf (vals, sizeof (vals), fmt, __VA_ARGS__); \
+ RTFL_OBJ_PRINT ("leave", "p:s", this, vals); \
+ } STMT_END
+
+#define DBG_OBJ_LEAVE_VAL_O(obj, fmt, ...) \
+ STMT_START { \
+ char vals[256]; \
+ snprintf (vals, sizeof (vals), fmt, __VA_ARGS__); \
+ RTFL_OBJ_PRINT ("leave", "p:s", obj, vals); \
+ } STMT_END
+
+#define DBG_OBJ_LEAVE_VAL0_O(obj, val) \
+ RTFL_OBJ_PRINT ("leave", "p:s:", obj, val)
+
+#define DBG_OBJ_CREATE_O(obj, klass) \
+ RTFL_OBJ_PRINT ("create", "p:s", obj, klass);
+
+#define DBG_OBJ_DELETE_O(obj) \
+ RTFL_OBJ_PRINT ("delete", "p", obj);
+
+#define DBG_OBJ_BASECLASS(klass) \
+ RTFL_OBJ_PRINT ("ident", "p:p", this, (klass*)this);
+
+#define DBG_OBJ_ASSOC(parent, child) \
+ RTFL_OBJ_PRINT ("assoc", "p:p", parent, child); \
+
+#define DBG_OBJ_ASSOC_PARENT(parent) \
+ DBG_OBJ_ASSOC (parent, this);
+
+#define DBG_OBJ_ASSOC_CHILD(child) \
+ DBG_OBJ_ASSOC (this, child);
+
+#define DBG_OBJ_SET_NUM_O(obj, var, val) \
+ RTFL_OBJ_PRINT ("set", "p:s:d", obj, var, val)
+
+#define DBG_OBJ_SET_SYM_O(obj, var, val) \
+ RTFL_OBJ_PRINT ("set", "p:s:s", obj, var, val)
+
+#define DBG_OBJ_SET_BOOL_O(obj, var, val) \
+ RTFL_OBJ_PRINT ("set", "p:s:s", obj, var, (val) ? "true" : "false")
+
+#define DBG_OBJ_SET_STR_O(obj, var, val) \
+ RTFL_OBJ_PRINT ("set", "p:s:\"q\"", obj, var, val)
+
+#define DBG_OBJ_SET_PTR_O(obj, var, val) \
+ RTFL_OBJ_PRINT ("set", "p:s:p", obj, var, val)
+
+#define DBG_OBJ_SET_COL_O(obj, var, val) \
+ RTFL_OBJ_PRINT ("set", "p:s:c", obj, var, val)
+
+#define DBG_OBJ_ARRSET_NUM_O(obj, var, ind, val) \
+ RTFL_OBJ_PRINT ("set", "p:s.d:d", obj, var, ind, val)
+
+#define DBG_OBJ_ARRSET_SYM_O(obj, var, ind, val) \
+ RTFL_OBJ_PRINT ("set", "p:s.d:s", obj, var, ind, val)
+
+#define DBG_OBJ_ARRSET_BOOL_O(obj, var, ind, val) \
+ RTFL_OBJ_PRINT ("set", "p:s.d:s", obj, var, ind, (val) ? "true" : "false")
+
+#define DBG_OBJ_ARRSET_STR_O(obj, var, ind, val) \
+ RTFL_OBJ_PRINT ("set", "p:s.d:\"q\"", obj, var, ind, val)
+
+#define DBG_OBJ_ARRSET_PTR_O(obj, var, ind, val) \
+ RTFL_OBJ_PRINT ("set", "p:s.d:p", obj, var, ind, val)
+
+#define DBG_OBJ_ARRSET_COL_O(obj, var, ind, val) \
+ RTFL_OBJ_PRINT ("set", "p:s.d:c", obj, var, ind, val)
+
+#define DBG_OBJ_ARRATTRSET_NUM_O(obj, var, ind, attr, val) \
+ RTFL_OBJ_PRINT ("set", "p:s.d.s:d", obj, var, ind, attr, val)
+
+#define DBG_OBJ_ARRATTRSET_SYM_O(obj, var, ind, attr, val) \
+ RTFL_OBJ_PRINT ("set", "p:s.d.s:s", obj, var, ind, attr, val)
+
+#define DBG_OBJ_ARRATTRSET_BOOL_O(obj, var, ind, attr, val) \
+ RTFL_OBJ_PRINT ("set", "p:s.d.s:s", obj, var, ind, attr, \
+ (val) ? "true" : "false")
+
+#define DBG_OBJ_ARRATTRSET_STR_O(obj, var, ind, attr, val) \
+ RTFL_OBJ_PRINT ("set", "p:s.d.s:\"q\"", obj, var, ind, attr, val)
+
+#define DBG_OBJ_ARRATTRSET_PTR_O(obj, var, ind, attr, val) \
+ RTFL_OBJ_PRINT ("set", "p:s.d.s:p", obj, var, ind, attr, val)
+
+#define DBG_OBJ_ARRATTRSET_COL_O(obj, var, ind, attr, val) \
+ RTFL_OBJ_PRINT ("set", "p:s.d.s:c", obj, var, ind, attr, val)
+
+#define DBG_OBJ_CLASS_COLOR(klass, color) \
+ RTFL_OBJ_PRINT ("class-color", "s:s", klass, color)
+
+#else /* DBG_RTFL */
+
+#define STMT_NOP do { } while (0)
+
+#define DBG_IF_RTFL if(0)
+
+//@inactive
+
+#endif /* DBG_RTFL */
+
+#endif /* __DEBUG_RTFL_HH__ */
diff --git a/doc/Makefile.am b/doc/Makefile.am
new file mode 100644
index 0000000..0dda147
--- /dev/null
+++ b/doc/Makefile.am
@@ -0,0 +1,4 @@
+EXTRA_DIST = \
+ rtfl.html \
+ tipsandtricks.html \
+ object-box-01.png
diff --git a/doc/object-box-01.png b/doc/object-box-01.png
new file mode 100644
index 0000000..7fcc651
--- /dev/null
+++ b/doc/object-box-01.png
Binary files differ
diff --git a/doc/rtfl.html b/doc/rtfl.html
new file mode 100644
index 0000000..87bc50e
--- /dev/null
+++ b/doc/rtfl.html
@@ -0,0 +1,997 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" lang="en">
+ <head>
+ <title>RTFL documentation</title>
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
+ <style type="text/css">
+ div.image, div.contents {
+ float: right;
+ margin: 0.5em 0 0.5em 1em
+ }
+
+ div.image, table.data {
+ text-align: center
+ }
+
+ div.contents {
+ width: 40%
+ }
+
+ p.imagedesc {
+ font-size: 0.8em;
+ font-style: italic
+ }
+
+ table.data {
+ border-collapse: collapse;
+ }
+
+ table.data td, table.data th {
+ padding: 0.1em 1em;
+ border: 1px solid;
+ }
+ </style>
+ </head>
+ <body>
+ <h1>RTFL Documentation</h1>
+
+ <div class="contents">
+ <h2>Contents</h2>
+
+ <ul>
+ <li><a href="#overview">Overview</a></li>
+ <li><a href="#synopsis">Synopsis</a></li>
+ <li><a href="#preparing_the_tested_program">Preparing the tested
+ program</a>
+ <ul>
+ <li><a href="#preparing_autoconfmake">Using RTFL with
+ <tt>autoconf</tt> and <tt>automake</tt></a></li>
+ </ul>
+ </li>
+ <li><a href="#protocol_and_macros">Protocol and macros</a>
+ <ul>
+ <li><a href="#protocol_general_module">General module</a></li>
+ <li><a href="#protocol_objects_module">Objects module</a></li>
+ </ul>
+ </li>
+ <li><a href="#using_rtfl_objcount">Using <tt>rtfl-objcount</tt></a></li>
+ <li><a href="#using_rtfl_objview">Using <tt>rtfl-objview</tt></a>
+ <ul>
+ <li><a href="#rtfl_objview_basic_usage">Basic usage</a></li>
+ <li><a href="#rtfl_objview_command_line_options">Command line
+ options</a></li>
+ <li><a href="#rtfl_objview_navigation">Navigation</a></li>
+ <li><a href="#rtfl_objview_hiding_commands">Hiding commands</a></li>
+ <li><a href="#rtfl_objview_filtering_by_type">Filtering by
+ type</a></li>
+ <li><a href="#rtfl_objview_stack_traces">Stack traces</a></li>
+ <li><a href="#rtfl_objview_marks">Marks</a></li>
+ <li><a href="#rtfl_objview_filtering_messages">Filtering
+ messages</a></li>
+ </ul>
+ </li>
+ <li><a href="#using_rtfl_objbase">Using <tt>rtfl-objbase</tt></a></li>
+ <li><a href="#using_rtfl_tee">Using <tt>rtfl-tee</tt></a></li>
+ <li><a href="#scripts">Scripts</a></li>
+ <li><a href="#see_also">See also</a></li>
+ </ul>
+ </div>
+
+ <h2 id="overview">Overview</h2>
+
+ <p>RTFL, which stands for <i>Read The Figurative Logfile</i>, is a
+ both a protocol for structured debug messages, as well as a
+ collection of programs (currently two, <tt>rtfl-objcount</tt>
+ and <tt>rtfl-objview</tt>) displaying these debug messages in a
+ semi-graphical way.</p>
+
+ <p>Programs are prepared to print these special debug messages to
+ standard output (typically controllable via <tt>#ifdef</tt>);
+ for C++, there is already a header file which provides
+ convenient macros. By passing the messages to a viewer program
+ (<tt>rtfl-objcount</tt>, <tt>rtfl-objview</tt>, or, in the
+ future, similar programs), it becomes simpler to determine what
+ the debugged program does.</p>
+
+ <h2 id="synopsis">Synopsis</h2>
+
+ <p>To use RTFL, prepare the program which is to be tested (see
+ <i><a href="#preparing_the_tested_program">Preparing the tested
+ program</a></i>), and run</p>
+
+ <p><tt><i>tested-program</i> | rtfl-objcount</tt><br/>
+ <tt><i>tested-program</i> | rtfl-objview [<i>options</i>]</tt></p>
+
+ <p>or, in the future, other programs, which will become part of
+ RTFL. The prepared, tested program will print special debug
+ messages to standard output, which will then be read
+ by <tt>rtfl-objcount</tt> or <tt>rtfl-objview</tt> via pipe. Of
+ course, using files instead of pipes is also possible.</p>
+
+ <p><tt>Rtfl-objcount</tt> does not yet support options, the ones
+ of <tt>rtfl-objview</tt> are described in the section
+ <i><a href="#rtfl_objview_command_line_options">Command line
+ options of <tt>rtfl-objview</tt></a></i>.</p>
+
+ <p>Details on using <tt>rtfl-objcount</tt>
+ and <tt>rtfl-objview</tt> can be found in the
+ sections <i><a href="#using_rtfl_objcount">Using
+ <tt>rtfl-objcount</tt></a></i>
+ and <i><a href="#using_rtfl_objview">Using
+ <tt>rtfl-objview</tt></a></i>, respectively. Furthermore,
+ there is a useful filter, <tt>rtfl-tee</tt>, which is described
+ in <i><a href="#using_rtfl_tee">Using <tt>rtfl-tee</tt></a></i>.</p>
+
+ <p>The filter <tt>rtfl-findrepeat</tt> has been moved
+ <a href="tipsandtricks.html#attic_rtfl_findrepeat">to the
+ attic</a>.
+
+ <h2 id="preparing_the_tested_program">Preparing the tested program</h2>
+
+ <p>The program to be tested must print special commands to
+ standard output. The file <tt>debug_rtfl.hh</tt>, included in
+ RTFL, provides some convenient macros. Both commands and macros
+ are described in the section
+ <i><a href="#protocol_and_macros">Protocol and macros</a></i>.
+ The macros are active only when the pre-processor variable
+ <tt>DBG_RTFL</tt> is defined. Furthermore, the full paths of the
+ source file names should be included into the commands; this
+ variant prefixes <tt>__FILE__</tt> with <tt>CUR_WORKING_DIR</tt>,
+ which has to be defined.</p>
+
+ <p>It is best to copy <tt>debug_rtfl.hh</tt> in your project, so
+ that there is no direct dependencies to RTFL. This file itself
+ is public domain, so there are no restrictions on <em>using</em>
+ RTFL.</p>
+
+ <p>See the <tt>tests</tt> directory for some examples. (But notice
+ that explicitly passing <tt>-DDBG_RTFL</tt>, as in
+ <tt>tests/Makefile.am</tt> is not “comme il faut”; instead,
+ provide a way to let the user decide.)</p>
+
+ <h3 id="preparing_autoconfmake">Using RTFL with <tt>autoconf</tt>
+ and <tt>automake</tt></h3>
+
+ <p>The file <b><tt>configure.ac</tt></b> of RTFL itself shows how
+ to handle this best by an option <tt>--enable-rtfl</tt>. First,
+ define this option:</p>
+
+ <pre>AC_ARG_ENABLE(rtfl, [--enable-rtfl Build with RTFL messages])</pre>
+
+ <p>Later, a pre-processor variable has to be defined:</p>
+
+ <pre>if test "x$enable_rtfl" = "xyes" ; then
+ CXXFLAGS="$CXXFLAGS -DDBG_RTFL"
+fi</pre>
+
+ <p>Furthermore, we need <tt>CUR_WORKING_DIR</tt>; this is defined
+ later; here we define:</p>
+
+ <pre>BASE_CUR_WORKING_DIR=`pwd`</pre>
+
+ <p>and:</p>
+
+ <pre>AC_SUBST(BASE_CUR_WORKING_DIR)</pre>
+
+ <p>Finally, all instances of <b><tt>Makefile.am</tt></b> have to
+ be prepared. Any file <tt>foo/Makefile.am</tt> should
+ contain:</p>
+
+ <pre>AM_CPPFLAGS = -DCUR_WORKING_DIR='"@BASE_CUR_WORKING_DIR@/foo"'</pre>
+
+ <h2 id="protocol_and_macros">Protocol and macros</h2>
+
+ <p>This section describes both the commands which are printed to
+ standard output, as well as the macros from <tt>debug_rtfl.hh</tt>.</p>
+
+ <p>The whole protocol is divided into modules (currently only
+ one). Each protocol module has a version number consisting of a
+ positive major number and a minor number, which may be 0. The
+ major number changes when the protocol module changes in an
+ incompatible way, while compatible changes affect the minor
+ number.<sup><a id="ref-protocol-compat" href="#note-protocol-compat">[1]</a></sup><sup><a id="ref-protocol-version" href="#note-protocol-version">[2]</a></sup></p>
+
+
+ <p>Generally, the colon (<tt>:</tt>) is used to divide different
+ parts of a command. To use the colon in a literal way, not for
+ division,it can be quoted using the backslash (<tt>\</tt>).
+ Likewise, a literally used backslash must be quoted
+ (<tt>\\</tt>).</p>
+
+ <p>In the detailed descriptions below, commands are shortened. All
+ commands begin with</p>
+
+ <p><tt>[rtfl-<i>module</i>-<i>major version</i>.<i>minor version</i>]<i>file name</i>:<i>line number</i>:<i>process identifier</i>:</tt></p>
+
+ <p>where the prefix <tt>[rtfl-<i>module</i>-<i>major version</i>.<i>minor version</i>]</tt>
+ is used to filter RTFL messages from other messages printed to
+ standard output. <I>Major version</i> and <i>minor version</i>
+ refer to the version of the protocol
+ module.<sup><a id="ref-mix-versions" href="#note-mix-versions">[3]</a></sup>
+ Then follows the file name and the line number, where this
+ message is triggered (this may be used for extensions, like
+ simple navigation through the source code). The last part is a
+ process (or thread) identifier, e.&nbsp;g. as returned
+ by <tt>getpid(2)</tt>. Then follows (not shown here)
+ the <i>command identifier</i>, which defines basically what to
+ do.</p>
+
+ <p>It is common to combine protocol module and command identifier,
+ separated by a hyphen. For example, <tt>obj-create</tt> refers
+ to the command <tt>create</tt> of the module <tt>obj</tt>.
+
+ <p>The following descriptions only give the part following this common
+ prefix.<sup><a id="ref-old-protocol" href="#note-old-protocol">[4]</a></sup></p>
+
+ <h3 id="protocol_general_module">General module</h3>
+
+ <p>The general module is identified by <tt>gen</tt>, the current
+ version is 1.0.</p>
+
+ <p>The general module contains messages intended for use with other
+ modules.</p>
+
+ <p><b>Command:</b> <tt>time:<i>usecs</i></tt><br/>
+ <b>Macro:</b> <tt>DBG_GEN_TIME()</tt><br/></p>
+
+ <p>Define the point in time of the <em>previous</em> command, in micro
+ seconds since a defined, but unspecified, origin. Can be used for simple
+ profiling.</p>
+
+ <h3 id="protocol_objects_module">Objects module</h3>
+
+ <p>The object module is identified by <tt>obj</tt>, the current
+ version is 1.0.</p>
+
+ <p>All commands from this module are related to an object, which
+ is typically the first argument following the command
+ identifier. For C++, the value of <tt>this</tt>, as printed
+ by <tt>printf("%p", this)</tt> is most suitable. The first
+ occurrence of a specific object will "define" the object; a
+ specific command is not needed (but see
+ <a href="#protocol_obj_create"><tt>create</tt></a>).</p>
+
+ <p>For most macros dealing with <tt>this</tt>, there is an
+ additional macro with the suffix <tt>_O</tt>, which expects the
+ object explicitly. Use these in special cases
+ when <tt>this</tt> is not suitable. They are not mentioned here;
+ look into <tt>debug_rtfl.hh</tt> for details.</p>
+
+ <p id="protocol_obj_msg"><b>Command:</b>
+ <tt>msg:<i>object</i>:<i>aspect</i>:<i>priority</i>:<i>msg</i></tt><br/>
+ <b>Macros:</b><br/>
+ <tt>DBG_OBJ_MSG(<i>aspect</i>, <i>priority</i>, <i>msg</i>)</tt><br/>
+ <tt>DBG_OBJ_MSGF(<i>aspect</i>, <i>priority</i>, <i>fmt</i> ...)</tt></p>
+
+ <p>Display a message (<i>msg</i>) related to an object. The
+ macro <tt>DBG_OBJ_MSG</tt> expects a simple text,
+ while <tt>DBG_OBJ_MSGF</tt> can be used to use
+ <tt>printf(3)</tt> like formatting.</p>
+
+ <p><i>Aspects</i> are arbitrary keywords, which can be used to
+ focus on different parts of a program (which may affect the same
+ objects). <i>Priorities</i> are positive numbers defining how
+ important a message should be regarded, with 0 denoting the most
+ important message. Both can be filtered by the viewer programs,
+ see <i><a href="#rtfl_objview_filtering_messages">Filtering
+ messages in <tt>rtfl-objview</tt></a></i>.</p>
+
+ <p>A very simple variant of HTML can be used in the messages, the
+ tags &lt;i&gt; and &lt;b&gt; display italics and bold text,
+ respectively.</p>
+
+ <p id="protocol_obj_mark"><b>Command:</b>
+ <tt>mark:<i>object</i>:<i>aspect</i>:<i>priority</i>:<i>mark</i></tt><br/>
+ <tt>DBG_OBJ_MARK(<i>aspect</i>, <i>priority</i>, <i>mark</i>)</tt><br/>
+ <tt>DBG_OBJ_MARKF(<i>aspect</i>, <i>priority</i>, <i>fmt</i> ...)</tt></p>
+
+ <p>Very similar to
+ <a href="#protocol_obj_msg"><tt>msg</tt></a>, but
+ <i>marks</i> are handled in a privileged way;
+ <a href="#using_rtfl_objview"><tt>rtfl-objview</tt></a> displays
+ them in a seperate menu, so it is simple to select them in a
+ fast way.</p>
+
+ <p>Marks are used to mark special positions within the streams of
+ RTFL commands; although there are macros, they are typically
+ added by filters, which scan RTFL messages for notable
+ occurences. An example is
+ <a href="#scripts"><tt>rtfl-stracktraces</tt></a> with the
+ option <tt>-m</tt>.</p>
+
+ <p id="protocol_obj_start_end"><b>Commands:</b>
+ <tt>msg-start:<i>object</i></tt> and
+ <tt>msg-end:<i>object</i></tt><br/>
+ <b>Macros:</b> <tt>DBG_OBJ_MSG_START()</tt> and
+ <tt>DBG_OBJ_MSG_END()</tt></p>
+
+ <p>Define the start and the end of a section, like a
+ function. Especially useful for recursions, where these commands
+ are nested.</p>
+
+ <p id="protocol_obj_enter_leave"><b>Commands:</b>
+ <tt>enter:<i>object</i>:<i>aspect</i>:<i>priority</i>:<i>funname</i>:<i>args</i></tt>
+ and <tt>leave:<i>object</i></tt>
+ or <tt>leave:<i>object</i>:<i>vals</i></tt><br/>
+ <b>Macros:</b><br/>
+ <tt>DBG_OBJ_ENTER0(<i>aspect</i>, <i>priority</i>, <i>funname</i>)</tt> (for functions/methods with no arguments)<br/>
+ <tt>DBG_OBJ_ENTER(<i>aspect</i>, <i>priority</i>, <i>funname</i>, <i>fmt</i> ...)</tt><br/>
+ <tt>DBG_OBJ_LEAVE()</tt><br/>
+ <tt>DBG_OBJ_LEAVE_VAL(<i>fmt</i> ...)</tt><br/>
+ <tt>DBG_OBJ_LEAVE_VAL0(<i>val</i>)</tt></p>
+
+ <p>States that a function or a method has been entered or left,
+ respectively. <i>Aspect</i> and <i>priority</i> have the same
+ meaning as for <a href="#protocol_obj_msg"><tt>msg</tt></a>.
+ The <tt>printf(3)</tt> like format <i>fmt</i> (macros
+ <tt>DBG_OBJ_ENTER</tt> and <tt>DBG_OBJ_LEAVE_VAL</tt>) must
+ match the following arguments. Any <tt>leave</tt> refers to
+ the last “open” <tt>enter</tt>.
+
+ <p><tt>Leave</tt> supports optional return values, the
+ macro <tt>DBG_OBJ_LEAVE_VAL</tt> should be used in this
+ case. Multiple values are allowed; either with languages which
+ support this, or indirectly by returning values by passing
+ references as arguments. For a literal text value, use
+ <tt>DBG_OBJ_LEAVE_VAL0</tt>.</p>
+
+ <p id="protocol_obj_create"><b>Command:</b>
+ <tt>create:<i>object</i>:<i>class</i></tt><br/>
+ <b>Macro:</b> <tt>DBG_OBJ_CREATE(<i>class</i>)</tt></p>
+
+ <p>Assigns a class to an object. This is not really necessary,
+ but without this command, the class of an object is not known,
+ and for the user of RTFL, difficult to guess.</p>
+
+ <p>When multiple classes are assigned to one object, the last
+ class is valid. This way, calling <tt>DBG_OBJ_CREATE()</tt> in
+ both constructors, the one of the base class (which is called
+ first) and the one of the sub class (which is called second),
+ will work properly, by eventually assigning the class of the sub
+ class.</p>
+
+ <p>For C++, it is recommended to use the fully qualified class
+ name (<tt>path::to::namespace::ClassName</tt>).</p>
+
+ <p id="protocol_obj_delete"><b>Command:</b>
+ <tt>delete:<i>object</i></tt><br/>
+ <b>Macro:</b> <tt>DBG_OBJ_DELETE()</tt></p>
+
+ <p>Deletes an object. Can be called multiple times for one object,
+ when each destructor the class hierarchy prints this
+ command.</p>
+
+ <p>After <tt>delete</tt> has been called as often as
+ <a href="#protocol_obj_create"><tt>create</tt></a> before, the object
+ identifier must be regarded as unassigned, i.&nbsp;e., if it is used
+ again, it is regarded as identifying a new object.</p>
+
+ <p id="protocol_obj_ident"><b>Command:</b>
+ <tt>ident:<i>object1</i>:<i>object2</i></tt><br/>
+ <b>Macro:</b> <tt>DBG_OBJ_BASECLASS(<i>class</i>)</tt></p>
+
+ <p>This command defines two objects as identical, so that all
+ commands for <i>object1</i> and <i>object2</i> will be treated
+ in the same way, in a non-distinguishable way.
+
+ <p>The reasoning behind this command is shown by the macro, and
+ lies in the way how C++ handles multiple inheritance. Assume a
+ class <tt>C</tt> which has two super-classes, <tt>A</tt>
+ and <tt>B</tt>. Typically, when regarding instances
+ of <tt>C</tt> as <tt>A</tt> (cast to <tt>A*</tt>), the value
+ of <tt>this</tt> will not change. However, when regarded
+ as <tt>B</tt>, the value will be different,
+ typically <tt>sizeof(A)</tt> bytes larger.</p>
+
+ <p>For this reason, <tt>DBG_OBJ_CREATE</tt> should, at least for
+ cases of multiple inheritance, be followed
+ by <tt>DBG_OBJ_BASECLASS</tt>:
+
+ <p><tt>DBG_OBJ_CREATE(C);</tt><br/>
+ <tt>DBG_OBJ_BASECLASS(A);</tt><br/>
+ <tt>DBG_OBJ_BASECLASS(B);</tt></p>
+
+ <p><b>Command:</b> <tt>noident</tt></p>
+
+ <p>This command tells the processing program that
+ <a href="#protocol_obj_ident"><tt>obj-ident</tt></a> is never used, which
+ makes it unnecessary to wait until the (non-)identity of object has been
+ clarified.</p>
+
+ <p id="protocol_obj_assoc"><b>Command:</b>
+ <tt>assoc:<i>parent</i>:<i>child</i></tt><br/>
+ <b>Macros:</b><br/>
+ <tt>DBG_OBJ_ASSOC(<i>parent</i>, <i>child</i>)</tt><br/>
+ <tt>DBG_OBJ_ASSOC_PARENT(<i>parent</i>)</tt><br/>
+ <tt>DBG_OBJ_ASSOC_CHILD(<i>child</i>)</tt></p>
+
+ <p>Creates an association between two objects. Objects have some
+ kind of hierarchy, not limited to a tree, not even a DAG, but
+ still not symmetric: <tt>DBG_OBJ_ASSOC(<i>x</i>, <i>y</i>)</tt>
+ is to be distinguished from <tt>DBG_OBJ_ASSOC(<i>y</i>, <i>x</i>)</tt>.
+
+ <p id="protocol_obj_set"><b>Command:</b>
+ <tt>set:<i>object</i>:<i>var</i>:<i>val</i></tt><br/>
+ <b>Macros:</b><br/>
+ <tt>DBG_OBJ_SET_<i>TYPE</i>(<i>var</i>, <i>val</i>)</tt><br/>
+ <tt>DBG_OBJ_ARRSET_<i>TYPE</i>(<i>var</i>, <i>ind</i>, <i>val</i>)</tt><br/>
+ <tt>DBG_OBJ_ARRATTRSET_<i>TYPE</i>(<i>var</i>, <i>ind</i>, <i>attr</i>, <i>val</i>)</tt></p>
+
+ <p>Set or change an attribute of an object. The name can be
+ divided by using the dot (<tt>.</tt>), both for sub structures
+ and for arrays. The different macros are used to format
+ different types:</p>
+
+ <table class="data">
+ <thead>
+ <tr>
+ <th><i>TYPE</i></th>
+ <th>C++ type of <i>val</i></th>
+ <th>Output</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td><tt>NUM</tt></td>
+ <td><tt>int</tt></td>
+ <td><i>val</i></td>
+ </tr>
+ <tr>
+ <td><tt>SYM</tt></td>
+ <td><tt>char*</tt></td>
+ <td><i>val</i></td>
+ </tr>
+ <tr>
+ <td><tt>BOOL</tt></td>
+ <td><tt>bool</tt></td>
+ <td><tt>true</tt> or <tt>false</tt></td>
+ </tr>
+ <tr>
+ <td><tt>STR</tt></td>
+ <td><tt>char*</tt></td>
+ <td><tt>"</tt><i>val</i><tt>"</tt></td>
+ </tr>
+ <tr>
+ <td><tt>PTR</tt></td>
+ <td><tt>void*</tt></td>
+ <td><i>val</i></td>
+ </tr>
+ <tr>
+ <td><tt>COL</tt></td>
+ <td><tt>int</tt> (<tt>0x<i>RRGGBB</i></tt>, interpreted as RGB
+ color)</td>
+ <td><tt>#<i>RRGGBB</i></tt></td>
+ </tr>
+ </tbody>
+ </table>
+
+ <p>Furthermore, variants use the dot notation for array
+ elements. The last variant is used for attributes of structures,
+ which are elements of an array. (For even more complex
+ notations, you can, of course, define new macros.)</p>
+
+ <p id="protocol_obj_class_color"><b>Command:</b>
+ <tt>class-color:<i>class</i>:<i>color</i></tt><sup><a id="ref-obj-color-old" href="#note-obj-color-old">[5]</a></sup><br/>
+ <b>Macro:</b> <tt>DBG_OBJ_CLASS_COLOR(<i>class</i>,
+ <i>color</i>)</tt><sup><a id="ref-obj-class-color-old" href="#note-obj-class-color-old">[6]</a></sup></p>
+
+ <p>Defines a color for groups of class names. <i>Classes</i> takes
+ the form of patterns as defined by <tt>fnmatch(3)</tt>,
+ e.&nbsp;.g. <tt>path::to::namespace::*</tt>; <i>color</i> is
+ given as <tt>#<i>RGB</i></tt> or <tt>#<i>RRGGBB</i></tt>.</p>
+
+ <p>When more than one pattern matches, the most specific is
+ applied.<sup><a id="ref-class-color-specifity" href="#note-class-color-specifity">[7]</a></sup><sup><a id="ref-class-color-specifity-old" href="#note-class-color-specifity-old">[8]</a></sup></p>
+
+ <p id="protocol_obj_object_color"><b>Command:</b>
+ <tt>object-color:<i>object</i>:<i>color</i></tt></p>
+
+ <p>Defines a color for single objects. Like in
+ <a href="#protocol_obj_class_color">class-color</a>, <i>color</i>
+ is given as <tt>#<i>RGB</i></tt> or <tt>#<i>RRGGBB</i></tt>.</p>
+
+ <p>Object colors are preferred over
+ <a href="#protocol_obj_class_color">class colors</a>.
+
+ <h2 id="using_rtfl_objcount">Using <tt>rtfl-objcount</tt></h2>
+
+ <p><tt>Rtfl-objcount</tt> reads RTFL commands from the
+ <a href="#protocol_objects_module">objects module</a> via
+ standard input, simply <em>counts</em> the number of instances
+ of each class, and shows them in a table, which is especially
+ useful to examine memory problems. Use <i>New snapshot</i> from
+ the <i>Snapshot</i> menu to preserve a current state: a column
+ is added, and new changes are only applied to the most right
+ column.
+
+ <p>Like <a href="#using_rtfl_objbase"><tt>rtfl-objbase</tt></a>,
+ <tt>rtfl-objcount</tt> first reads commands from a file <tt>.rtfl</tt> in
+ the current directory, which typically contains commands for the program
+ to be debugged.</p>
+
+ <h2 id="using_rtfl_objview">Using <tt>rtfl-objview</tt></h2>
+
+ <p><tt>Rtfl-objview</tt> reads RTFL commands from the
+ <a href="#protocol_objects_module">objects module</a> via
+ standard input, and displays them as a diagram, with all
+ commands related to one object as a box, and showing the
+ relations between the objects.</p>
+
+ <p>Like <a href="#using_rtfl_objbase"><tt>rtfl-objbase</tt></a>,
+ <tt>rtfl-objview</tt> first reads commands from a file <tt>.rtfl</tt> in
+ the current directory, which typically contains commands for the program
+ to be debugged. (See also <a href="#rtfl_objview_option_b">option
+ <tt>-B</tt></a>.)</p>
+
+ <h3 id="rtfl_objview_basic_usage">Basic usage</h3>
+
+ <div class="image">
+ <img src="object-box-01.png"/>
+ <p class="imagedesc">A typical object box</p>
+ </div>
+
+ <p>All messages related to an object will be displayed in a box
+ showing</p>
+
+ <ul>
+ <li>the object identifier, and when known, the class, at the top;</li>
+ <li>the attributes in the middle part;</li>
+ <li>all messages in the lower part.</li>
+ </ul>
+
+ <p>At different levels, parts of a box can be toggled between
+ visible and invisible (or, instead, replaced by a much smaller
+ part, as e.&nbsp;g. used for attributes). This is indicated in
+ the usual way, by “+” (to show) and “−” (to hide) in the upper
+ left corner.</p>
+
+ <p>For attributes, the structure based on the dot notation
+ (see <a href="#protocol_obj_set"><tt>set</tt></a>) creates a
+ tree whose parts can be toggled between visible and
+ invisible. The complete history of values is displayed, but can
+ be hidden by instead only showing the recent value.</p>
+
+ <p>In the messages part,
+ <a href="#protocol_obj_start_end"><tt>msg-start</tt> and
+ <tt>msg-end</tt></a> change the indentation of the
+ messaged between, and also insert the messages <i>start</i>
+ and <i>end</i>.</p>
+
+ <p>Associations lead to a respective positioning of the object
+ boxes and connections by arrows, as well as a message in the
+ messages part.</p>
+
+ <p>(Many aspects can be configured, see
+ <i><a href="#rtfl_objview_filtering_by_types">Filtering by
+ types</a></i>.)</p>
+
+ <h3 id="rtfl_objview_command_line_options">Command line options</h3>
+
+ <p><tt>Rtfl-objview</tt> supports these options:</p>
+
+ <dl>
+ <dt><tt>-a</tt> <i>aspect</i>, <tt>-A</tt> <i>aspect</i></dt>
+ <dd>Show (<tt>-a</tt>) or hide (<tt>-A</tt>) an aspect
+ (see <i><a href="#rtfl_objview_filtering_messages">Filtering
+ messages</a></i>). This is equivalent to turning on/off an
+ aspect from the <i>Aspects</i> menu. The aspect “*” refers to
+ all, so this option is then equivalent to <i>Show/Hide all</i>
+ aspects. Both options can be used multiple times, and are
+ processed in the order in which they are given; so <tt>-A "*"
+ -a foo</tt> will only show messages with the aspect
+ “foo”.</dd>
+
+ <dt id="rtfl_objview_option_b"><tt>-b</tt>, <tt>-B</tt></dt>
+ <dd>Do (<tt>-b</tt>) or do not (<tt>-B</tt>) apply <tt>.rtfl</tt> and
+ filtering identities (what
+ <a href="#using_rtfl_objbase"><tt>rtfl-objbase</tt></a> does).</dd>
+
+ <dt><tt>-m</tt>, <tt>-M</tt></dt>
+ <dd>Show (<tt>-m</tt>) or hide (<tt>-M</tt>) the messages of all
+ object boxes. Hiding (<tt>-M</tt>) is useful when examining
+ attributes; the messages can be shown by clicking on
+ “+”. (Since showing is the default, the option <tt>-m</tt>
+ only exists for reasons of symmetry.)</dd>
+
+ <dt><tt>-o</tt>, <tt>-O</tt></dt>
+ <dd>Show (<tt>-o</tt>) or hide (<tt>-O</tt>) the contents of all
+ object boxes. Hiding (<tt>-O</tt>) can be useful to get an
+ overview over the relations, without initially caring about
+ the contents; the contents can be shown by clicking on
+ “+”. (Since showing is the default, the option <tt>-o</tt>
+ only exists for reasons of symmetry.)</dd>
+
+ <dt><tt>-p</tt> <i>priority</i></dt>
+ <dd>Set the priority of messages (see
+ <i><a href="#rtfl_objview_filtering_messages">Filtering
+ messages</a></i>). This is equivalent to choosing the
+ respective value in the <i>Priorities</i> menu. The
+ <i>priority</i> “*” refers to <i>No limit</i>.</dd>
+
+ <dt><tt>-t</tt> <i>types</i>, <tt>-T</tt> <i>types</i></dt>
+ <dd>Show (<tt>-t</tt>) or hide (<tt>-T</tt>) certain command types
+ (see <i><a href="#rtfl_objview_filtering_by_types">Filtering by
+ types</a></i>). <i>Types</i> is a sequence of any of these characters: “c”
+ for creations, “i” for indentations, “m” for messages, “a” for marks, “f”
+ for functions, “s” for association, “t” for attributes, and “d” for
+ deletions. This is equivalent to turning on/off the respective types in
+ the <i>Commands</i> menu.</dd>
+
+ <dt><tt>-v</tt> <i>viewer</i></dt>
+ <dd>Set the program called for viewing code (see
+ <i><a href="#rtfl_objview_navigation">Navigation</a></i>).
+ <i>Viewer</i> is a command (passed to <tt>system(3)</tt>),
+ which may contain these variables: “%n” is replaced by the
+ line number, “%p” is replaced by the path of the file. Notice
+ that you should append “&” to avoid blocking. The default is
+ “<tt>xterm -e 'vi +%n %p' &</tt>”; another nice option is
+ “<tt>emacsclient -n %n %p</tt>”. (Also notice that there is
+ currently no quoting done for expanding “%p”, so it is best to
+ keep your file names as simple as possible.)
+ </dl>
+
+ <h3 id="rtfl_objview_navigation">Navigation</h3>
+
+ <p>The commands (from the object module)
+ <a href="#protocol_obj_start_end"><tt>msg-start</tt>,
+ <tt>msg-end</tt></a>,
+ <a href="#protocol_obj_enter_leave"><tt>enter</tt>,
+ <tt>leave</tt></a>,
+ <a href="#protocol_obj_msg"><tt>msg</tt></a>,
+ <a href="#protocol_obj_mark"><tt>mark</tt></a>,
+ <a href="#protocol_obj_set"><tt>set</tt></a>,
+ <a href ="#protocol_obj_assoc"><tt>assoc</tt></a>,
+ <a href="#protocol_obj_create"><tt>create</tt></a>, and
+ <a href="#protocol_obj_delete"><tt>delete</tt></a> are
+ <em>navigable</em>. They are assigned a serial numbers (starting
+ with 0) which is preceding the actual message; furthermore, they
+ can be selected (by clicking on the respective message) and
+ navigated with the commands <i>Previous</i> and <i>Next</i> from
+ the <i>Command</i> menu, or the respective keyboard
+ accelerators. Furthermore, <i>View Code</i> calls an external
+ (and <a href="#rtfl_objview_command_line_options">configurable</a>)
+ viewer or editor to show the line in the code where the
+ selected message was printed.</p>
+
+ <p>Both preceding the serial number on one hand, and selection and
+ highlighting on the other, refers to the respective message in
+ the lower part of the object box (<tt>msg-start</tt>,
+ <tt>msg-end</tt>, <tt>msg</tt>, <tt>mark</tt>,
+ <tt>assoc</tt>, <tt>create</tt>, <tt>delete</tt>), or (<tt>set</tt>)
+ for the message in the attribute value history (click “+” to
+ show), respectively </p>
+
+ <p>Some navigable commands are <i>related</i>; by
+ activating <i>Switch between related</i> from the
+ <i>Commands</i> menu switches between them. Currently
+ <tt>enter</tt> and <tt>leave</tt> are regarded, as well as
+ <tt>msg-start</tt> and <tt>msg-end</tt>.</p>
+
+ <h3 id="rtfl_objview_hiding_commands">Hiding commands</h3>
+
+ <p>Displaying of navigable commands can be limited to any
+ region. Select a command (mouse or navigating) and choose from
+ the <i>Command</i> menu:</p>
+
+ <ul>
+ <li><i>Hide before</i> to hide all commands before selected one
+ (which so becomes the first visible command);</li>
+ <li><i>Hide after</i> likewise to hide all commands after
+ selected one (which becomes the last visible command);</li>
+ <li><i>Hide all</i> to hide all commands but show new commands
+ (equivalent to hiding before the next command to be
+ created);</li>
+ <li><i>Show before</i> to undo <i>Hide before</i>;</li>
+ <li><i>Show after</i> to undo <i>Hide after</i>;</li>
+ <li><i>Show all</i> to show all commands again.</li>
+ </ul>
+
+ <p>Notice that the serial numbers are recalculated, so that the
+ first <em>visible</em> command has the number 0. This is also
+ valid for commands filtered out
+ (<a href="#rtfl_objview_filtering_by_type">by type</a>, or
+ <a href="#rtfl_objview_filtering_messages">by aspect and
+ priority</a>).</p>
+
+ <h3 id="rtfl_objview_stack_traces">Stack traces</h3>
+
+ <p>Based on <a href="#protocol_obj_enter_leave"><tt>enter</tt> and
+ <tt>leave</tt></a>, the command <i>Show stack trace</i> from
+ the <i>Command</i> menu opens a new window showing
+ all <tt>enter</tt> commands leading to the selected command. As
+ long as these are not hidden (which is represented by italics),
+ you can navigate to these by clicking on <i>Jump to</i>.</p>
+
+ <h3 id="rtfl_objview_marks">Marks</h3>
+
+ <p>All <a href="#protocol_obj_mark"><tt>marks</tt></a> are added to
+ the <i>Marks</i> menu, from where they can be directly
+ selected, as long as they are not hidden.</p>
+
+ <h3 id="rtfl_objview_filtering_by_type">Filtering by type</h3>
+
+ <p>All <a href="#rtfl_objview_navigation">navigable commands</a>
+ can be filtered by types, by using entries in the <i>Command</i>
+ menu. In all cases, this refers to the navigable part of the
+ command; other effects (indentation itself, current value of an
+ attribute, arrows for associations) are not affected.</p>
+
+ <ul>
+ <li><i>Creations</i> refers to
+ <a href="#protocol_obj_create"><tt>create</tt></a>,</li>
+ <li><i>Indentations</i> to
+ <a href="#protocol_obj_start_end"><tt>msg-start</tt> and
+ <tt>msg-end</tt></a>,</li>
+ <li><i>Messages</i> to
+ <a href="#protocol_obj_msg"><tt>msg</tt></a>,</li>
+ <li><i>Marks</i> to
+ <a href="#protocol_obj_mark"><tt>mark</tt></a>,</li>
+ <li><i>Functions</i> to
+ <a href="#protocol_obj_enter_leave"><tt>enter</tt> and
+ <tt>leave</tt></a>,</li>
+ <li><i>Associations</i> to
+ <a href="#protocol_obj_assoc"><tt>assoc</tt></a>,</li>
+ <li><i>Attributes</i> to
+ <a href="#protocol_obj_set"><tt>set</tt></a>, and</li>
+ <li><i>Deletions</i> to
+ <a href="#protocol_obj_delete"><tt>delete</tt></a>.</li>
+ </ul>
+
+ <p>By default, indentation messages are turned off, all others are
+ turned on.</p>
+
+ <h3 id="rtfl_objview_filtering_messages">Filtering messages</h3>
+
+ <p><a href="#protocol_obj_msg">Message commands</a> can be
+ filtered by aspects and priorities.</p>
+
+ <p>All aspects defined by the program are visible in
+ the <i>Aspects</i> menu, alphabetically sorted, and can be
+ toggled individually. <i>Show all</i> and <i>Hide all</i> not
+ only affect all aspects already shown in the <i>Aspects</i>
+ menu, but also define the default value for newly added aspects
+ (initially turned on, or initially turned off,
+ respectively).</p>
+
+ <p>Likewise, the <i>Priorities</i> menu contains all priorities,
+ numerically sorted. Choosing one defines the <em>maximal</em>
+ priority number (and so minimal importance); anything above this
+ number (and so less important) is not shown. <i>No limit</i>
+ will not filter any messages by priority.</p>
+
+ <p><i>Note:</i> Both aspects and priorities should be sorted
+ (aspects alphabetically, priorities numerically), which is not
+ yet the case. Especially for priorities, this can become
+ confusing. Also, version 0.0.7 contains a bug that <i>No
+ limit</i> is not selected initially, when it should be. (This is
+ only a visualization problem, filtering works.)</p>
+
+ <h2 id="using_rtfl_objbase">Using <tt>rtfl-objbase</tt></h2>
+
+ <p><tt>Rtfl-objbase</tt> is a filter which reads RTFL commands from the
+ <a href="#protocol_objects_module">objects module</a> and writes
+ them again to standard output, after
+
+ <ul>
+ <li>reading and applying commands from a file <tt>.rtfl</tt> in the
+ current directory (which typically contains commands for the program to
+ be debugged),</li>
+ <li>dealing with <a href="#protocol_obj_ident"><tt>obj-ident</tt></a>:
+ identities declared as identical are replaced by actually
+ identical identites, so a program processing the output may simply
+ ignore <tt>obj-ident</tt>;</li>
+ <li>dealing with <a href="#protocol_obj_delete"><tt>obj-delete</tt></a>
+ and replacing re-used identities of deleted objects by new
+ identities;</li>
+ <li>furthermore, the newest version is used for the output.</li>
+ </ul>
+
+ <p><tt>Rtfl-objbase</tt> is usefully for
+ <a href="#scripts">scripts</a>.</p>
+
+ <h2 id="using_rtfl_tee">Using <tt>rtfl-tee</tt></h2>
+
+ <p><tt>Rtfl-tee</tt> is a simple program which works similar
+ to <tt>tee(1)</tt>: it copies standard input to standard output
+ as well as to a new pipe which is connected to standard input of
+ another process. The exact syntax is:</p>
+
+ <p><tt>rtfl-tee [-b] [--] <i>command</i> [<i>arguments</i> ...]</tt></p>
+
+ <p>All <i>arguments</i> refer to <i>command</i>.</p>
+
+ <p>The option <tt>-b</tt> enables the <i>bypass</i> mode, in which
+ the standard output of <i>command</i> is piped to
+ <tt>rtfl-tee</tt>, which prints both its own standard input and
+ the standard output of <i>command</i> line by line, so that the
+ lines from both streams are preserved. Use this
+ when <i>command</i> is a filter and you want to mix both the
+ original and the filtered stream in a simple way. Notice that no
+ order of the lines is guaranteed.</p>
+
+ <p>Everything after <tt>--</tt> is regarded as <i>command</i>. Use
+ this for commands starting with “-”.</p>
+
+ <p>A typical (simple) example:</p>
+
+ <p><tt><i>tested-program</i> | rtfl-tee rtf-objview -O | rtfl-objcount</tt></p>
+
+ <p>This will start <tt><i>tested-program</i></tt> in a way that
+ the output is passed both
+ to <a href="#using_rtfl_objview"><tt>rtfl-objview</tt></a>
+ (started with option <tt>-O</tt>)
+ and <a href="#using_rtfl_objcount"><tt>rtfl-objcount</tt></a>.
+
+ <p>An example for the bypass mode is given in the section
+ <i><a href="tipsandtricks.html#transformation_of_attributes">Transformation
+ of attributes</a></i> in <i>Tips and tricks</i>.</p>
+
+ <h2 id="scripts">Scripts</h2>
+
+ <p>Part of the RTFL package are some scripts:</p>
+
+ <ul>
+ <li><tt>rtfl-check-objects</tt>, which uses RTFL messages to
+ check for invalid object access,</li>
+ <li><tt>rtfl-filter-out-classes</tt>, which helps filtering out
+ classes not currently interesting (a function which should
+ become part
+ of <a href="#using_rtfl_objview"><tt>rtfl-objview</tt></a>),</li>
+ <li><tt>rtfl-objfilter</tt>, which filters messages by types,
+ aspects and priorities (as
+ <a href="#using_rtfl_objview"><tt>rtfl-objview</tt></a>
+ would do it),</li>
+ <li><tt>rtfl-objtail</tt>, which limits a stream of RTFL
+ messages, and</li>
+ <li><tt>rtfl-stacktraces</tt>, which prints stacktraces leading
+ to a specific method, or helps, as a filter, finding such
+ stack traces.</li>
+ </ul>
+
+ <p>See the comments at the respective scripts for more information
+ on usage.</p>
+
+ <p>The scripts <tt>rtfl-filter-out-classes</tt>,
+ <tt>rtfl-objfilter</tt>, <tt>rtfl-objtail</tt>, and (with
+ options <tt>-e</tt> and <tt>-m</tt>) <tt>rtfl-stacktraces</tt>
+ are used as filters: if e.&nbsp;g. you want to
+ use <tt>rtfl-objview</tt> but ignore all classes of the
+ package <tt>some::package</tt>, run</p>
+
+ <p><tt><i>tested-program</i> | rtfl-filter-out-classes "some::package::*" | rtfl-objview [<i>options</i>]</tt></p>
+
+ <p><strong>N. b.</strong> that since versioning and escaping of
+ protocols, parsing is incorrect:</p>
+
+ <ul>
+ <li>The tag is checked as <tt>/^\[rtfl[^\]]*\]/</tt>, which
+ matches more as it should. (Fixed when using <tt>rtfl-objbase</tt>,
+ see below.)</li>
+ <li>More serious: the object module (prefix in the pre-version
+ protocol) is considered as optional; e.&nbsp;g.
+ <tt>(obj-)?create</tt> is used to cover both versions. This
+ may conflict with another module which also contains a
+ command <tt>create</tt>. (Fixed when using <tt>rtfl-objbase</tt>,
+ see below.)</li>
+ <li>Splitting up the line is done as before, ignoring quoting.
+ This works as long as there are no colons in parts where no
+ colons were allowed before (all parts except the last one).
+ For object identifiers etc., this will be still the case, but
+ for some parts (like method identifiers, which may in some
+ cases be fully qualified as <tt>Class::method</tt>), this may
+ cause problems in the future.</li>
+ <li>In one case quoting is supported: <tt>rtfl-objfilter</tt>
+ unquotes class names, replacing “\:” by “:” (but non “\\” by
+ “\”). This is done regardless of the protocol version, which
+ works as long as there are no backslashes in class names.</li>
+ </ul>
+
+ <p>Furthermore, <a href="#using_rtfl_objbase"><tt>rtfl-objbase</tt></a>
+ should be used by all scripts to achieve a uniform handling of
+ <a href="#protocol_obj_ident"><tt>obj-ident</tt></a> and
+ <a href="#protocol_obj_delete"><tt>obj-delete</tt></a>, as well as
+ to fix some parsing problems. Currently, this has been done for
+ <tt>rtfl-filter-out-classes</tt> and <tt>rtfl-objtail</tt>.</p>
+
+ <h2 id="see_also">See also</h2>
+
+ <ul>
+ <li>RTFL website:
+ <a href="http://home.gna.org/rtfl/">http://home.gna.org/rtfl/</a></li>
+ <li><a href="tipsandtricks.html">Tips and tricks</a></li>
+ </ul>
+
+ <hr/>
+
+ <p><sup><a id="note-protocol-compat" href="#ref-protocol-compat">[1]</a></sup>
+ Some notes and definitions:</p>
+
+ <p><em>Backward compatibility</em> means than a parser can focus
+ on one new version and ignore differences to older
+ versions. Backward compatibility is <em>not</em> generally
+ given, only within a major version; instead, a parser must be
+ aware of older versions. However, changes will be made in a way
+ making this as simple as possible; how this is done will be
+ decided from case to case.</p>
+
+ <p><em>Forward compatibility</em> means than a parser implementing
+ an older version can deal with newer versions. Forward
+ compatibility is given within a major version, by defining the
+ following rules:</p>
+
+ <ul>
+ <li>All lines with an unsupported <em>major</em> version for a
+ given protocol module must be ignored, as well as lines from
+ unsupported protocol modules.</li>
+ <li>For unsupported <em>minor</em> versions,
+ <ul>
+ <li>new commands and</li>
+ <li>unexpected arguments at the end</li>
+ </ul>
+ must be ignored.</li>
+ </ul>
+
+ <p>This implies that there are two ways how a protocol module can
+ be extended in a forward compatible way (leading to a
+ new <em>minor</em> version):</p>
+
+ <ul>
+ <li>adding new commands, and</li>
+ <li>adding new optional arguments (at the end) to existing
+ commands.</li>
+ </ul>
+
+ <p>For simplicity, a parser may simply check the module
+ and <em>major</em> version, and, for supported modules and major
+ versions, ignore new commands and new arguments. New
+ forward-compatible changes can be implemented by and by.</p>
+
+ <p><sup><a id="note-protocol-version" href="#ref-protocol-version">[2]</a></sup>
+ Currently, there is no version for the general part of the
+ protocol, which is independent of the modules. This may change
+ when the general protocol changes.</p>
+
+ <p><sup><a id="note-mix-versions" href="#ref-mix-versions">[3]</a></sup>
+ Since a stream may consist of command lines of different
+ protocol modules, it can consist of command lines with different
+ versions. It is even allowed to mix different versions of the same
+ protocol module.</p>
+
+ <p><sup><a id="note-old-protocol" href="#ref-old-protocol">[4]</a></sup>
+
+ An old version of the protocol, called “pre-version protocol”,
+ is still supported for the objects module, albeit deprecated.
+ Lines start with <tt>[rtfl]</tt>, with neither module name nor
+ version; the module name is put before the command
+ (example: <tt>obj-create</tt>). No escaping mechanism is defined, so
+ that only the last part may contain colons. If not otherwise
+ stated, the specific commands are equivalent</p>
+
+ <p><sup><a id="note-obj-color-old" href="#ref-obj-color-old">[5]</a></sup>
+ In the “pre-version protocol”, <tt>obj-color</tt> is still a
+ (deprecated) synonym of <tt>obj-class-color</tt>.</p>
+
+ <p><sup><a id="note-obj-class-color-old" href="#ref-obj-class-color-old">[6]</a></sup>
+ In the “pre-version protocol”, the order of the arguments
+ is <tt>obj-class-color:<i>color</i>:<i>class</i></tt>,
+ since <i>class</i> typically contains colons, as used for C++
+ namespaces, which are only allowed in the last argument. As for
+ the macro, there are different versions, so you have to be
+ cautious. (As opposed to the protocols, old versions of macros
+ are not supported, since the file <tt>debug_rtfl.hh</tt> is
+ typically copied into the tested program, and so the maintainer
+ of the tested program is responsible.)
+ </p>
+
+ <p><sup><a id="note-class-color-specifity" href="#ref-class-color-specifity">[7]</a></sup>
+ The exact definition of the specifity of a pattern: number of
+ “?” − 100 ∙ number of “*” + 100 ∙ number of other
+ characters.</p>
+
+ <p><sup><a id="note-class-color-specifity-old" href="#ref-class-color-specifity-old">[8]</a></sup>
+ In the “pre-version protocol”, the rule was different (the first
+ pattern was choosen), but for simplicity, newer versions of RTFL
+ treat the “pre-version protocol” like the new version.</p>
+ </body>
+</html>
diff --git a/doc/tipsandtricks.html b/doc/tipsandtricks.html
new file mode 100644
index 0000000..92479f4
--- /dev/null
+++ b/doc/tipsandtricks.html
@@ -0,0 +1,415 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" lang="en">
+ <head>
+ <title>RTFL: Tips and tricks</title>
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
+ </head>
+ <body>
+ <p>[<a href="rtfl.html">Back to RTFL documentation.</a>]</p>
+
+ <h1>Tips and tricks</h1>
+
+ <p>Here, I'll summarize some useful experiences during the work
+ on <a href="http://www.dillo.org/">dillo</a>, for which RTFL was
+ initially written.</p>
+
+ <h2>Preparing the tested program</h2>
+
+ <ul>
+ <li>Do not prepare your program for a specific purpose, but in a
+ way that the RTFL message tell what happens in the
+ program, <em>in an objective way</em>. Ideally, most
+ preparation work is done once and pays off for many different
+ debugging problems.</li>
+ <li>Use different aspects so that filtering (as
+ in <a href="rtfl.html#using_rtfl_objview"><tt>rtfl-objview</tt></a>)
+ helps to focus on your specific problem.
+ </li>
+ </ul>
+
+ <h2><a href="rtfl.html#using_rtfl_objview"><tt>rtfl-objview</tt></a></h2>
+
+ <h3>Work around bugs and flaws</h3>
+
+ <p>Currently, RTFL is not at the top of my priority list, but just
+ a mean to an end (with <a href="http://www.dillo.org/">dillo</a>
+ being the end). This means that I am not too motivated to fix
+ bugs which can be worked around:</p>
+
+ <ul>
+ <li><del>There are several redrawing problems. Calling
+ <tt>xrefresh</tt> or switching between virtual screens should
+ should redraw everything correctly.</del> <i>(Redrawing
+ problems seem fixed now.)</i></li>
+ <li><del>Sometimes, the focused command is not visible. Pressing
+ Ctrl+N and then Ctrl+P should get it back into the viewport
+ again.</del> <i>(Scrolling problems seem fixed now.)</i></li>
+ <li>Use scripts to filter the RTFL messages. Hacking a script in
+ Perl is often much faster as integrating the functionality
+ into <tt>rtfl-objview</tt>. Some <a href="rtfl.html#scripts">useful
+ scripts</a> are already part of RTFL.</li>
+ </ul>
+
+ <h3>General approach</h3>
+
+ <p>Run the tested program and pass the standard output via pipe
+ to <tt>rtfl-objview</tt>. The
+ <a href="rtfl.html#rtfl_objview_command_line_options">command
+ line options</a> <tt>-M</tt> and <tt>-O</tt> are useful to get
+ an overview, <tt>-a</tt> and <tt>-A</tt> will help you to filter
+ out irrelevant messages.</p>
+
+ <p>Then search for an entry point:</p>
+
+ <ul>
+ <li>First of all, get an overview what the objects displayed in
+ the diagram actually represent. In
+ <a href="http://www.dillo.org/">dillo</a>, many objects
+ represent elements of the rendered document, so if an element
+ is rendered wrong, it is important to find the respective
+ object.</li>
+ <li>Depending on the tested program, it may be useful to search
+ for strange patterns of function calls. Simple example:
+ endless recursions are easily recognized by a steadily
+ increasing indentation.</li>
+ <li>An often helpful approach is to examine the attributes:
+ search for the respective object and the respective attribute;
+ a value which looks strange is a good starting point.</li>
+ </ul>
+
+ <p>If you have troubles to find the respective object, try to
+ color it via
+ <a href="rtfl.html#protocol_obj_object_color">obj-object-color</a>,
+ using a filter like
+ this:<sup><a id="ref-pre-version-1" href="#note-pre-version-1">[1]</a></sup></p>
+
+ <pre>sed 's/^\(\[rtfl-obj-1\.[0-9]*\].*\):set:\([^:]*\):words\.0\.text\/widget\/breakSpace:"Abc"$/\0\n\1:object-color:\2:#ff80ff/g'</pre>
+
+ <p>which colors all objects to light purple which have the
+ attribute <tt>words.0.text/widget/breakSpace</tt> set to the
+ value <tt>"Abc"</tt>. This example is again taken
+ from <a href="http://www.dillo.org/">dillo</a>, like the
+ following one, which colors objects in the color in which they
+ are rendered (represented by the attribute
+ <tt>style.background-color</tt>):<sup><a id="ref-pre-version-2" href="#note-pre-version-2">[2]</a></sup></p>
+
+ <pre>sed 's/^\(\[rtfl-obj-1\.[0-9]*\].*\):set:\([^:]*\):style.background-color:\(#[0-9a-f]*\)$/\0\n\1:object-color:\2:\3/g'</pre>
+
+ <p>As soon as you have selected a specific command, try to
+ determine the commands before:</p>
+
+ <ul>
+ <li>Navigate through the
+ <a href="rtfl.html#rtfl_objview_navigation">previous
+ commands</a>.</li>
+ <li>Or use the <a href="rtfl.html#rtfl_objview_stack_traces">stack
+ traces</a> function to get an overview.</li>
+ <li>One more tip: Use <i>Switch between related</i> for skipping
+ the messages within one method call if you think that the
+ problem is found outside of this method.</li>
+ </ul>
+
+ <h3>Advanced problems</h3>
+
+ <h4>CPU hogging</h4>
+
+ <p>In this case, the number of messages (infinite) will be too
+ large for <tt>rtfl-objview</tt>. Simply use <tt>head(1)</tt> to
+ reduce them; for the number of lines, some trial and error is
+ necessary.</p>
+
+ <h4>Too many messages</h4>
+
+ <p>In some cases, it is useful to concentrate on what happens at
+ the end, especially if the program aborts. In this cases, the
+ script <a href="rtfl.html#scripts"><tt>rtfl-objtail</tt></a>
+ helps to filter messages, but preserve relevant object
+ creations, associations etc. at the beginning. Again, some tests
+ are needed for the number of lines.</p>
+
+ <h4 id="transformation_of_attributes">Transformation of attributes</h4>
+
+ <p>While <a href="rtfl.html#protocol_obj_set"><tt>obj-set</tt></a>
+ is used to set actual attributes, it is sometimes useful to
+ accumulate values. Instead of adding code to the tested program,
+ filters can do this and add respective pseudo attributes. The
+ following snippet counts for each object (and each process) the
+ number of calls of the method
+ <tt>draw</tt>:<sup><a id="ref-pre-version-3" href="#note-pre-version-3">[3]</a></sup></p>
+
+ <pre><a href="rtfl.html#using_rtfl_tee">rtfl-tee</a> -b sh -c \
+ "grep '^\[rtfl\].*:obj-enter:[^:]*:[^:]*:[^:]*:draw:' | \
+ sed 's/^.*:\([^:]*\):obj-enter:\([^:]*\):.*$/\1:\2/g' | \
+ sort | uniq -c | \
+ sed 's/^ *\([^ ]*\) *\([^:]*\):\(.*\)$/[rtfl]:0:\2:obj-set:\3:&lt;b&gt;called &lt;i&gt;draw&lt;\/i&gt;&lt;\/b&gt;:\1/g'"</pre>
+
+ <h3>More tips</h3>
+
+ <ul>
+ <li>Use the script
+ <a href="rtfl.html#scripts"><tt>rtfl-filter-out-classes</tt></a>
+ to reduce again messages. (I plan to integrate this
+ into <tt>rtfl-objview</tt>.)</li>
+ <li>The serial numbers preceding commands are often useful to
+ determine which command follows the other. E.&nbsp;g., by
+ comparing the numbers of attributes, it can be determined
+ which attribute possibly depends on another.</li>
+ </ul>
+
+ <h2>Attic</h2>
+
+ <p>Some ideas proved to be less practical that they looked at
+ first. Here, you will find several smaller projects which I have
+ abandoned, but you might find them useful as an inspiration.</p>
+
+ <h3><a href="http://www.dillo.org/">Dillo</a>: HTML
+ attribute <tt>rtfl-id</tt></h3>
+
+ <p>To make finding the exact relation between HTML elements of a
+ tested page and the <a href="http://www.dillo.org/">dillo</a>
+ widgets simpler, one could define a new HTML
+ element, <tt>rtfl-id</tt>, which is recognized by the HTML
+ parser of dillo and eventually passed to the respective
+ widget. (Printing a
+ <a href="rtfl.html#protocol_obj_set"><tt>obj-set</tt></a>
+ message is sufficient, storage in the widget is not necessary.)
+ This is demonstrated by the patch
+ <a href="#appendix_dillo_rtfl_id_diff"><tt>dillo-rtfl-id.diff</tt></a>
+ below.</p>
+
+ <p>Furthermore, a simple Perl
+ script, <a href="#appendix_add_rtfl_id_pl"><tt>add-rtfl-id.pl</tt></a>,
+ adds unique <tt>rtfl-id</tt>'s to a given HTML page (standard
+ input to standard output).</p>
+
+ <p>(<em>Warning:</em> both are incomplete.)</p>
+
+ <h3 id="attic_rtfl_findrepeat"><tt>rtfl-findrepeat</tt></h3>
+
+ <p><tt>Rtfl-findrepeat</tt> is a program which searches in a
+ stream for identical sequences. See comment at the beginning
+ of <tt>common/rtfl_findrepeat.cc</tt> for more details on
+ usage. Suitable arguments should be achieved by trial and
+ error.</p>
+
+ <p>The idea behind this: if a program hogs the CPU, it is most
+ likely that it does similar things again and again, by
+ error. With a bit of luck, this will result in identical RTFL
+ messages, which <tt>rtfl-findrepeat</tt> helps to
+ find. With <a href="http://www.dillo.org/">dillo</a>, however,
+ this rendered not as really usable, so I have moved
+ <tt>rtfl-findrepeat</tt> to here.</p>
+
+ <h2>Appendix</h2>
+
+ <h3 id="appendix_dillo_rtfl_id_diff"><tt>dillo-rtfl-id.diff</tt></h3>
+
+ <pre>diff -r 45a8d0d4b0d6 dw/widget.hh
+--- a/dw/widget.hh Mon Sep 08 23:20:10 2014 +0200
++++ b/dw/widget.hh Tue Sep 09 13:09:08 2014 +0200
+@@ -502,6 +502,11 @@
+ */
+ virtual Iterator *iterator (Content::Type mask, bool atEnd) = 0;
+ virtual void removeChild (Widget *child);
++
++ void setRtflId (const char *rtflId) {
++ if (rtflId) DBG_OBJ_SET_STR ("rtfl-id", rtflId);
++ else DBG_OBJ_SET_SYM ("rtfl-id", "none");
++ }
+ };
+
+ void splitHeightPreserveAscent (int height, int *ascent, int *descent);
+diff -r 45a8d0d4b0d6 src/doctree.hh
+--- a/src/doctree.hh Mon Sep 08 23:20:10 2014 +0200
++++ b/src/doctree.hh Tue Sep 09 13:09:08 2014 +0200
+@@ -13,6 +13,7 @@
+ lout::misc::SimpleVector&lt;char*&gt; *klass;
+ const char *pseudo;
+ const char *id;
++ const char *rtflId;
+
+ DoctreeNode () {
+ parent = NULL;
+@@ -21,11 +22,13 @@
+ klass = NULL;
+ pseudo = NULL;
+ id = NULL;
++ rtflId = NULL;
+ element = 0;
+ };
+
+ ~DoctreeNode () {
+ dFree ((void*) id);
++ dFree ((void*) rtflId);
+ while (lastChild) {
+ DoctreeNode *n = lastChild;
+ lastChild = lastChild-&gt;sibling;
+diff -r 45a8d0d4b0d6 src/form.cc
+--- a/src/form.cc Mon Sep 08 23:20:10 2014 +0200
++++ b/src/form.cc Tue Sep 09 13:09:08 2014 +0200
+@@ -938,6 +938,7 @@
+ * but it caused 100% CPU usage.
+ */
+ page = new Textblock (false);
++ page-&gt;setRtflId (html-&gt;rtflId ());
+ page-&gt;setStyle (html-&gt;backgroundStyle ());
+
+ ResourceFactory *factory = HT2LT(html)-&gt;getResourceFactory();
+diff -r 45a8d0d4b0d6 src/html.cc
+--- a/src/html.cc Mon Sep 08 23:20:10 2014 +0200
++++ b/src/html.cc Tue Sep 09 13:09:08 2014 +0200
+@@ -362,6 +362,7 @@
+ static void Html_add_textblock(DilloHtml *html, bool addBreaks, int breakSpace)
+ {
+ Textblock *textblock = new Textblock (prefs.limit_text_width);
++ textblock-&gt;setRtflId (html-&gt;rtflId ());
+
+ if (addBreaks)
+ HT2TB(html)-&gt;addParbreak (breakSpace, html-&gt;wordStyle ());
+@@ -2186,6 +2187,7 @@
+ }
+
+ dw::Image *dw = new dw::Image(alt_ptr);
++ dw-&gt;setRtflId (html-&gt;rtflId ());
+ image =
+ a_Image_new(html-&gt;dw-&gt;getLayout(), (void*)(dw::core::ImgRenderer*)dw, 0);
+
+@@ -3038,6 +3040,7 @@
+ HT2TB(html)-&gt;addParbreak (5, html-&gt;wordStyle ());
+
+ hruler = new Ruler();
++ hruler-&gt;setRtflId (html-&gt;rtflId ());
+ hruler-&gt;setStyle (html-&gt;style ());
+ HT2TB(html)-&gt;addWidget (hruler, html-&gt;style ());
+ HT2TB(html)-&gt;addParbreak (5, html-&gt;wordStyle ());
+@@ -3783,6 +3786,10 @@
+ const char *attrbuf;
+ char lang[3];
+
++ if (tagsize &gt;= 13 &amp;&amp; /* length of "&lt;t rtfl-id=i&gt;" */
++ (attrbuf = a_Html_get_attr(html, tag, tagsize, "rtfl-id")))
++ html-&gt;styleEngine-&gt;setRtflId(attrbuf);
++
+ if (tagsize &gt;= 8 &amp;&amp; /* length of "&lt;t id=i&gt;" */
+ (attrbuf = a_Html_get_attr(html, tag, tagsize, "id"))) {
+ /* According to the SGML declaration of HTML 4, all NAME values
+@@ -3882,6 +3889,7 @@
+ HT2TB(html)-&gt;addParbreak (0, wordStyle);
+
+ list_item = new ListItem ((ListItem*)*ref_list_item,prefs.limit_text_width);
++ list_item-&gt;setRtflId (html-&gt;rtflId ());
+ HT2TB(html)-&gt;addWidget (list_item, style);
+ HT2TB(html)-&gt;addParbreak (0, wordStyle);
+ *ref_list_item = list_item;
+diff -r 45a8d0d4b0d6 src/html_common.hh
+--- a/src/html_common.hh Mon Sep 08 23:20:10 2014 +0200
++++ b/src/html_common.hh Tue Sep 09 13:09:08 2014 +0200
+@@ -234,6 +234,7 @@
+
+ inline void restyle () { styleEngine-&gt;restyle (bw); }
+
++ inline const char *rtflId () { return styleEngine-&gt;rtflId (); }
+ };
+
+ /*
+diff -r 45a8d0d4b0d6 src/styleengine.cc
+--- a/src/styleengine.cc Mon Sep 08 23:20:10 2014 +0200
++++ b/src/styleengine.cc Tue Sep 09 13:09:08 2014 +0200
+@@ -160,6 +160,12 @@
+ dn-&gt;id = dStrdup (id);
+ }
+
++void StyleEngine::setRtflId (const char *rtflId) {
++ DoctreeNode *dn = doctree-&gt;top ();
++ assert (dn-&gt;rtflId == NULL);
++ dn-&gt;rtflId = dStrdup (rtflId);
++}
++
+ /**
+ * \brief split a string at sep chars and return a SimpleVector of strings
+ */
+diff -r 45a8d0d4b0d6 src/styleengine.hh
+--- a/src/styleengine.hh Mon Sep 08 23:20:10 2014 +0200
++++ b/src/styleengine.hh Tue Sep 09 13:09:08 2014 +0200
+@@ -77,6 +77,7 @@
+ void startElement (int tag, BrowserWindow *bw);
+ void startElement (const char *tagname, BrowserWindow *bw);
+ void setId (const char *id);
++ void setRtflId (const char *rtflId);
+ const char * getId () { return doctree-&gt;top ()-&gt;id; };
+ void setClass (const char *klass);
+ void setStyle (const char *style);
+@@ -122,6 +123,10 @@
+ else
+ return wordStyle0 (bw);
+ };
++
++ inline const char *rtflId () {
++ return stack-&gt;getRef(stack-&gt;size()-1)-&gt;doctreeNode-&gt;rtflId;
++ };
+ };
+
+ #endif
+diff -r 45a8d0d4b0d6 src/table.cc
+--- a/src/table.cc Mon Sep 08 23:20:10 2014 +0200
++++ b/src/table.cc Tue Sep 09 13:09:08 2014 +0200
+@@ -158,6 +158,7 @@
+
+ HT2TB(html)-&gt;addParbreak (0, html-&gt;wordStyle ());
+ table = new dw::Table(prefs.limit_text_width);
++ table-&gt;setRtflId (html-&gt;rtflId ());
+ HT2TB(html)-&gt;addWidget (table, html-&gt;style ());
+ HT2TB(html)-&gt;addParbreak (0, html-&gt;wordStyle ());
+
+@@ -451,6 +452,7 @@
+ prefs.limit_text_width);
+ else
+ col_tb = new SimpleTableCell (prefs.limit_text_width);
++ col_tb-&gt;setRtflId (html-&gt;rtflId ());
+
+ if (html-&gt;style()-&gt;borderCollapse == BORDER_MODEL_COLLAPSE){
+ Html_set_collapsing_border_model(html, col_tb);</pre>
+
+ <h3 id="appendix_add_rtfl_id_pl"><tt>add-rtfl-id.pl</tt></h3>
+
+ <pre>#!/usr/bin/perl
+
+$id = 0;
+
+while(&lt;STDIN&gt;) {
+ chomp;
+ $first = 1;
+ foreach $part (split /w&lt;/) {
+ if ($first) {
+ print $part;
+ } else {
+ if ($part =~ /^\//) {
+ print "&lt;$part";
+ } else {
+ $part =~ s/([^ &gt;]*)/\1 rtfl-id="$id"/;
+ $id++;
+ print "&lt;$part";
+ }
+ }
+ $first = 0;
+ }
+ print "\n";
+}</pre>
+
+ <hr/>
+
+ <p><sup><a id="note-pre-version-1" href="#ref-pre-version-1">[1]</a></sup>
+ Use this for the pre-version protocol:</p>
+ <pre>sed 's/^\(\[rtfl\].*\):obj-set:\([^:]*\):words\.0\.text\/widget\/breakSpace:"Abc"$/\0\n\1:obj-object-color:\2:#ff80ff/g'</pre>
+
+ <p><sup><a id="note-pre-version-2" href="#ref-pre-version-2">[2]</a></sup>
+ Again, for the pre-version protocol:</p>
+ <pre>sed 's/^\(\[rtfl\].*\):obj-set:\([^:]*\):style.background-color:\(#[0-9a-f]*\)$/\0\n\1:obj-object-color:\2:\3/g'</pre>
+
+ <p><sup><a id="note-pre-version-3" href="#ref-pre-version-3">[3]</a></sup>
+ This works only with the pre-version protocol. Should be
+ adjusted eventually.</p>
+
+ </body>
+</html>
diff --git a/dw/Makefile.am b/dw/Makefile.am
new file mode 100644
index 0000000..471a309
--- /dev/null
+++ b/dw/Makefile.am
@@ -0,0 +1,57 @@
+AM_CPPFLAGS = \
+ -I$(top_srcdir) \
+ -DDILLO_LIBDIR='"$(pkglibdir)/"' \
+ -DCUR_WORKING_DIR='"@BASE_CUR_WORKING_DIR@/dw"'
+
+noinst_LIBRARIES = \
+ libDw-core.a \
+ libDw-fltk.a
+
+libDw_core_a_SOURCES = \
+ core.hh \
+ events.hh \
+ findtext.cc \
+ findtext.hh \
+ imgbuf.hh \
+ imgrenderer.hh \
+ imgrenderer.cc \
+ iterator.cc \
+ iterator.hh \
+ layout.cc \
+ layout.hh \
+ platform.hh \
+ selection.hh \
+ selection.cc \
+ style.cc \
+ style.hh \
+ types.cc \
+ types.hh \
+ ui.cc \
+ ui.hh \
+ view.hh \
+ widget.cc \
+ widget.hh
+
+# "fltkcomplexbutton.cc", "fltkcomplexbutton.hh", "fltkflatview.cc",
+# and "fltkflatview.hh" have been removed from libDw-fltk.a.
+
+libDw_fltk_a_SOURCES = \
+ fltkcore.hh \
+ fltkimgbuf.cc \
+ fltkimgbuf.hh \
+ fltkmisc.cc \
+ fltkmisc.hh \
+ fltkplatform.cc \
+ fltkplatform.hh \
+ fltkpreview.hh \
+ fltkpreview.cc \
+ fltkui.cc \
+ fltkui.hh \
+ fltkviewbase.cc \
+ fltkviewbase.hh \
+ fltkviewport.cc \
+ fltkviewport.hh
+
+libDw_fltk_a_CXXFLAGS = @LIBFLTK_CXXFLAGS@
+
+EXTRA_DIST = preview.xbm
diff --git a/dw/core.hh b/dw/core.hh
new file mode 100644
index 0000000..022574b
--- /dev/null
+++ b/dw/core.hh
@@ -0,0 +1,60 @@
+#ifndef __DW_CORE_HH__
+#define __DW_CORE_HH__
+
+#define __INCLUDED_FROM_DW_CORE_HH__
+
+/**
+ * \brief Dw is in this namespace, or sub namespaces of this one.
+ *
+ * The core can be found in dw::core, widgets are defined directly here.
+ *
+ * \sa \ref dw-overview
+ */
+namespace dw {
+
+/**
+ * \brief The core of Dw is defined in this namespace.
+ *
+ * \sa \ref dw-overview
+ */
+namespace core {
+
+typedef unsigned char byte;
+
+class Layout;
+class View;
+class Widget;
+class Iterator;
+
+// Nothing yet to free.
+inline void freeall () { }
+
+namespace ui {
+
+class ResourceFactory;
+
+} // namespace ui
+} // namespace core
+} // namespace dw
+
+#include "../lout/object.hh"
+#include "../lout/container.hh"
+#include "../lout/signal.hh"
+
+#include "types.hh"
+#include "events.hh"
+#include "imgbuf.hh"
+#include "imgrenderer.hh"
+#include "style.hh"
+#include "view.hh"
+#include "platform.hh"
+#include "iterator.hh"
+#include "findtext.hh"
+#include "selection.hh"
+#include "layout.hh"
+#include "widget.hh"
+#include "ui.hh"
+
+#undef __INCLUDED_FROM_DW_CORE_HH__
+
+#endif // __DW_CORE_HH__
diff --git a/dw/events.hh b/dw/events.hh
new file mode 100644
index 0000000..5309186
--- /dev/null
+++ b/dw/events.hh
@@ -0,0 +1,83 @@
+#ifndef __DW_EVENTS_HH__
+#define __DW_EVENTS_HH__
+
+#ifndef __INCLUDED_FROM_DW_CORE_HH__
+# error Do not include this file directly, use "core.hh" instead.
+#endif
+
+namespace dw {
+namespace core {
+
+/**
+ * \brief Platform independent representation.
+ */
+enum ButtonState
+{
+ /* We won't use more than these ones. */
+ SHIFT_MASK = 1 << 0,
+ CONTROL_MASK = 1 << 1,
+ META_MASK = 1 << 2,
+ BUTTON1_MASK = 1 << 3,
+ BUTTON2_MASK = 1 << 4,
+ BUTTON3_MASK = 1 << 5
+};
+
+/**
+ * \brief Base class for all events.
+ *
+ * The dw::core::Event hierarchy describes events in a platform independent
+ * way.
+ */
+class Event: public lout::object::Object
+{
+public:
+};
+
+/**
+ * \brief Base class for all mouse events.
+ */
+class MouseEvent: public Event
+{
+public:
+ ButtonState state;
+};
+
+/**
+ * \brief Base class for all mouse events related to a specific position.
+ */
+class MousePositionEvent: public MouseEvent
+{
+public:
+ int xCanvas, yCanvas, xWidget, yWidget;
+};
+
+/**
+ * \brief Represents a button press or release event.
+ */
+class EventButton: public MousePositionEvent
+{
+public:
+ int numPressed; /* 1 for simple click, 2 for double click, etc. */
+ int button;
+};
+
+/**
+ * \brief Represents a mouse motion event.
+ */
+class EventMotion: public MousePositionEvent
+{
+};
+
+/**
+ * \brief Represents a enter or leave notify event.
+ */
+class EventCrossing: public MouseEvent
+{
+public:
+ Widget *lastWidget, *currentWidget;
+};
+
+} // namespace core
+} // namespace dw
+
+#endif // __DW_EVENTS_HH__
diff --git a/dw/findtext.cc b/dw/findtext.cc
new file mode 100644
index 0000000..57c83c5
--- /dev/null
+++ b/dw/findtext.cc
@@ -0,0 +1,307 @@
+/*
+ * RTFL (originally part of dillo)
+ *
+ * Copyright 2005-2007 Sebastian Geerken <sgeerken@dillo.org>
+ *
+ * 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; with the following exception:
+ *
+ * The copyright holders of RTFL give you permission to link this file
+ * statically or dynamically against all versions of the graphviz
+ * library, which are published by AT&T Corp. under one of the following
+ * licenses:
+ *
+ * - Common Public License version 1.0 as published by International
+ * Business Machines Corporation (IBM), or
+ * - Eclipse Public License version 1.0 as published by the Eclipse
+ * Foundation.
+ *
+ * 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/>.
+ */
+
+
+
+#include "core.hh"
+#include "../lout/debug.hh"
+#include "../lout/msg.h"
+
+namespace dw {
+namespace core {
+
+FindtextState::FindtextState ()
+{
+ DBG_OBJ_CREATE ("dw::core::FindtextState");
+
+ key = NULL;
+ nexttab = NULL;
+ widget = NULL;
+ iterator = NULL;
+ hlIterator = NULL;
+}
+
+FindtextState::~FindtextState ()
+{
+ if (key)
+ free(key);
+ if (nexttab)
+ delete[] nexttab;
+ if (iterator)
+ delete iterator;
+ if (hlIterator)
+ delete hlIterator;
+
+ DBG_OBJ_DELETE ();
+}
+
+void FindtextState::setWidget (Widget *widget)
+{
+ this->widget = widget;
+
+ // A widget change will restart the search.
+ if (key)
+ free(key);
+ key = NULL;
+ if (nexttab)
+ delete[] nexttab;
+ nexttab = NULL;
+
+ if (iterator)
+ delete iterator;
+ iterator = NULL;
+ if (hlIterator)
+ delete hlIterator;
+ hlIterator = NULL;
+}
+
+FindtextState::Result FindtextState::search (const char *key, bool caseSens,
+ bool backwards)
+{
+ if (!widget || *key == 0) // empty keys are not found
+ return NOT_FOUND;
+
+ bool wasHighlighted = unhighlight ();
+ bool newKey;
+
+ // If the key (or the widget) changes (including case sensitivity),
+ // the search is started from the beginning.
+ if (this->key == NULL || this->caseSens != caseSens ||
+ strcmp (this->key, key) != 0) {
+ newKey = true;
+ if (this->key)
+ free(this->key);
+ this->key = strdup (key);
+ this->caseSens = caseSens;
+
+ if (nexttab)
+ delete[] nexttab;
+ nexttab = createNexttab (key, caseSens, backwards);
+
+ if (iterator)
+ delete iterator;
+ iterator = new CharIterator (widget, true);
+
+ if (backwards) {
+ /* Go to end */
+ while (iterator->next () ) ;
+ iterator->prev (); //We don't want to be at CharIterator::END.
+ } else {
+ iterator->next ();
+ }
+ } else
+ newKey = false;
+
+ bool firstTrial = !wasHighlighted || newKey;
+
+ if (search0 (backwards, firstTrial)) {
+ // Highlighting is done with a clone.
+ hlIterator = iterator->cloneCharIterator ();
+ for (int i = 0; key[i]; i++)
+ hlIterator->next ();
+ CharIterator::highlight (iterator, hlIterator, HIGHLIGHT_FINDTEXT);
+ CharIterator::scrollTo (iterator, hlIterator,
+ HPOS_INTO_VIEW, VPOS_CENTER);
+
+ // The search will continue from the word after the found position.
+ iterator->next ();
+ return SUCCESS;
+ } else {
+ if (firstTrial) {
+ return NOT_FOUND;
+ } else {
+ // Nothing found anymore, reset the state for the next trial.
+ delete iterator;
+ iterator = new CharIterator (widget, true);
+ if (backwards) {
+ /* Go to end */
+ while (iterator->next ()) ;
+ iterator->prev (); //We don't want to be at CharIterator::END.
+ } else {
+ iterator->next ();
+ }
+ // We expect a success.
+ Result result2 = search (key, caseSens, backwards);
+ assert (result2 == SUCCESS);
+ return RESTART;
+ }
+ }
+}
+
+/**
+ * \brief This method is called when the user closes the "find text" dialog.
+ */
+void FindtextState::resetSearch ()
+{
+ unhighlight ();
+
+ if (key)
+ free(key);
+ key = NULL;
+}
+
+/*
+ * Return a new string: with the reverse of the original.
+ */
+const char* FindtextState::rev(const char *str)
+{
+ if (!str)
+ return NULL;
+
+ int len = strlen(str);
+ char *nstr = new char[len+1];
+ for (int i = 0; i < len; ++i)
+ nstr[i] = str[len-1 -i];
+ nstr[len] = 0;
+
+ return nstr;
+}
+
+int *FindtextState::createNexttab (const char *needle, bool caseSens,
+ bool backwards)
+{
+ const char* key;
+
+ key = (backwards) ? rev(needle) : needle;
+ int i = 0;
+ int j = -1;
+ int l = strlen (key);
+ int *nexttab = new int[l + 1]; // + 1 is necessary for l == 1 case
+ nexttab[0] = -1;
+
+ do {
+ if (j == -1 || charsEqual (key[i], key[j], caseSens)) {
+ i++;
+ j++;
+ nexttab[i] = j;
+ //_MSG ("nexttab[%d] = %d\n", i, j);
+ } else
+ j = nexttab[j];
+ } while (i < l - 1);
+
+ if (backwards)
+ delete [] key;
+
+ return nexttab;
+}
+
+/**
+ * \brief Unhighlight, and return whether a region was highlighted.
+ */
+bool FindtextState::unhighlight ()
+{
+ if (hlIterator) {
+ CharIterator *start = hlIterator->cloneCharIterator ();
+ for (int i = 0; key[i]; i++)
+ start->prev ();
+
+ CharIterator::unhighlight (start, hlIterator, HIGHLIGHT_FINDTEXT);
+ delete start;
+ delete hlIterator;
+ hlIterator = NULL;
+
+ return true;
+ } else
+ return false;
+}
+
+bool FindtextState::search0 (bool backwards, bool firstTrial)
+{
+ if (iterator->getChar () == CharIterator::END)
+ return false;
+
+ bool ret = false;
+ const char* searchKey = (backwards) ? rev(key) : key;
+ int j = 0;
+ bool nextit = true;
+ int l = strlen (key);
+
+ if (backwards && !firstTrial) {
+ _MSG("Having to do.");
+ /* Position correctly */
+ /* In order to achieve good results (i.e: find a word that ends within
+ * the previously searched word's limit) we have to position the
+ * iterator in the semilast character of the previously searched word.
+ *
+ * Since we know that if a word was found before it was exactly the
+ * same word as the one we are searching for now, we can apply the
+ * following expression:
+ *
+ * Where l=length of the key and n=num of positions to move:
+ *
+ * n = l - 3
+ *
+ * If n is negative, we have to move backwards, but if it is
+ * positive, we have to move forward. So, when l>=4, we start moving
+ * the iterator forward. */
+
+ if (l==1) {
+ iterator->prev();
+ iterator->prev();
+ } else if (l==2) {
+ iterator->prev();
+ } else if (l>=4) {
+ for (int i=0; i<l-3; i++) {
+ iterator->next();
+ }
+ }
+
+ } else if (backwards && l==1) {
+ /* Particular case where we can't find the last character */
+ iterator->next();
+ }
+
+ do {
+ if (j == -1 || charsEqual (iterator->getChar(),searchKey[j],caseSens)) {
+ j++;
+ nextit = backwards ? iterator->prev () : iterator->next ();
+ } else
+ j = nexttab[j];
+ } while (nextit && j < l);
+
+ if (j >= l) {
+ if (backwards) {
+ //This is the location of the key
+ iterator->next();
+ } else {
+ // Go back to where the key was found.
+ for (int i = 0; i < l; i++)
+ iterator->prev ();
+ }
+ ret = true;
+ }
+
+ if (backwards)
+ delete [] searchKey;
+
+ return ret;
+}
+
+} // namespace core
+} // namespace dw
diff --git a/dw/findtext.hh b/dw/findtext.hh
new file mode 100644
index 0000000..c680348
--- /dev/null
+++ b/dw/findtext.hh
@@ -0,0 +1,84 @@
+#ifndef __DW_FINDTEXT_STATE_H__
+#define __DW_FINDTEXT_STATE_H__
+
+#ifndef __INCLUDED_FROM_DW_CORE_HH__
+# error Do not include this file directly, use "core.hh" instead.
+#endif
+
+#include <ctype.h>
+
+namespace dw {
+namespace core {
+
+class FindtextState
+{
+public:
+ typedef enum {
+ /** \brief The next occurrence of the pattern has been found. */
+ SUCCESS,
+
+ /**
+ * \brief There is no further occurrence of the pattern, instead, the
+ * first occurrence has been selected.
+ */
+ RESTART,
+
+ /** \brief The patten does not at all occur in the text. */
+ NOT_FOUND
+ } Result;
+
+private:
+ /**
+ * \brief The key used for the last search.
+ *
+ * If dw::core::Findtext::search is called with the same key, the search
+ * is continued, otherwise it is restarted.
+ */
+ char *key;
+
+ /** \brief Whether the last search was case sensitive. */
+ bool caseSens;
+
+ /** \brief The table used for KMP search. */
+ int *nexttab;
+
+ /** \brief The top of the widget tree, in which the search is done.
+ *
+ * From this, the iterator will be constructed. Set by
+ * dw::core::Findtext::widget
+ */
+ Widget *widget;
+
+ /** \brief The position from where the next search will start. */
+ CharIterator *iterator;
+
+ /**
+ * \brief The position from where the characters are highlighted.
+ *
+ * NULL, when no text is highlighted.
+ */
+ CharIterator *hlIterator;
+
+ static const char* rev(const char* _str); /* reverse a C string */
+
+ static int *createNexttab (const char *needle,bool caseSens,bool backwards);
+ bool unhighlight ();
+ bool search0 (bool backwards, bool firstTrial);
+
+ inline static bool charsEqual (char c1, char c2, bool caseSens)
+ { return caseSens ? c1 == c2 : tolower (c1) == tolower (c2) ||
+ (isspace (c1) && isspace (c2)); }
+
+public:
+ FindtextState ();
+ ~FindtextState ();
+
+ void setWidget (Widget *widget);
+ Result search (const char *key, bool caseSens, bool backwards);
+ void resetSearch ();
+};
+
+} // namespace core
+} // namespace dw
+
+#endif // __DW_FINDTEXT_STATE_H__
diff --git a/dw/fltkcore.hh b/dw/fltkcore.hh
new file mode 100644
index 0000000..5ac619b
--- /dev/null
+++ b/dw/fltkcore.hh
@@ -0,0 +1,36 @@
+#ifndef __DW_FLTK_CORE_HH__
+#define __DW_FLTK_CORE_HH__
+
+#define __INCLUDED_FROM_DW_FLTK_CORE_HH__
+
+namespace dw {
+namespace fltk {
+namespace ui {
+
+class FltkResource;
+
+} // namespace ui
+} // namespace fltk
+} // namespace dw
+
+#include <FL/Fl_Widget.H>
+
+#include "core.hh"
+#include "fltkimgbuf.hh"
+#include "fltkplatform.hh"
+#include "fltkui.hh"
+
+namespace dw {
+namespace fltk {
+
+inline void freeall ()
+{
+ FltkImgbuf::freeall ();
+}
+
+} // namespace fltk
+} // namespace dw
+
+#undef __INCLUDED_FROM_DW_FLTK_CORE_HH__
+
+#endif // __DW_FLTK_CORE_HH__
diff --git a/dw/fltkimgbuf.cc b/dw/fltkimgbuf.cc
new file mode 100644
index 0000000..6621dc5
--- /dev/null
+++ b/dw/fltkimgbuf.cc
@@ -0,0 +1,584 @@
+/*
+ * RTFL (originally part of dillo)
+ *
+ * Copyright 2005-2007, 2012-2013 Sebastian Geerken <sgeerken@dillo.org>
+ *
+ * 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; with the following exception:
+ *
+ * The copyright holders of RTFL give you permission to link this file
+ * statically or dynamically against all versions of the graphviz
+ * library, which are published by AT&T Corp. under one of the following
+ * licenses:
+ *
+ * - Common Public License version 1.0 as published by International
+ * Business Machines Corporation (IBM), or
+ * - Eclipse Public License version 1.0 as published by the Eclipse
+ * Foundation.
+ *
+ * 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/>.
+ */
+
+#include "fltkcore.hh"
+#include "../lout/msg.h"
+#include "../lout/misc.hh"
+
+#include <FL/fl_draw.H>
+#include <math.h>
+
+#define IMAGE_MAX_AREA (6000 * 6000)
+
+#define MAX_WIDTH 0x8000
+#define MAX_HEIGHT 0x8000
+
+namespace dw {
+namespace fltk {
+
+using namespace lout::container::typed;
+
+const enum ScaleMode { SIMPLE, BEAUTIFUL, BEAUTIFUL_GAMMA }
+ scaleMode = BEAUTIFUL_GAMMA;
+
+Vector <FltkImgbuf::GammaCorrectionTable> *FltkImgbuf::gammaCorrectionTables
+ = new Vector <FltkImgbuf::GammaCorrectionTable> (true, 2);
+
+uchar *FltkImgbuf::findGammaCorrectionTable (double gamma)
+{
+ // Since the number of possible keys is low, a linear search is
+ // sufficiently fast.
+
+ for (int i = 0; i < gammaCorrectionTables->size(); i++) {
+ GammaCorrectionTable *gct = gammaCorrectionTables->get(i);
+ if (gct->gamma == gamma)
+ return gct->map;
+ }
+
+ _MSG("Creating new table for gamma = %g\n", gamma);
+
+ GammaCorrectionTable *gct = new GammaCorrectionTable();
+ gct->gamma = gamma;
+
+ for (int i = 0; i < 256; i++)
+ gct->map[i] = 255 * pow((double)i / 255, gamma);
+
+ gammaCorrectionTables->put (gct);
+ return gct->map;
+}
+
+bool FltkImgbuf::excessiveImageDimensions (int width, int height)
+{
+ return width <= 0 || height <= 0 ||
+ width > IMAGE_MAX_AREA / height;
+}
+
+void FltkImgbuf::freeall ()
+{
+ _MSG("Deleting gammaCorrectionTables\n");
+ delete gammaCorrectionTables;
+ gammaCorrectionTables = NULL;
+}
+
+FltkImgbuf::FltkImgbuf (Type type, int width, int height, double gamma)
+{
+ DBG_OBJ_CREATE ("dw::fltk::FltkImgbuf");
+
+ _MSG ("FltkImgbuf::FltkImgbuf: new root %p\n", this);
+ init (type, width, height, gamma, NULL);
+}
+
+FltkImgbuf::FltkImgbuf (Type type, int width, int height, double gamma,
+ FltkImgbuf *root)
+{
+ DBG_OBJ_CREATE ("dw::fltk::FltkImgbuf");
+
+ _MSG ("FltkImgbuf::FltkImgbuf: new scaled %p, root is %p\n", this, root);
+ init (type, width, height, gamma, root);
+}
+
+void FltkImgbuf::init (Type type, int width, int height, double gamma,
+ FltkImgbuf *root)
+{
+ if (excessiveImageDimensions (width, height)) {
+ // Excessive image sizes which would cause crashes due to too
+ // big allocations for the image buffer (for root buffers, when
+ // the image was specially prepared). In this case we use a 1 x
+ // 1 size.
+ MSG("FltkImgbuf::init: suspicious image size request %d x %d\n",
+ width, height);
+ init (type, 1, 1, gamma, root);
+ } else if (width > MAX_WIDTH) {
+ // Too large dimensions cause dangerous overflow errors, so we
+ // limit dimensions to harmless values.
+ //
+ // Example: 65535 * 65536 / 65536 (see scaling below) results in
+ // the negative value -1.
+
+ MSG("FltkImgbuf::init: cannot handle large width %d\n", width);
+ init (type, MAX_WIDTH, height, gamma, root);
+ } else if (height > MAX_HEIGHT) {
+ MSG("FltkImgbuf::init: cannot handle large height %d\n", height);
+ init (type, width, MAX_HEIGHT, gamma, root);
+ } else if (gamma <= 0) {
+ MSG("FltkImgbuf::init: non-positive gamma %g\n", gamma);
+ init (type, width, height, 1, root);
+ } else {
+ this->root = root;
+ this->type = type;
+ this->width = width;
+ this->height = height;
+ this->gamma = gamma;
+
+ DBG_OBJ_SET_NUM ("width", width);
+ DBG_OBJ_SET_NUM ("height", height);
+
+ // TODO: Maybe this is only for root buffers
+ switch (type) {
+ case RGBA: bpp = 4; break;
+ case RGB: bpp = 3; break;
+ default: bpp = 1; break;
+ }
+ _MSG("FltkImgbuf::init this=%p width=%d height=%d bpp=%d gamma=%g\n",
+ this, width, height, bpp, gamma);
+ rawdata = new uchar[bpp * width * height];
+ // Set light-gray as interim background color.
+ memset(rawdata, 222, width*height*bpp);
+
+ refCount = 1;
+ deleteOnUnref = true;
+ copiedRows = new lout::misc::BitSet (height);
+
+ // The list is only used for root buffers.
+ if (isRoot())
+ scaledBuffers = new lout::container::typed::List <FltkImgbuf> (true);
+ else
+ scaledBuffers = NULL;
+
+ if (!isRoot()) {
+ // Scaling
+ for (int row = 0; row < root->height; row++) {
+ if (root->copiedRows->get (row))
+ scaleRow (row, root->rawdata + row*root->width*root->bpp);
+ }
+ }
+ }
+}
+
+FltkImgbuf::~FltkImgbuf ()
+{
+ _MSG ("FltkImgbuf::~FltkImgbuf\n");
+
+ if (!isRoot())
+ root->detachScaledBuf (this);
+
+ delete[] rawdata;
+ delete copiedRows;
+
+ if (scaledBuffers)
+ delete scaledBuffers;
+
+ DBG_OBJ_DELETE ();
+}
+
+/**
+ * \brief This method is called for the root buffer, when a scaled buffer
+ * removed.
+ */
+void FltkImgbuf::detachScaledBuf (FltkImgbuf *scaledBuf)
+{
+ scaledBuffers->detachRef (scaledBuf);
+
+ _MSG("FltkImgbuf[root %p]: scaled buffer %p is detached, %d left\n",
+ this, scaledBuf, scaledBuffers->size ());
+
+ if (refCount == 0 && scaledBuffers->isEmpty () && deleteOnUnref)
+ // If the root buffer is not used anymore, but this is the last scaled
+ // buffer.
+ // See also: FltkImgbuf::unref().
+ delete this;
+}
+
+void FltkImgbuf::setCMap (int *colors, int num_colors)
+{
+}
+
+inline void FltkImgbuf::scaleRow (int row, const core::byte *data)
+{
+ if (row < root->height) {
+ if (scaleMode == SIMPLE)
+ scaleRowSimple (row, data);
+ else
+ scaleRowBeautiful (row, data);
+ }
+}
+
+inline void FltkImgbuf::scaleRowSimple (int row, const core::byte *data)
+{
+ int sr1 = scaledY (row);
+ int sr2 = scaledY (row + 1);
+
+ for (int sr = sr1; sr < sr2; sr++) {
+ // Avoid multiple passes.
+ if (copiedRows->get(sr)) continue;
+
+ copiedRows->set (sr, true);
+ if (sr == sr1) {
+ for (int px = 0; px < root->width; px++) {
+ int px1 = px * width / root->width;
+ int px2 = (px+1) * width / root->width;
+ for (int sp = px1; sp < px2; sp++) {
+ memcpy(rawdata + (sr*width + sp)*bpp, data + px*bpp, bpp);
+ }
+ }
+ } else {
+ memcpy(rawdata + sr*width*bpp, rawdata + sr1*width*bpp, width*bpp);
+ }
+ }
+}
+
+inline void FltkImgbuf::scaleRowBeautiful (int row, const core::byte *data)
+{
+ int sr1 = scaledY (row);
+ int sr2 = scaledY (row + 1);
+ bool allRootRows = false;
+
+ // Don't rescale rows!
+ if (copiedRows->get(sr1)) return;
+
+ if (height > root->height) {
+ scaleBuffer (data, root->width, 1,
+ rawdata + sr1 * width * bpp, width, sr2 - sr1,
+ bpp, gamma);
+ // Mark scaled rows done
+ for (int sr = sr1; sr < sr2 || sr == sr1; sr++)
+ copiedRows->set (sr, true);
+ } else {
+ assert (sr1 == sr2 || sr1 + 1 == sr2);
+ int row1 = backscaledY(sr1), row2 = backscaledY(sr1 + 1);
+
+ // Check all the necessary root lines already arrived,
+ // a larger area than a single row may be accessed here.
+ for (int r=row1; (allRootRows=root->copiedRows->get(r)) && ++r < row2; );
+ if (allRootRows) {
+ scaleBuffer (root->rawdata + row1 * root->width * bpp,
+ root->width, row2 - row1,
+ rawdata + sr1 * width * bpp, width, 1,
+ bpp, gamma);
+ // Mark scaled row done
+ copiedRows->set (sr1, true);
+ }
+ }
+}
+
+/**
+ * General method to scale an image buffer. Used to scale single lines
+ * in scaleRowBeautiful.
+ *
+ * The algorithm is rather simple. If the scaled buffer is smaller
+ * (both width and height) than the original buffer, each pixel in the
+ * scaled buffer is assigned a rectangle of pixels in the original
+ * buffer; the resulting pixel value (red, green, blue) is simply the
+ * average of all pixel values. This is pretty fast and leads to
+ * rather good results.
+ *
+ * Nothing special (like interpolation) is done when scaling up.
+ *
+ * If scaleMode is set to BEAUTIFUL_GAMMA, gamma correction is
+ * considered, see <http://www.4p8.com/eric.brasseur/gamma.html>.
+ *
+ * TODO Could be optimized as in scaleRowSimple: when the destination
+ * image is larger, calculate only one row/column, and copy it to the
+ * other rows/columns.
+ */
+inline void FltkImgbuf::scaleBuffer (const core::byte *src, int srcWidth,
+ int srcHeight, core::byte *dest,
+ int destWidth, int destHeight, int bpp,
+ double gamma)
+{
+ uchar *gammaMap1, *gammaMap2;
+
+ if (scaleMode == BEAUTIFUL_GAMMA) {
+ gammaMap1 = findGammaCorrectionTable (gamma);
+ gammaMap2 = findGammaCorrectionTable (1 / gamma);
+ }
+
+ for(int x = 0; x < destWidth; x++)
+ for(int y = 0; y < destHeight; y++) {
+ int xo1 = x * srcWidth / destWidth;
+ int xo2 = lout::misc::max ((x + 1) * srcWidth / destWidth, xo1 + 1);
+ int yo1 = y * srcHeight / destHeight;
+ int yo2 = lout::misc::max ((y + 1) * srcHeight / destHeight, yo1 + 1);
+ int n = (xo2 - xo1) * (yo2 - yo1);
+
+ int v[bpp];
+ for(int i = 0; i < bpp; i++)
+ v[i] = 0;
+
+ for(int xo = xo1; xo < xo2; xo++)
+ for(int yo = yo1; yo < yo2; yo++) {
+ const core::byte *ps = src + bpp * (yo * srcWidth + xo);
+ for(int i = 0; i < bpp; i++)
+ v[i] +=
+ (scaleMode == BEAUTIFUL_GAMMA ? gammaMap2[ps[i]] : ps[i]);
+ }
+
+ core::byte *pd = dest + bpp * (y * destWidth + x);
+ for(int i = 0; i < bpp; i++)
+ pd[i] =
+ scaleMode == BEAUTIFUL_GAMMA ? gammaMap1[v[i] / n] : v[i] / n;
+ }
+}
+
+void FltkImgbuf::copyRow (int row, const core::byte *data)
+{
+ assert (isRoot());
+
+ if (row < height) {
+ // Flag the row done and copy its data.
+ copiedRows->set (row, true);
+ memcpy(rawdata + row * width * bpp, data, width * bpp);
+
+ // Update all the scaled buffers of this root image.
+ for (Iterator <FltkImgbuf> it = scaledBuffers->iterator();
+ it.hasNext(); ) {
+ FltkImgbuf *sb = it.getNext ();
+ sb->scaleRow (row, data);
+ }
+ }
+}
+
+void FltkImgbuf::newScan ()
+{
+ if (isRoot()) {
+ for (Iterator<FltkImgbuf> it = scaledBuffers->iterator(); it.hasNext();){
+ FltkImgbuf *sb = it.getNext ();
+ sb->copiedRows->clear();
+ }
+ }
+}
+
+core::Imgbuf* FltkImgbuf::getScaledBuf (int width, int height)
+{
+ if (!isRoot())
+ return root->getScaledBuf (width, height);
+
+ if (width > MAX_WIDTH) {
+ // Similar to init.
+ MSG("FltkImgbuf::getScaledBuf: cannot handle large width %d\n", width);
+ return getScaledBuf (MAX_WIDTH, height);
+ }
+ if (height > MAX_HEIGHT) {
+ MSG("FltkImgbuf::getScaledBuf: cannot handle large height %d\n", height);
+ return getScaledBuf (width, MAX_HEIGHT);
+ }
+
+ if (width == this->width && height == this->height) {
+ ref ();
+ return this;
+ }
+
+ for (Iterator <FltkImgbuf> it = scaledBuffers->iterator(); it.hasNext(); ) {
+ FltkImgbuf *sb = it.getNext ();
+ if (sb->width == width && sb->height == height) {
+ sb->ref ();
+ return sb;
+ }
+ }
+
+ // Check for excessive image sizes which would cause crashes due to
+ // too big allocations for the image buffer. In this case we return
+ // a pointer to the unscaled image buffer.
+ if (excessiveImageDimensions (width, height)) {
+ MSG("FltkImgbuf::getScaledBuf: suspicious image size request %d x %d\n",
+ width, height);
+ ref ();
+ return this;
+ }
+
+ // This size is not yet used, so a new buffer has to be created.
+ FltkImgbuf *sb = new FltkImgbuf (type, width, height, gamma, this);
+ scaledBuffers->append (sb);
+ DBG_OBJ_ASSOC_CHILD (sb);
+
+ return sb;
+}
+
+void FltkImgbuf::getRowArea (int row, dw::core::Rectangle *area)
+{
+ // TODO: May have to be adjusted.
+
+ if (isRoot()) {
+ /* root buffer */
+ area->x = 0;
+ area->y = row;
+ area->width = width;
+ area->height = 1;
+ _MSG("::getRowArea: area x=%d y=%d width=%d height=%d\n",
+ area->x, area->y, area->width, area->height);
+ } else {
+ if (row > root->height)
+ area->x = area->y = area->width = area->height = 0;
+ else {
+ // scaled buffer
+ int sr1 = scaledY (row);
+ int sr2 = scaledY (row + 1);
+
+ area->x = 0;
+ area->y = sr1;
+ area->width = width;
+ area->height = sr2 - sr1;
+ _MSG("::getRowArea: area x=%d y=%d width=%d height=%d\n",
+ area->x, area->y, area->width, area->height);
+ }
+ }
+}
+
+int FltkImgbuf::getRootWidth ()
+{
+ return root ? root->width : width;
+}
+
+int FltkImgbuf::getRootHeight ()
+{
+ return root ? root->height : height;
+}
+
+core::Imgbuf *FltkImgbuf::createSimilarBuf (int width, int height)
+{
+ return new FltkImgbuf (type, width, height, gamma);
+}
+
+void FltkImgbuf::copyTo (Imgbuf *dest, int xDestRoot, int yDestRoot,
+ int xSrc, int ySrc, int widthSrc, int heightSrc)
+{
+ FltkImgbuf *fDest = (FltkImgbuf*)dest;
+ assert (bpp == fDest->bpp);
+
+ int xSrc2 = lout::misc::min (xSrc + widthSrc, fDest->width - xDestRoot);
+ int ySrc2 = lout::misc::min (ySrc + heightSrc, fDest->height - yDestRoot);
+
+ //printf ("copying from (%d, %d), %d x %d to (%d, %d) (root) => "
+ // "xSrc2 = %d, ySrc2 = %d\n",
+ // xSrc, ySrc, widthSrc, heightSrc, xDestRoot, yDestRoot,
+ // xSrc2, ySrc2);
+
+ for (int x = xSrc; x < xSrc2; x++)
+ for (int y = ySrc; y < ySrc2; y++) {
+ int iSrc = x + width * y;
+ int iDest = xDestRoot + x + fDest->width * (yDestRoot + y);
+
+ //printf (" (%d, %d): %d -> %d\n", x, y, iSrc, iDest);
+
+ for (int b = 0; b < bpp; b++)
+ fDest->rawdata[bpp * iDest + b] = rawdata[bpp * iSrc + b];
+ }
+}
+
+void FltkImgbuf::ref ()
+{
+ refCount++;
+
+ //if (root)
+ // MSG("FltkImgbuf[scaled %p, root is %p]: ref() => %d\n",
+ // this, root, refCount);
+ //else
+ // MSG("FltkImgbuf[root %p]: ref() => %d\n", this, refCount);
+}
+
+void FltkImgbuf::unref ()
+{
+ //if (root)
+ // MSG("FltkImgbuf[scaled %p, root is %p]: ref() => %d\n",
+ // this, root, refCount - 1);
+ //else
+ // MSG("FltkImgbuf[root %p]: ref() => %d\n", this, refCount - 1);
+
+ if (--refCount == 0) {
+ if (isRoot ()) {
+ // Root buffer, it must be ensured that no scaled buffers are left.
+ // See also FltkImgbuf::detachScaledBuf().
+ if (scaledBuffers->isEmpty () && deleteOnUnref) {
+ delete this;
+ } else {
+ _MSG("FltkImgbuf[root %p]: not deleted. numScaled=%d\n",
+ this, scaledBuffers->size ());
+ }
+ } else
+ // Scaled buffer buffer, simply delete it.
+ delete this;
+ }
+}
+
+bool FltkImgbuf::lastReference ()
+{
+ return refCount == 1 &&
+ (scaledBuffers == NULL || scaledBuffers->isEmpty ());
+}
+
+void FltkImgbuf::setDeleteOnUnref (bool deleteOnUnref)
+{
+ assert (isRoot ());
+ this->deleteOnUnref = deleteOnUnref;
+}
+
+bool FltkImgbuf::isReferred ()
+{
+ return refCount != 0 ||
+ (scaledBuffers != NULL && !scaledBuffers->isEmpty ());
+}
+
+
+int FltkImgbuf::scaledY(int ySrc)
+{
+ // TODO: May have to be adjusted.
+ assert (root != NULL);
+ return ySrc * height / root->height;
+}
+
+int FltkImgbuf::backscaledY(int yScaled)
+{
+ assert (root != NULL);
+
+ // Notice that rounding errors because of integers do not play a
+ // role. This method cannot be the exact inverse of scaledY, since
+ // scaleY is not bijective, and so not invertible. Instead, both
+ // values always return the smallest value.
+ return yScaled * root->height / height;
+}
+
+void FltkImgbuf::draw (Fl_Widget *target, int xRoot, int yRoot,
+ int x, int y, int width, int height)
+{
+ // TODO: Clarify the question, whether "target" is the current widget
+ // (and so has not to be passed at all).
+
+ _MSG("::draw: xRoot=%d x=%d yRoot=%d y=%d width=%d height=%d\n"
+ " this->width=%d this->height=%d\n",
+ xRoot, x, yRoot, y, width, height, this->width, this->height);
+
+ if (x > this->width || y > this->height) {
+ return;
+ }
+
+ if (x + width > this->width) {
+ width = this->width - x;
+ }
+
+ if (y + height > this->height) {
+ height = this->height - y;
+ }
+
+ fl_draw_image(rawdata+bpp*(y*this->width + x), xRoot + x, yRoot + y, width,
+ height, bpp, this->width * bpp);
+
+}
+
+} // namespace fltk
+} // namespace dw
diff --git a/dw/fltkimgbuf.hh b/dw/fltkimgbuf.hh
new file mode 100644
index 0000000..0b8b554
--- /dev/null
+++ b/dw/fltkimgbuf.hh
@@ -0,0 +1,93 @@
+#ifndef __DW_FLTKIMGBUF_HH__
+#define __DW_FLTKIMGBUF_HH__
+
+#ifndef __INCLUDED_FROM_DW_FLTK_CORE_HH__
+# error Do not include this file directly, use "fltkcore.hh" instead.
+#endif
+
+namespace dw {
+namespace fltk {
+
+class FltkImgbuf: public core::Imgbuf
+{
+private:
+ class GammaCorrectionTable: public lout::object::Object
+ {
+ public:
+ double gamma;
+ uchar map[256];
+ };
+
+ FltkImgbuf *root;
+ int refCount;
+ bool deleteOnUnref;
+ lout::container::typed::List <FltkImgbuf> *scaledBuffers;
+
+ int width, height;
+ Type type;
+ double gamma;
+
+//{
+ int bpp;
+ uchar *rawdata;
+//}
+
+ // This is just for testing drawing, it has to be replaced by
+ // the image buffer.
+ lout::misc::BitSet *copiedRows;
+
+ static lout::container::typed::Vector <GammaCorrectionTable>
+ *gammaCorrectionTables;
+
+ static uchar *findGammaCorrectionTable (double gamma);
+ static bool excessiveImageDimensions (int width, int height);
+
+ FltkImgbuf (Type type, int width, int height, double gamma,
+ FltkImgbuf *root);
+ void init (Type type, int width, int height, double gamma, FltkImgbuf *root);
+ int scaledY(int ySrc);
+ int backscaledY(int yScaled);
+ int isRoot() { return (root == NULL); }
+ void detachScaledBuf (FltkImgbuf *scaledBuf);
+
+protected:
+ ~FltkImgbuf ();
+
+public:
+ FltkImgbuf (Type type, int width, int height, double gamma);
+
+ static void freeall ();
+
+ void setCMap (int *colors, int num_colors);
+ inline void scaleRow (int row, const core::byte *data);
+ inline void scaleRowSimple (int row, const core::byte *data);
+ inline void scaleRowBeautiful (int row, const core::byte *data);
+ inline static void scaleBuffer (const core::byte *src, int srcWidth,
+ int srcHeight, core::byte *dest,
+ int destWidth, int destHeight, int bpp,
+ double gamma);
+
+ void newScan ();
+ void copyRow (int row, const core::byte *data);
+ core::Imgbuf* getScaledBuf (int width, int height);
+ void getRowArea (int row, dw::core::Rectangle *area);
+ int getRootWidth ();
+ int getRootHeight ();
+ core::Imgbuf *createSimilarBuf (int width, int height);
+ void copyTo (Imgbuf *dest, int xDestRoot, int yDestRoot,
+ int xSrc, int ySrc, int widthSrc, int heightSrc);
+ void ref ();
+ void unref ();
+
+ bool lastReference ();
+ void setDeleteOnUnref (bool deleteOnUnref);
+ bool isReferred ();
+
+ void draw (Fl_Widget *target, int xRoot, int yRoot,
+ int x, int y, int width, int height);
+};
+
+} // namespace fltk
+} // namespace dw
+
+#endif // __DW_FLTK_IMGBUF_HH__
diff --git a/dw/fltkmisc.cc b/dw/fltkmisc.cc
new file mode 100644
index 0000000..45230ad
--- /dev/null
+++ b/dw/fltkmisc.cc
@@ -0,0 +1,58 @@
+/*
+ * RTFL (originally part of dillo)
+ *
+ * Copyright 2005-2007 Sebastian Geerken <sgeerken@dillo.org>
+ *
+ * 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; with the following exception:
+ *
+ * The copyright holders of RTFL give you permission to link this file
+ * statically or dynamically against all versions of the graphviz
+ * library, which are published by AT&T Corp. under one of the following
+ * licenses:
+ *
+ * - Common Public License version 1.0 as published by International
+ * Business Machines Corporation (IBM), or
+ * - Eclipse Public License version 1.0 as published by the Eclipse
+ * Foundation.
+ *
+ * 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/>.
+ */
+
+
+#include "../lout/msg.h"
+#include "fltkmisc.hh"
+
+#include <FL/Fl.H>
+#include <stdio.h>
+
+namespace dw {
+namespace fltk {
+namespace misc {
+
+int screenWidth ()
+{
+ return Fl::w ();
+}
+
+int screenHeight ()
+{
+ return Fl::h ();
+}
+
+void warpPointer (int x, int y)
+{
+ MSG_ERR("no warpPointer mechanism available.\n");
+}
+
+} // namespace misc
+} // namespace fltk
+} // namespace dw
diff --git a/dw/fltkmisc.hh b/dw/fltkmisc.hh
new file mode 100644
index 0000000..fc00431
--- /dev/null
+++ b/dw/fltkmisc.hh
@@ -0,0 +1,22 @@
+#ifndef __FLTKMISC_HH__
+#define __FLTKMISC_HH__
+
+namespace dw {
+namespace fltk {
+
+/**
+ * \brief Miscellaneous FLTK stuff.
+ */
+namespace misc {
+
+int screenWidth ();
+int screenHeight ();
+
+void warpPointer (int x, int y);
+
+} // namespace misc
+} // namespace fltk
+} // namespace dw
+
+
+#endif // __FLTKMISC_HH__
diff --git a/dw/fltkplatform.cc b/dw/fltkplatform.cc
new file mode 100644
index 0000000..a244765
--- /dev/null
+++ b/dw/fltkplatform.cc
@@ -0,0 +1,739 @@
+/*
+ * RTFL (originally part of dillo)
+ *
+ * Copyright 2005-2007 Sebastian Geerken <sgeerken@dillo.org>
+ *
+ * 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; with the following exception:
+ *
+ * The copyright holders of RTFL give you permission to link this file
+ * statically or dynamically against all versions of the graphviz
+ * library, which are published by AT&T Corp. under one of the following
+ * licenses:
+ *
+ * - Common Public License version 1.0 as published by International
+ * Business Machines Corporation (IBM), or
+ * - Eclipse Public License version 1.0 as published by the Eclipse
+ * Foundation.
+ *
+ * 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/>.
+ */
+
+#include <stdio.h>
+
+#include "../lout/msg.h"
+#include "../lout/debug.hh"
+#include "fltkcore.hh"
+
+#include <FL/fl_draw.H>
+#include <FL/Fl_Box.H>
+#include <FL/Fl_Tooltip.H>
+#include <FL/Fl_Menu_Window.H>
+#include <FL/Fl_Paged_Device.H>
+
+/*
+ * Local data
+ */
+
+/* Tooltips */
+static Fl_Menu_Window *tt_window = NULL;
+static int in_tooltip = 0, req_tooltip = 0;
+
+namespace dw {
+namespace fltk {
+
+using namespace lout;
+
+/**
+ * \todo Distinction between italics and oblique would be nice.
+ */
+
+container::typed::HashTable <dw::core::style::FontAttrs,
+ FltkFont> *FltkFont::fontsTable =
+ new container::typed::HashTable <dw::core::style::FontAttrs,
+ FltkFont> (false, false);
+
+container::typed::HashTable <lout::object::ConstString,
+ FltkFont::FontFamily> *FltkFont::systemFonts =
+ NULL;
+
+FltkFont::FontFamily FltkFont::standardFontFamily (FL_HELVETICA,
+ FL_HELVETICA_BOLD,
+ FL_HELVETICA_ITALIC,
+ FL_HELVETICA_BOLD_ITALIC);
+
+FltkFont::FontFamily::FontFamily (Fl_Font fontNormal, Fl_Font fontBold,
+ Fl_Font fontItalic, Fl_Font fontBoldItalic)
+{
+ font[0] = fontNormal;
+ font[1] = fontBold;
+ font[2] = fontItalic;
+ font[3] = fontBoldItalic;
+}
+
+void FltkFont::FontFamily::set (Fl_Font f, int attrs)
+{
+ int idx = 0;
+ if (attrs & FL_BOLD)
+ idx += 1;
+ if (attrs & FL_ITALIC)
+ idx += 2;
+ font[idx] = f;
+}
+
+Fl_Font FltkFont::FontFamily::get (int attrs)
+{
+ int idx = 0;
+ if (attrs & FL_BOLD)
+ idx += 1;
+ if (attrs & FL_ITALIC)
+ idx += 2;
+
+ // should the desired font style not exist, we
+ // return the normal font of the fontFamily
+ return font[idx] >= 0 ? font[idx] : font[0];
+}
+
+
+
+FltkFont::FltkFont (core::style::FontAttrs *attrs)
+{
+ if (!systemFonts)
+ initSystemFonts ();
+
+ copyAttrs (attrs);
+
+ int fa = 0;
+ if (weight >= 500)
+ fa |= FL_BOLD;
+ if (style != core::style::FONT_STYLE_NORMAL)
+ fa |= FL_ITALIC;
+
+ object::ConstString nameString (name);
+ FontFamily *family = systemFonts->get (&nameString);
+ if (!family)
+ family = &standardFontFamily;
+
+ font = family->get (fa);
+
+ fl_font(font, size);
+ // WORKAROUND: A bug with fl_width(uint_t) on non-xft X was present in
+ // 1.3.0 (STR #2688).
+ spaceWidth = misc::max(0, (int)fl_width(" ") + letterSpacing);
+ int xx, xy, xw, xh;
+ fl_text_extents("x", xx, xy, xw, xh);
+ xHeight = xh;
+ descent = fl_descent();
+ ascent = fl_height() - descent;
+}
+
+FltkFont::~FltkFont ()
+{
+ fontsTable->remove (this);
+}
+
+static void strstrip(char *big, const char *little)
+{
+ if (strlen(big) >= strlen(little) &&
+ misc::AsciiStrcasecmp(big + strlen(big) - strlen(little), little) == 0)
+ *(big + strlen(big) - strlen(little)) = '\0';
+}
+
+void FltkFont::initSystemFonts ()
+{
+ systemFonts = new container::typed::HashTable
+ <lout::object::ConstString, FontFamily> (true, true);
+
+ int k = Fl::set_fonts ("-*-iso10646-1");
+ for (int i = 0; i < k; i++) {
+ int t;
+ char *name = strdup (Fl::get_font_name ((Fl_Font) i, &t));
+
+ // normalize font family names (strip off "bold", "italic")
+ if (t & FL_ITALIC)
+ strstrip(name, " italic");
+ if (t & FL_BOLD)
+ strstrip(name, " bold");
+
+ _MSG("Found font: %s%s%s\n", name, t & FL_BOLD ? " bold" : "",
+ t & FL_ITALIC ? " italic" : "");
+
+ object::String *familyName = new object::String(name);
+ free (name);
+ FontFamily *family = systemFonts->get (familyName);
+
+ if (family) {
+ family->set ((Fl_Font) i, t);
+ delete familyName;
+ } else {
+ // set first font of family also as normal font in case there
+ // is no normal (non-bold, non-italic) font
+ family = new FontFamily ((Fl_Font) i, -1, -1, -1);
+ family->set ((Fl_Font) i, t);
+ systemFonts->put (familyName, family);
+ }
+ }
+}
+
+bool
+FltkFont::fontExists (const char *name)
+{
+ if (!systemFonts)
+ initSystemFonts ();
+ object::ConstString familyName (name);
+ return systemFonts->get (&familyName) != NULL;
+}
+
+Fl_Font
+FltkFont::get (const char *name, int attrs)
+{
+ if (!systemFonts)
+ initSystemFonts ();
+ object::ConstString familyName (name);
+ FontFamily *family = systemFonts->get (&familyName);
+ if (family)
+ return family->get (attrs);
+ else
+ return FL_HELVETICA;
+}
+
+bool
+FltkPlatform::fontExists (const char *name)
+{
+ return FltkFont::fontExists (name);
+}
+
+FltkFont*
+FltkFont::create (core::style::FontAttrs *attrs)
+{
+ FltkFont *font = fontsTable->get (attrs);
+
+ if (font == NULL) {
+ font = new FltkFont (attrs);
+ fontsTable->put (font, font);
+ }
+
+ return font;
+}
+
+container::typed::HashTable <dw::core::style::ColorAttrs,
+ FltkColor>
+ *FltkColor::colorsTable =
+ new container::typed::HashTable <dw::core::style::ColorAttrs,
+ FltkColor> (false, false);
+
+FltkColor::FltkColor (int color): Color (color)
+{
+ this->color = color;
+
+ if (!(colors[SHADING_NORMAL] = shadeColor (color, SHADING_NORMAL) << 8))
+ colors[SHADING_NORMAL] = FL_BLACK;
+ if (!(colors[SHADING_INVERSE] = shadeColor (color, SHADING_INVERSE) << 8))
+ colors[SHADING_INVERSE] = FL_BLACK;
+ if (!(colors[SHADING_DARK] = shadeColor (color, SHADING_DARK) << 8))
+ colors[SHADING_DARK] = FL_BLACK;
+ if (!(colors[SHADING_LIGHT] = shadeColor (color, SHADING_LIGHT) << 8))
+ colors[SHADING_LIGHT] = FL_BLACK;
+}
+
+FltkColor::~FltkColor ()
+{
+ colorsTable->remove (this);
+}
+
+FltkColor * FltkColor::create (int col)
+{
+ ColorAttrs attrs(col);
+ FltkColor *color = colorsTable->get (&attrs);
+
+ if (color == NULL) {
+ color = new FltkColor (col);
+ colorsTable->put (color, color);
+ }
+
+ return color;
+}
+
+FltkTooltip::FltkTooltip (const char *text) : Tooltip(text)
+{
+}
+
+FltkTooltip::~FltkTooltip ()
+{
+ if (in_tooltip || req_tooltip)
+ cancel(); /* cancel tooltip window */
+}
+
+FltkTooltip *FltkTooltip::create (const char *text)
+{
+ return new FltkTooltip(text);
+}
+
+/*
+ * Tooltip callback: used to delay it a bit
+ * INVARIANT: Only one instance of this function is requested.
+ */
+static void tooltip_tcb(void *data)
+{
+ req_tooltip = 2;
+ ((FltkTooltip *)data)->onEnter();
+ req_tooltip = 0;
+}
+
+void FltkTooltip::onEnter()
+{
+ _MSG("FltkTooltip::onEnter\n");
+ if (!str || !*str)
+ return;
+ if (req_tooltip == 0) {
+ Fl::remove_timeout(tooltip_tcb);
+ Fl::add_timeout(1.0, tooltip_tcb, this);
+ req_tooltip = 1;
+ return;
+ }
+
+ if (!tt_window) {
+ tt_window = new Fl_Menu_Window(0,0,100,24);
+ tt_window->set_override();
+ tt_window->box(FL_NO_BOX);
+ Fl_Box *b = new Fl_Box(0,0,100,24);
+ b->box(FL_BORDER_BOX);
+ b->color(fl_color_cube(FL_NUM_RED-1, FL_NUM_GREEN-1, FL_NUM_BLUE-2));
+ b->labelcolor(FL_BLACK);
+ b->labelfont(FL_HELVETICA);
+ b->labelsize(14);
+ b->align(FL_ALIGN_WRAP|FL_ALIGN_LEFT|FL_ALIGN_INSIDE);
+ tt_window->resizable(b);
+ tt_window->end();
+ }
+
+ /* prepare tooltip window */
+ int x, y;
+ Fl_Box *box = (Fl_Box*)tt_window->child(0);
+ box->label(str);
+ Fl::get_mouse(x,y); y += 6;
+ /* calculate window size */
+ int ww, hh;
+ ww = 800; // max width;
+ box->measure_label(ww, hh);
+ ww += 6 + 2 * Fl::box_dx(box->box());
+ hh += 6 + 2 * Fl::box_dy(box->box());
+ tt_window->resize(x,y,ww,hh);
+ tt_window->show();
+ in_tooltip = 1;
+}
+
+/*
+ * Leaving the widget cancels the tooltip
+ */
+void FltkTooltip::onLeave()
+{
+ _MSG(" FltkTooltip::onLeave in_tooltip=%d\n", in_tooltip);
+ cancel();
+}
+
+void FltkPlatform::cancelTooltip()
+{
+ FltkTooltip::cancel();
+}
+
+/*
+ * Remove a shown tooltip or cancel a pending one
+ */
+void FltkTooltip::cancel()
+{
+ if (req_tooltip) {
+ Fl::remove_timeout(tooltip_tcb);
+ req_tooltip = 0;
+ }
+ if (!in_tooltip) return;
+ in_tooltip = 0;
+ tt_window->hide();
+
+ /* WORKAROUND: (Black magic here)
+ * Hiding a tooltip with the keyboard or mousewheel doesn't work.
+ * The code below "fixes" the problem */
+ Fl_Widget *widget = Fl::belowmouse();
+ if (widget && widget->window()) {
+ widget->window()->damage(FL_DAMAGE_EXPOSE,0,0,1,1);
+ }
+}
+
+void FltkTooltip::onMotion()
+{
+}
+
+void FltkView::addFltkWidget (Fl_Widget *widget,
+ core::Allocation *allocation)
+{
+}
+
+void FltkView::removeFltkWidget (Fl_Widget *widget)
+{
+}
+
+void FltkView::allocateFltkWidget (Fl_Widget *widget,
+ core::Allocation *allocation)
+{
+}
+
+void FltkView::drawFltkWidget (Fl_Widget *widget, core::Rectangle *area)
+{
+}
+
+
+core::ui::LabelButtonResource *
+FltkPlatform::FltkResourceFactory::createLabelButtonResource (const char
+ *label)
+{
+ return new ui::FltkLabelButtonResource (platform, label);
+}
+
+core::ui::ComplexButtonResource *
+FltkPlatform::FltkResourceFactory::createComplexButtonResource (core::Widget
+ *widget,
+ bool relief)
+{
+ // Not needed within RTFL.
+ lout::misc::assertNotReached ();
+ return NULL;
+}
+
+core::ui::ListResource *
+FltkPlatform::FltkResourceFactory::createListResource (core::ui
+ ::ListResource
+ ::SelectionMode
+ selectionMode, int rows)
+{
+ return new ui::FltkListResource (platform, selectionMode, rows);
+}
+
+core::ui::OptionMenuResource *
+FltkPlatform::FltkResourceFactory::createOptionMenuResource ()
+{
+ return new ui::FltkOptionMenuResource (platform);
+}
+
+core::ui::EntryResource *
+FltkPlatform::FltkResourceFactory::createEntryResource (int size,
+ bool password,
+ const char *label)
+{
+ return new ui::FltkEntryResource (platform, size, password, label);
+}
+
+core::ui::MultiLineTextResource *
+FltkPlatform::FltkResourceFactory::createMultiLineTextResource (int cols,
+ int rows)
+{
+ return new ui::FltkMultiLineTextResource (platform, cols, rows);
+}
+
+core::ui::CheckButtonResource *
+FltkPlatform::FltkResourceFactory::createCheckButtonResource (bool activated)
+{
+ return new ui::FltkCheckButtonResource (platform, activated);
+}
+
+core::ui::RadioButtonResource
+*FltkPlatform::FltkResourceFactory::createRadioButtonResource
+(core::ui::RadioButtonResource *groupedWith, bool activated)
+{
+ return
+ new ui::FltkRadioButtonResource (platform,
+ (ui::FltkRadioButtonResource*)
+ groupedWith,
+ activated);
+}
+
+// ----------------------------------------------------------------------
+
+FltkPlatform::FltkPlatform ()
+{
+ DBG_OBJ_CREATE ("dw::fltk::FltkPlatform");
+
+ layout = NULL;
+ idleQueue = new container::typed::List <IdleFunc> (true);
+ idleFuncRunning = false;
+ idleFuncId = 0;
+
+ view = NULL;
+ resources = new container::typed::List <ui::FltkResource> (false);
+
+ resourceFactory.setPlatform (this);
+}
+
+FltkPlatform::~FltkPlatform ()
+{
+ if (idleFuncRunning)
+ Fl::remove_idle (generalStaticIdle, (void*)this);
+ delete idleQueue;
+ delete resources;
+
+ DBG_OBJ_DELETE ();
+}
+
+void FltkPlatform::setLayout (core::Layout *layout)
+{
+ this->layout = layout;
+ DBG_OBJ_ASSOC_CHILD (layout);
+}
+
+
+void FltkPlatform::attachView (core::View *view)
+{
+ if (this->view)
+ MSG_ERR("FltkPlatform::attachView: multiple views!\n");
+ this->view = (FltkView*)view;
+
+ for (container::typed::Iterator <ui::FltkResource> it =
+ resources->iterator (); it.hasNext (); ) {
+ ui::FltkResource *resource = it.getNext ();
+ resource->attachView (this->view);
+ }
+}
+
+
+void FltkPlatform::detachView (core::View *view)
+{
+ if (this->view != view)
+ MSG_ERR("FltkPlatform::detachView: this->view: %p view: %p\n",
+ this->view, view);
+
+ for (container::typed::Iterator <ui::FltkResource> it =
+ resources->iterator (); it.hasNext (); ) {
+ ui::FltkResource *resource = it.getNext ();
+ resource->detachView ((FltkView*)view);
+ }
+ this->view = NULL;
+}
+
+
+int FltkPlatform::textWidth (core::style::Font *font, const char *text,
+ int len)
+{
+ char chbuf[4];
+ int c, cu;
+ int width = 0;
+ FltkFont *ff = (FltkFont*) font;
+ int curr = 0, next = 0, nb;
+
+ if (font->fontVariant == core::style::FONT_VARIANT_SMALL_CAPS) {
+ int sc_fontsize = lout::misc::roundInt(ff->size * 0.78);
+ for (curr = 0; next < len; curr = next) {
+ next = nextGlyph(text, curr);
+ c = fl_utf8decode(text + curr, text + next, &nb);
+ if ((cu = fl_toupper(c)) == c) {
+ /* already uppercase, just draw the character */
+ fl_font(ff->font, ff->size);
+ if (fl_nonspacing(cu) == 0) {
+ width += font->letterSpacing;
+ width += (int)fl_width(text + curr, next - curr);
+ }
+ } else {
+ /* make utf8 string for converted char */
+ nb = fl_utf8encode(cu, chbuf);
+ fl_font(ff->font, sc_fontsize);
+ if (fl_nonspacing(cu) == 0) {
+ width += font->letterSpacing;
+ width += (int)fl_width(chbuf, nb);
+ }
+ }
+ }
+ } else {
+ fl_font (ff->font, ff->size);
+ width = (int) fl_width (text, len);
+
+ if (font->letterSpacing) {
+ int curr = 0, next = 0;
+
+ while (next < len) {
+ next = nextGlyph(text, curr);
+ c = fl_utf8decode(text + curr, text + next, &nb);
+ if (fl_nonspacing(c) == 0)
+ width += font->letterSpacing;
+ curr = next;
+ }
+ }
+ }
+
+ return width;
+}
+
+char *FltkPlatform::textToUpper (const char *text, int len)
+{
+ char *newstr = NULL;
+
+ if (len > 0) {
+ int newlen;
+
+ newstr = (char*) malloc(3 * len + 1);
+ newlen = fl_utf_toupper((const unsigned char*)text, len, newstr);
+ assert(newlen <= 3 * len);
+ newstr[newlen] = '\0';
+ }
+ return newstr;
+}
+
+char *FltkPlatform::textToLower (const char *text, int len)
+{
+ char *newstr = NULL;
+
+ if (len > 0) {
+ int newlen;
+
+ newstr = (char*) malloc(3 * len + 1);
+ newlen = fl_utf_tolower((const unsigned char*)text, len, newstr);
+ assert(newlen <= 3 * len);
+ newstr[newlen] = '\0';
+ }
+ return newstr;
+}
+
+int FltkPlatform::nextGlyph (const char *text, int idx)
+{
+ return fl_utf8fwd (&text[idx + 1], text, &text[strlen (text)]) - text;
+}
+
+int FltkPlatform::prevGlyph (const char *text, int idx)
+{
+ return fl_utf8back (&text[idx - 1], text, &text[strlen (text)]) - text;
+}
+
+float FltkPlatform::dpiX ()
+{
+ float horizontal, vertical;
+
+ Fl::screen_dpi(horizontal, vertical);
+ return horizontal;
+}
+
+float FltkPlatform::dpiY ()
+{
+ float horizontal, vertical;
+
+ Fl::screen_dpi(horizontal, vertical);
+ return vertical;
+}
+
+void FltkPlatform::generalStaticIdle (void *data)
+{
+ ((FltkPlatform*)data)->generalIdle();
+}
+
+void FltkPlatform::generalIdle ()
+{
+ IdleFunc *idleFunc;
+
+ if (!idleQueue->isEmpty ()) {
+ /* Execute the first function in the list. */
+ idleFunc = idleQueue->getFirst ();
+ (layout->*(idleFunc->func)) ();
+
+ /* Remove this function. */
+ idleQueue->removeRef(idleFunc);
+ }
+
+ if (idleQueue->isEmpty()) {
+ idleFuncRunning = false;
+ Fl::remove_idle (generalStaticIdle, (void*)this);
+ }
+}
+
+/**
+ * \todo Incomplete comments.
+ */
+int FltkPlatform::addIdle (void (core::Layout::*func) ())
+{
+ /*
+ * Since ... (todo) we have to wrap around fltk_add_idle. There is only one
+ * idle function, the passed idle function is put into a queue.
+ */
+ if (!idleFuncRunning) {
+ Fl::add_idle (generalStaticIdle, (void*)this);
+ idleFuncRunning = true;
+ }
+
+ idleFuncId++;
+
+ IdleFunc *idleFunc = new IdleFunc();
+ idleFunc->id = idleFuncId;
+ idleFunc->func = func;
+ idleQueue->append (idleFunc);
+
+ return idleFuncId;
+}
+
+void FltkPlatform::removeIdle (int idleId)
+{
+ bool found;
+ container::typed::Iterator <IdleFunc> it;
+ IdleFunc *idleFunc;
+
+ for (found = false, it = idleQueue->iterator(); !found && it.hasNext(); ) {
+ idleFunc = it.getNext();
+ if (idleFunc->id == idleId) {
+ idleQueue->removeRef (idleFunc);
+ found = true;
+ }
+ }
+
+ if (idleFuncRunning && idleQueue->isEmpty())
+ Fl::remove_idle (generalStaticIdle, (void*)this);
+}
+
+core::style::Font *FltkPlatform::createFont (core::style::FontAttrs
+ *attrs,
+ bool tryEverything)
+{
+ return FltkFont::create (attrs);
+}
+
+core::style::Color *FltkPlatform::createColor (int color)
+{
+ return FltkColor::create (color);
+}
+
+core::style::Tooltip *FltkPlatform::createTooltip (const char *text)
+{
+ return FltkTooltip::create (text);
+}
+
+void FltkPlatform::copySelection(const char *text)
+{
+ Fl::copy(text, strlen(text), 0);
+}
+
+core::Imgbuf *FltkPlatform::createImgbuf (core::Imgbuf::Type type,
+ int width, int height, double gamma)
+{
+ return new FltkImgbuf (type, width, height, gamma);
+}
+
+core::ui::ResourceFactory *FltkPlatform::getResourceFactory ()
+{
+ return &resourceFactory;
+}
+
+
+void FltkPlatform::attachResource (ui::FltkResource *resource)
+{
+ resources->append (resource);
+ resource->attachView (view);
+}
+
+void FltkPlatform::detachResource (ui::FltkResource *resource)
+{
+ resources->removeRef (resource);
+}
+
+} // namespace fltk
+} // namespace dw
diff --git a/dw/fltkplatform.hh b/dw/fltkplatform.hh
new file mode 100644
index 0000000..2fb9563
--- /dev/null
+++ b/dw/fltkplatform.hh
@@ -0,0 +1,186 @@
+#ifndef __DW_FLTKPLATFORM_HH__
+#define __DW_FLTKPLATFORM_HH__
+
+#ifndef __INCLUDED_FROM_DW_FLTK_CORE_HH__
+# error Do not include this file directly, use "fltkcore.hh" instead.
+#endif
+
+namespace dw {
+
+/**
+ * \brief This namespace contains FLTK implementations of Dw interfaces.
+ */
+namespace fltk {
+
+class FltkFont: public core::style::Font
+{
+ class FontFamily: public lout::object::Object {
+ Fl_Font font[4];
+ public:
+ FontFamily (Fl_Font fontNormal, Fl_Font fontBold,
+ Fl_Font fontItalic, Fl_Font fontBoldItalic);
+ void set (Fl_Font, int attrs);
+ Fl_Font get (int attrs);
+ };
+
+ static FontFamily standardFontFamily;
+
+ static lout::container::typed::HashTable <lout::object::ConstString,
+ FontFamily> *systemFonts;
+ static lout::container::typed::HashTable <dw::core::style::FontAttrs,
+ FltkFont> *fontsTable;
+
+ FltkFont (core::style::FontAttrs *attrs);
+ ~FltkFont ();
+
+ static void initSystemFonts ();
+
+public:
+ Fl_Font font;
+
+ static FltkFont *create (core::style::FontAttrs *attrs);
+ static bool fontExists (const char *name);
+ static Fl_Font get (const char *name, int attrs);
+};
+
+
+class FltkColor: public core::style::Color
+{
+ static lout::container::typed::HashTable <dw::core::style::ColorAttrs,
+ FltkColor> *colorsTable;
+
+ FltkColor (int color);
+ ~FltkColor ();
+
+public:
+ int colors[SHADING_NUM];
+
+ static FltkColor *create(int color);
+};
+
+class FltkTooltip: public core::style::Tooltip
+{
+private:
+ FltkTooltip (const char *text);
+ ~FltkTooltip ();
+public:
+ static FltkTooltip *create(const char *text);
+ static void cancel();
+ void onEnter();
+ void onLeave();
+ void onMotion();
+};
+
+
+/**
+ * \brief This interface adds some more methods for all flkt-based views.
+ */
+class FltkView: public core::View
+{
+public:
+ virtual bool usesFltkWidgets () = 0;
+
+ virtual void addFltkWidget (Fl_Widget *widget,
+ core::Allocation *allocation);
+ virtual void removeFltkWidget (Fl_Widget *widget);
+ virtual void allocateFltkWidget (Fl_Widget *widget,
+ core::Allocation *allocation);
+ virtual void drawFltkWidget (Fl_Widget *widget, core::Rectangle *area);
+};
+
+
+class FltkPlatform: public core::Platform
+{
+private:
+ class FltkResourceFactory: public core::ui::ResourceFactory
+ {
+ private:
+ FltkPlatform *platform;
+
+ public:
+ inline void setPlatform (FltkPlatform *platform) {
+ this->platform = platform; }
+
+ core::ui::LabelButtonResource *createLabelButtonResource (const char
+ *label);
+ core::ui::ComplexButtonResource *
+ createComplexButtonResource (core::Widget *widget, bool relief);
+ core::ui::ListResource *
+ createListResource (core::ui::ListResource::SelectionMode selectionMode,
+ int rows);
+ core::ui::OptionMenuResource *createOptionMenuResource ();
+ core::ui::EntryResource *createEntryResource (int size, bool password,
+ const char *label);
+ core::ui::MultiLineTextResource *createMultiLineTextResource (int cols,
+ int rows);
+ core::ui::CheckButtonResource *createCheckButtonResource (bool
+ activated);
+ core::ui::RadioButtonResource *
+ createRadioButtonResource (core::ui::RadioButtonResource
+ *groupedWith, bool activated);
+ };
+
+ FltkResourceFactory resourceFactory;
+
+ class IdleFunc: public lout::object::Object
+ {
+ public:
+ int id;
+ void (core::Layout::*func) ();
+ };
+
+ core::Layout *layout;
+
+ lout::container::typed::List <IdleFunc> *idleQueue;
+ bool idleFuncRunning;
+ int idleFuncId;
+
+ static void generalStaticIdle(void *data);
+ void generalIdle();
+
+ FltkView *view;
+ lout::container::typed::List <ui::FltkResource> *resources;
+
+public:
+ FltkPlatform ();
+ ~FltkPlatform ();
+
+ void setLayout (core::Layout *layout);
+
+ void attachView (core::View *view);
+
+ void detachView (core::View *view);
+
+ int textWidth (core::style::Font *font, const char *text, int len);
+ char *textToUpper (const char *text, int len);
+ char *textToLower (const char *text, int len);
+ int nextGlyph (const char *text, int idx);
+ int prevGlyph (const char *text, int idx);
+ float dpiX ();
+ float dpiY ();
+
+ int addIdle (void (core::Layout::*func) ());
+ void removeIdle (int idleId);
+
+ core::style::Font *createFont (core::style::FontAttrs *attrs,
+ bool tryEverything);
+ bool fontExists (const char *name);
+ core::style::Color *createColor (int color);
+ core::style::Tooltip *createTooltip (const char *text);
+ void cancelTooltip();
+
+ core::Imgbuf *createImgbuf (core::Imgbuf::Type type, int width, int height,
+ double gamma);
+
+ void copySelection(const char *text);
+
+ core::ui::ResourceFactory *getResourceFactory ();
+
+ void attachResource (ui::FltkResource *resource);
+ void detachResource (ui::FltkResource *resource);
+};
+
+} // namespace fltk
+} // namespace dw
+
+#endif // __DW_FLTKPLATFORM_HH__
diff --git a/dw/fltkpreview.cc b/dw/fltkpreview.cc
new file mode 100644
index 0000000..b234e81
--- /dev/null
+++ b/dw/fltkpreview.cc
@@ -0,0 +1,316 @@
+/*
+ * RTFL (originally part of dillo)
+ *
+ * Copyright 2005-2007 Sebastian Geerken <sgeerken@dillo.org>
+ *
+ * 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; with the following exception:
+ *
+ * The copyright holders of RTFL give you permission to link this file
+ * statically or dynamically against all versions of the graphviz
+ * library, which are published by AT&T Corp. under one of the following
+ * licenses:
+ *
+ * - Common Public License version 1.0 as published by International
+ * Business Machines Corporation (IBM), or
+ * - Eclipse Public License version 1.0 as published by the Eclipse
+ * Foundation.
+ *
+ * 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/>.
+ */
+
+#include "../lout/msg.h"
+
+#include "fltkpreview.hh"
+#include "fltkmisc.hh"
+
+#include <FL/Fl.H>
+#include <FL/Fl_Bitmap.H>
+#include <FL/fl_draw.H>
+#include <stdio.h>
+
+#include "preview.xbm"
+
+namespace dw {
+namespace fltk {
+
+FltkPreview::FltkPreview (int x, int y, int w, int h,
+ dw::core::Layout *layout, const char *label):
+ FltkViewBase (x, y, w, h, label)
+{
+ layout->attachView (this);
+
+ scrollX = 0;
+ scrollY = 0;
+ scrollWidth = 1;
+ scrollHeight = 1;
+}
+
+FltkPreview::~FltkPreview ()
+{
+}
+
+int FltkPreview::handle (int event)
+{
+ return FltkViewBase::handle (event);
+}
+
+int FltkPreview::translateViewXToCanvasX (int x)
+{
+ return x * canvasWidth / w ();
+}
+
+int FltkPreview::translateViewYToCanvasY (int y)
+{
+ return y * canvasHeight / h ();
+}
+
+int FltkPreview::translateCanvasXToViewX (int x)
+{
+ return x * w () / canvasWidth;
+}
+
+int FltkPreview::translateCanvasYToViewY (int y)
+{
+ return y * h () / canvasHeight;
+}
+
+void FltkPreview::setCanvasSize (int width, int ascent, int descent)
+{
+ FltkViewBase::setCanvasSize (width, ascent, descent);
+ if (parent() && parent()->visible ())
+ ((FltkPreviewWindow*)parent())->reallocate ();
+}
+
+bool FltkPreview::usesViewport ()
+{
+ return true;
+}
+
+int FltkPreview::getHScrollbarThickness ()
+{
+ return 0;
+}
+
+int FltkPreview::getVScrollbarThickness ()
+{
+ return 0;
+}
+
+void FltkPreview::scrollTo (int x, int y)
+{
+ scrollX = x;
+ scrollY = y;
+}
+
+void FltkPreview::scroll (dw::core::ScrollCommand cmd)
+{
+ MSG_ERR("FltkPreview::scroll not implemented\n");
+}
+
+void FltkPreview::setViewportSize (int width, int height,
+ int hScrollbarThickness,
+ int vScrollbarThickness)
+{
+ scrollWidth = width - vScrollbarThickness;
+ scrollHeight = height - hScrollbarThickness;
+}
+
+void FltkPreview::drawText (core::style::Font *font,
+ core::style::Color *color,
+ core::style::Color::Shading shading,
+ int x, int y, const char *text, int len)
+{
+ /*
+ * We must call setfont() before calling getwidth() (or anything
+ * else that measures text).
+ */
+ FltkFont *ff = (FltkFont*)font;
+ Fl::set_font(ff->font, translateCanvasXToViewX (ff->size));
+#if 0
+ /**
+ * \todo Normally, this should already be known, maybe it
+ * should be passed?
+ */
+ int width = (int)getwidth (text, len);
+ int height = font->ascent; // No descent, this would look to "bold".
+
+ int x1 = translateCanvasXToViewX (x);
+ int y1 = translateCanvasYToViewY (y);
+ int x2 = translateCanvasXToViewX (x + width);
+ int y2 = translateCanvasYToViewY (y + height);
+ Rectangle rect (x1, y1, x2 - x1, y2 - y1);
+
+ setcolor(((FltkColor*)color)->colors[shading]);
+ fillrect (rect);
+#endif
+ fl_color(((FltkColor*)color)->colors[shading]);
+ fl_draw(text, len, translateCanvasXToViewX (x), translateCanvasYToViewY(y));
+}
+
+void FltkPreview::drawSimpleWrappedText (core::style::Font *font,
+ core::style::Color *color,
+ core::style::Color::Shading shading,
+ int x, int y, int w, int h,
+ const char *text)
+{
+}
+
+void FltkPreview::drawImage (core::Imgbuf *imgbuf, int xRoot, int yRoot,
+ int x, int y, int width, int height)
+{
+}
+
+bool FltkPreview::usesFltkWidgets ()
+{
+ return false;
+}
+
+void FltkPreview::drawFltkWidget (Fl_Widget *widget,
+ core::Rectangle *area)
+{
+}
+
+// ----------------------------------------------------------------------
+
+FltkPreviewWindow::FltkPreviewWindow (dw::core::Layout *layout):
+ Fl_Menu_Window (1, 1)
+{
+ box (FL_EMBOSSED_BOX);
+
+ begin ();
+ preview = new FltkPreview (BORDER_WIDTH, BORDER_WIDTH, 1, 1, layout);
+ end ();
+
+ hide ();
+}
+
+FltkPreviewWindow::~FltkPreviewWindow ()
+{
+}
+
+void FltkPreviewWindow::showWindow ()
+{
+ reallocate ();
+ show ();
+}
+
+void FltkPreviewWindow::reallocate ()
+{
+ int maxWidth = misc::screenWidth () / 2;
+ int maxHeight = misc::screenHeight () * 4 / 5;
+ int mx, my, width, height;
+ bool warp = false;
+
+ if (preview->canvasHeight * maxWidth > maxHeight * preview->canvasWidth) {
+ // Expand to maximal height (most likely case).
+ width = preview->canvasWidth * maxHeight / preview->canvasHeight;
+ height = maxHeight;
+ } else {
+ // Expand to maximal width.
+ width = maxWidth;
+ height = preview->canvasHeight * maxWidth / preview->canvasWidth;
+ }
+
+ Fl::get_mouse(mx, my);
+
+ posX = mx - preview->translateCanvasXToViewX (preview->scrollX
+ + preview->scrollWidth / 2);
+ posY = my - preview->translateCanvasYToViewY (preview->scrollY
+ + preview->scrollHeight / 2);
+
+ if (posX < 0) {
+ mx -= posX;
+ posX = 0;
+ warp = true;
+ } else if (posX + width > misc::screenWidth ()) {
+ mx -= (posX - (misc::screenWidth () - width));
+ posX = misc::screenWidth () - width;
+ warp = true;
+ }
+
+ if (posY < 0) {
+ my -= posY;
+ posY = 0;
+ warp = true;
+ } else if (posY + height > misc::screenHeight ()) {
+ my -= (posY - (misc::screenHeight () - height));
+ posY = misc::screenHeight () - height;
+ warp = true;
+ }
+
+ if (warp)
+ misc::warpPointer (mx, my);
+
+ resize (posX, posY, width, height);
+
+ preview->size(w () - 2 * BORDER_WIDTH, h () - 2 * BORDER_WIDTH);
+}
+
+void FltkPreviewWindow::hideWindow ()
+{
+ Fl_Window::hide ();
+}
+
+void FltkPreviewWindow::scrollTo (int mouseX, int mouseY)
+{
+ preview->scrollX =
+ preview->translateViewXToCanvasX (mouseX - posX - BORDER_WIDTH)
+ - preview->scrollWidth / 2;
+ preview->scrollY =
+ preview->translateViewYToCanvasY (mouseY - posY - BORDER_WIDTH)
+ - preview->scrollHeight / 2;
+ preview->theLayout->scrollPosChanged (preview,
+ preview->scrollX, preview->scrollY);
+}
+
+// ----------------------------------------------------------------------
+
+FltkPreviewButton::FltkPreviewButton (int x, int y, int w, int h,
+ dw::core::Layout *layout,
+ const char *label):
+ Fl_Button (x, y, w, h, label)
+{
+ image (new Fl_Bitmap (preview_bits, preview_width, preview_height));
+ window = new FltkPreviewWindow (layout);
+}
+
+FltkPreviewButton::~FltkPreviewButton ()
+{
+}
+
+int FltkPreviewButton::handle (int event)
+{
+ /** \bug Some parts are missing. */
+
+ switch (event) {
+ case FL_PUSH:
+ window->showWindow ();
+ return Fl_Button::handle (event);
+
+ case FL_DRAG:
+ if (window->visible ()) {
+ window->scrollTo (Fl::event_x_root (), Fl::event_y_root ());
+ return 1;
+ }
+ return Fl_Button::handle (event);
+
+ case FL_RELEASE:
+ window->hideWindow ();
+ return Fl_Button::handle (event);
+
+ default:
+ return Fl_Button::handle (event);
+ }
+}
+
+} // namespace fltk
+} // namespace dw
diff --git a/dw/fltkpreview.hh b/dw/fltkpreview.hh
new file mode 100644
index 0000000..2382b86
--- /dev/null
+++ b/dw/fltkpreview.hh
@@ -0,0 +1,95 @@
+#ifndef __FlTKPREVIEW_HH__
+#define __FlTKPREVIEW_HH__
+
+#include <FL/Fl_Button.H>
+#include <FL/Fl_Menu_Window.H>
+#include "fltkviewbase.hh"
+
+namespace dw {
+namespace fltk {
+
+class FltkPreview: public FltkViewBase
+{
+ friend class FltkPreviewWindow;
+
+private:
+ int scrollX, scrollY, scrollWidth, scrollHeight;
+
+protected:
+ int translateViewXToCanvasX (int x);
+ int translateViewYToCanvasY (int y);
+ int translateCanvasXToViewX (int x);
+ int translateCanvasYToViewY (int y);
+
+public:
+ FltkPreview (int x, int y, int w, int h, dw::core::Layout *layout,
+ const char *label = 0);
+ ~FltkPreview ();
+
+ int handle (int event);
+
+ void setCanvasSize (int width, int ascent, int descent);
+
+ bool usesViewport ();
+ int getHScrollbarThickness ();
+ int getVScrollbarThickness ();
+ void scrollTo (int x, int y);
+ void scroll (dw::core::ScrollCommand cmd);
+ void setViewportSize (int width, int height,
+ int hScrollbarThickness, int vScrollbarThickness);
+
+ void drawText (core::style::Font *font,
+ core::style::Color *color,
+ core::style::Color::Shading shading,
+ int x, int y, const char *text, int len);
+ void drawSimpleWrappedText (core::style::Font *font,
+ core::style::Color *color,
+ core::style::Color::Shading shading,
+ int x, int y, int w, int h,
+ const char *text);
+ void drawImage (core::Imgbuf *imgbuf, int xRoot, int yRoot,
+ int x, int y, int width, int height);
+
+ bool usesFltkWidgets ();
+ void drawFltkWidget (Fl_Widget *widget, core::Rectangle *area);
+};
+
+
+class FltkPreviewWindow: public Fl_Menu_Window
+{
+private:
+ enum { BORDER_WIDTH = 2 };
+
+ FltkPreview *preview;
+ int posX, posY;
+
+public:
+ FltkPreviewWindow (dw::core::Layout *layout);
+ ~FltkPreviewWindow ();
+
+ void reallocate ();
+
+ void showWindow ();
+ void hideWindow ();
+
+ void scrollTo (int mouseX, int mouseY);
+};
+
+
+class FltkPreviewButton: public Fl_Button
+{
+private:
+ FltkPreviewWindow *window;
+
+public:
+ FltkPreviewButton (int x, int y, int w, int h,
+ dw::core::Layout *layout, const char *label = 0);
+ ~FltkPreviewButton ();
+
+ int handle (int event);
+};
+
+} // namespace fltk
+} // namespace dw
+
+#endif // __FlTKPREVIEW_HH__
diff --git a/dw/fltkui.cc b/dw/fltkui.cc
new file mode 100644
index 0000000..ce47dcd
--- /dev/null
+++ b/dw/fltkui.cc
@@ -0,0 +1,1395 @@
+/*
+ * RTFL (originally part of dillo)
+ *
+ * Copyright 2005-2007 Sebastian Geerken <sgeerken@dillo.org>
+ *
+ * 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; with the following exception:
+ *
+ * The copyright holders of RTFL give you permission to link this file
+ * statically or dynamically against all versions of the graphviz
+ * library, which are published by AT&T Corp. under one of the following
+ * licenses:
+ *
+ * - Common Public License version 1.0 as published by International
+ * Business Machines Corporation (IBM), or
+ * - Eclipse Public License version 1.0 as published by the Eclipse
+ * Foundation.
+ *
+ * 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/>.
+ */
+
+
+
+#include "fltkcore.hh"
+#include "../lout/msg.h"
+#include "../lout/misc.hh"
+
+#include <FL/Fl.H>
+#include <FL/fl_draw.H>
+#include <FL/Fl_Input.H>
+#include <FL/Fl_Text_Editor.H>
+#include <FL/Fl_Check_Button.H>
+#include <FL/Fl_Round_Button.H>
+#include <FL/Fl_Choice.H>
+#include <FL/Fl_Browser.H>
+
+#include <stdio.h>
+
+//----------------------------------------------------------------------------
+/*
+ * Local sub classes
+ */
+
+/*
+ * Used to enable CTRL+{a,e,d,k} in form inputs (for start,end,del,cut)
+ */
+class CustInput2 : public Fl_Input {
+public:
+ CustInput2 (int x, int y, int w, int h, const char* l=0) :
+ Fl_Input(x,y,w,h,l) {};
+ int handle(int e);
+};
+
+int CustInput2::handle(int e)
+{
+ int k = Fl::event_key();
+
+ _MSG("CustInput2::handle event=%d\n", e);
+
+ // We're only interested in some flags
+ unsigned modifier = Fl::event_state() & (FL_SHIFT | FL_CTRL | FL_ALT);
+
+ if (e == FL_KEYBOARD) {
+ if (k == FL_Page_Down || k == FL_Page_Up || k == FL_Up || k == FL_Down) {
+ // Let them through for key commands and viewport motion.
+ return 0;
+ }
+ if (modifier == FL_CTRL) {
+ if (k == 'a' || k == 'e') {
+ position(k == 'a' ? 0 : size());
+ return 1;
+ } else if (k == 'k') {
+ cut(position(), size());
+ return 1;
+ } else if (k == 'd') {
+ cut(position(), position()+1);
+ return 1;
+ } else if (k == 'h' || k == 'i' || k == 'j' || k == 'l' || k == 'm') {
+ // Fl_Input wants to use ^H as backspace, and also "insert a few
+ // selected control characters literally", but this gets in the way
+ // of key commands.
+ return 0;
+ }
+ }
+ }
+ return Fl_Input::handle(e);
+}
+
+
+/*
+ * Used to handle some keystrokes as shortcuts to option menuitems
+ * (i.e. jump to the next menuitem whose label starts with the pressed key)
+ */
+class CustChoice : public Fl_Choice {
+public:
+ CustChoice (int x, int y, int w, int h, const char* l=0) :
+ Fl_Choice(x,y,w,h,l) {};
+ int handle(int e);
+};
+
+int CustChoice::handle(int e)
+{
+ int k = Fl::event_key();
+ unsigned modifier = Fl::event_state() & (FL_SHIFT|FL_CTRL|FL_ALT|FL_META);
+
+ _MSG("CustChoice::handle %p e=%d active=%d focus=%d\n",
+ this, e, active(), (Fl::focus() == this));
+ if (Fl::focus() != this) {
+ ; // Not Focused, let FLTK handle it
+ } else if (e == FL_KEYDOWN && modifier == 0) {
+ if (k == FL_Enter || k == FL_Down) {
+ return Fl_Choice::handle(FL_PUSH); // activate menu
+
+ } else if (isalnum(k)) { // try key as shortcut to menuitem
+ int t = value()+1 >= size() ? 0 : value()+1;
+ while (t != value()) {
+ const Fl_Menu_Item *mi = &(menu()[t]);
+ if (mi->submenu()) // submenu?
+ ;
+ else if (mi->label() && mi->active()) { // menu item?
+ if (k == tolower(mi->label()[0])) {
+ value(mi);
+ return 1; // Let FLTK know we used this key
+ }
+ }
+ if (++t == size())
+ t = 0;
+ }
+ }
+ }
+
+ return Fl_Choice::handle(e);
+}
+
+//----------------------------------------------------------------------------
+
+namespace dw {
+namespace fltk {
+namespace ui {
+
+enum { RELIEF_X_THICKNESS = 3, RELIEF_Y_THICKNESS = 3 };
+
+using namespace lout::object;
+using namespace lout::container::typed;
+
+FltkResource::FltkResource (FltkPlatform *platform)
+{
+ DBG_OBJ_CREATE ("dw::fltk::ui::FltkResource");
+
+ this->platform = platform;
+
+ allocation.x = 0;
+ allocation.y = 0;
+ allocation.width = 1;
+ allocation.ascent = 1;
+ allocation.descent = 0;
+
+ style = NULL;
+
+ enabled = true;
+}
+
+/**
+ * This is not a constructor, since it calls some virtual methods, which
+ * should not be done in a C++ base constructor.
+ */
+void FltkResource::init (FltkPlatform *platform)
+{
+ view = NULL;
+ widget = NULL;
+ platform->attachResource (this);
+}
+
+FltkResource::~FltkResource ()
+{
+ platform->detachResource (this);
+ if (widget) {
+ if (view) {
+ view->removeFltkWidget(widget);
+ }
+ delete widget;
+ }
+ if (style)
+ style->unref ();
+
+ DBG_OBJ_DELETE ();
+}
+
+void FltkResource::attachView (FltkView *view)
+{
+ if (this->view)
+ MSG_ERR("FltkResource::attachView: multiple views!\n");
+
+ if (view->usesFltkWidgets ()) {
+ this->view = view;
+
+ widget = createNewWidget (&allocation);
+ view->addFltkWidget (widget, &allocation);
+ if (style)
+ setWidgetStyle (widget, style);
+ if (! enabled)
+ widget->deactivate ();
+ }
+}
+
+void FltkResource::detachView (FltkView *view)
+{
+ if (this->view != view)
+ MSG_ERR("FltkResource::detachView: this->view: %p view: %p\n",
+ this->view, view);
+ this->view = NULL;
+}
+
+void FltkResource::sizeAllocate (core::Allocation *allocation)
+{
+ DBG_OBJ_ENTER ("resize", 0, "sizeAllocate", "%d, %d; %d * (%d + %d)",
+ allocation->x, allocation->y, allocation->width,
+ allocation->ascent, allocation->descent);
+
+ this->allocation = *allocation;
+ view->allocateFltkWidget (widget, allocation);
+
+ DBG_OBJ_LEAVE ();
+}
+
+void FltkResource::draw (core::View *view, core::Rectangle *area)
+{
+ FltkView *fltkView = (FltkView*)view;
+ if (fltkView->usesFltkWidgets () && this->view == fltkView) {
+ fltkView->drawFltkWidget (widget, area);
+ }
+}
+
+void FltkResource::setStyle (core::style::Style *style)
+{
+ if (this->style)
+ this->style->unref ();
+
+ this->style = style;
+ style->ref ();
+
+ setWidgetStyle (widget, style);
+}
+
+void FltkResource::setWidgetStyle (Fl_Widget *widget,
+ core::style::Style *style)
+{
+ FltkFont *font = (FltkFont*)style->font;
+ widget->labelsize (font->size);
+ widget->labelfont (font->font);
+
+ FltkColor *bg = (FltkColor*)style->backgroundColor;
+ if (bg) {
+ int normal_bg = bg->colors[FltkColor::SHADING_NORMAL];
+
+ if (style->color) {
+ int style_fg = ((FltkColor*)style->color)->colors
+ [FltkColor::SHADING_NORMAL];
+ Fl_Color fg = fl_contrast(style_fg, normal_bg);
+
+ widget->labelcolor(fg);
+ widget->selection_color(fg);
+ }
+
+ widget->color(normal_bg);
+ }
+}
+
+void FltkResource::setDisplayed(bool displayed)
+{
+ if (displayed)
+ widget->show();
+ else
+ widget->hide();
+}
+
+bool FltkResource::displayed()
+{
+ bool ret = false;
+
+ if (widget) {
+ // visible() is not the same thing as being show()n exactly, but
+ // show()/hide() set it appropriately for our purposes.
+ ret = widget->visible();
+ }
+ return ret;
+}
+
+bool FltkResource::isEnabled ()
+{
+ return enabled;
+}
+
+void FltkResource::setEnabled (bool enabled)
+{
+ this->enabled = enabled;
+
+ if (enabled)
+ widget->activate ();
+ else
+ widget->deactivate ();
+}
+
+// ----------------------------------------------------------------------
+
+template <class I> FltkSpecificResource<I>::FltkSpecificResource (FltkPlatform
+ *platform) :
+ FltkResource (platform)
+{
+ DBG_OBJ_CREATE ("dw::fltk::ui::FltkSpecificResource<>");
+ DBG_OBJ_BASECLASS (I);
+ DBG_OBJ_BASECLASS (FltkResource);
+}
+
+template <class I> FltkSpecificResource<I>::~FltkSpecificResource ()
+{
+ DBG_OBJ_DELETE ();
+}
+
+template <class I> void FltkSpecificResource<I>::sizeAllocate (core::Allocation
+ *allocation)
+{
+ FltkResource::sizeAllocate (allocation);
+}
+
+template <class I> void FltkSpecificResource<I>::draw (core::View *view,
+ core::Rectangle *area)
+{
+ FltkResource::draw (view, area);
+}
+
+template <class I> void FltkSpecificResource<I>::setStyle (core::style::Style
+ *style)
+{
+ FltkResource::setStyle (style);
+}
+
+template <class I> bool FltkSpecificResource<I>::isEnabled ()
+{
+ return FltkResource::isEnabled ();
+}
+
+template <class I> void FltkSpecificResource<I>::setEnabled (bool enabled)
+{
+ FltkResource::setEnabled (enabled);
+}
+
+// ----------------------------------------------------------------------
+
+class EnterButton : public Fl_Button {
+public:
+ EnterButton (int x,int y,int w,int h, const char* label = 0) :
+ Fl_Button (x,y,w,h,label) {};
+ int handle(int e);
+};
+
+int EnterButton::handle(int e)
+{
+ if (e == FL_KEYBOARD && Fl::focus() == this && Fl::event_key() == FL_Enter){
+ set_changed();
+ simulate_key_action();
+ do_callback();
+ return 1;
+ }
+ return Fl_Button::handle(e);
+}
+
+FltkLabelButtonResource::FltkLabelButtonResource (FltkPlatform *platform,
+ const char *label):
+ FltkSpecificResource <dw::core::ui::LabelButtonResource> (platform)
+{
+ this->label = strdup (label);
+ init (platform);
+}
+
+FltkLabelButtonResource::~FltkLabelButtonResource ()
+{
+ free((char *)label);
+}
+
+Fl_Widget *FltkLabelButtonResource::createNewWidget (core::Allocation
+ *allocation)
+{
+ Fl_Button *button =
+ new EnterButton (allocation->x, allocation->y, allocation->width,
+ allocation->ascent + allocation->descent, label);
+ button->callback (widgetCallback, this);
+ button->when (FL_WHEN_RELEASE);
+ return button;
+}
+
+void FltkLabelButtonResource::sizeRequest (core::Requisition *requisition)
+{
+ DBG_OBJ_ENTER0 ("resize", 0, "sizeRequest");
+
+ if (style) {
+ FltkFont *font = (FltkFont*)style->font;
+ fl_font(font->font,font->size);
+ requisition->width =
+ (int)fl_width (label, strlen (label))
+ + 2 * RELIEF_X_THICKNESS;
+ requisition->ascent = font->ascent + RELIEF_Y_THICKNESS;
+ requisition->descent = font->descent + RELIEF_Y_THICKNESS;
+ } else {
+ requisition->width = 1;
+ requisition->ascent = 1;
+ requisition->descent = 0;
+ }
+
+ DBG_OBJ_MSGF ("resize", 1, "result: %d * (%d + %d)",
+ requisition->width, requisition->ascent, requisition->descent);
+ DBG_OBJ_LEAVE ();
+}
+
+/*
+ * Get FLTK state and translate to dw
+ *
+ * TODO: find a good home for this and the fltkviewbase.cc original.
+ */
+static core::ButtonState getDwButtonState ()
+{
+ int s1 = Fl::event_state ();
+ int s2 = (core::ButtonState)0;
+
+ if (s1 & FL_SHIFT) s2 |= core::SHIFT_MASK;
+ if (s1 & FL_CTRL) s2 |= core::CONTROL_MASK;
+ if (s1 & FL_ALT) s2 |= core::META_MASK;
+ if (s1 & FL_BUTTON1) s2 |= core::BUTTON1_MASK;
+ if (s1 & FL_BUTTON2) s2 |= core::BUTTON2_MASK;
+ if (s1 & FL_BUTTON3) s2 |= core::BUTTON3_MASK;
+
+ return (core::ButtonState)s2;
+}
+
+static void setButtonEvent(dw::core::EventButton *event)
+{
+ event->xCanvas = Fl::event_x();
+ event->yCanvas = Fl::event_y();
+ event->state = getDwButtonState();
+ event->button = Fl::event_button();
+ event->numPressed = Fl::event_clicks() + 1;
+}
+
+void FltkLabelButtonResource::widgetCallback (Fl_Widget *widget,
+ void *data)
+{
+ if (!Fl::event_button3()) {
+ FltkLabelButtonResource *lbr = (FltkLabelButtonResource*) data;
+ dw::core::EventButton event;
+ setButtonEvent(&event);
+ lbr->emitClicked(&event);
+ }
+}
+
+const char *FltkLabelButtonResource::getLabel ()
+{
+ return label;
+}
+
+
+void FltkLabelButtonResource::setLabel (const char *label)
+{
+ free((char *)this->label);
+ this->label = strdup (label);
+
+ widget->label (this->label);
+ queueResize (true);
+}
+
+// ----------------------------------------------------------------------
+
+FltkEntryResource::FltkEntryResource (FltkPlatform *platform, int size,
+ bool password, const char *label):
+ FltkSpecificResource <dw::core::ui::EntryResource> (platform)
+{
+ this->size = size;
+ this->password = password;
+ this->label = label ? strdup(label) : NULL;
+ this->label_w = 0;
+
+ initText = NULL;
+ editable = false;
+
+ init (platform);
+}
+
+FltkEntryResource::~FltkEntryResource ()
+{
+ if (initText)
+ free((char *)initText);
+ if (label)
+ free(label);
+}
+
+Fl_Widget *FltkEntryResource::createNewWidget (core::Allocation
+ *allocation)
+{
+ Fl_Input *input =
+ new CustInput2(allocation->x, allocation->y, allocation->width,
+ allocation->ascent + allocation->descent);
+ if (password)
+ input->type(FL_SECRET_INPUT);
+ input->callback (widgetCallback, this);
+ input->when (FL_WHEN_ENTER_KEY_ALWAYS);
+
+ if (label) {
+ input->label(label);
+ input->align(FL_ALIGN_LEFT);
+ }
+ if (initText)
+ input->value (initText);
+
+ return input;
+}
+
+void FltkEntryResource::setWidgetStyle (Fl_Widget *widget,
+ core::style::Style *style)
+{
+ Fl_Input *in = (Fl_Input *)widget;
+
+ FltkResource::setWidgetStyle(widget, style);
+
+ in->textcolor(widget->labelcolor());
+ in->cursor_color(in->textcolor());
+ in->textsize(in->labelsize());
+ in->textfont(in->labelfont());
+
+ if (label) {
+ int h;
+ label_w = 0;
+ widget->measure_label(label_w, h);
+ label_w += RELIEF_X_THICKNESS;
+ }
+}
+
+void FltkEntryResource::setDisplayed(bool displayed)
+{
+ FltkResource::setDisplayed(displayed);
+ queueResize(true);
+}
+
+void FltkEntryResource::sizeRequest (core::Requisition *requisition)
+{
+ DBG_OBJ_ENTER0 ("resize", 0, "sizeRequest");
+
+ if (displayed() && style) {
+ FltkFont *font = (FltkFont*)style->font;
+ fl_font(font->font,font->size);
+ // WORKAROUND: A bug with fl_width(uint_t) on non-xft X was present in
+ // 1.3.0 (STR #2688).
+ requisition->width =
+ (int)fl_width ("n")
+ * (size == UNLIMITED_SIZE ? 10 : size)
+ + label_w + (2 * RELIEF_X_THICKNESS);
+ requisition->ascent = font->ascent + RELIEF_Y_THICKNESS;
+ requisition->descent = font->descent + RELIEF_Y_THICKNESS;
+ } else {
+ requisition->width = 0;
+ requisition->ascent = 0;
+ requisition->descent = 0;
+ }
+
+ DBG_OBJ_MSGF ("resize", 1, "result: %d * (%d + %d)",
+ requisition->width, requisition->ascent, requisition->descent);
+ DBG_OBJ_LEAVE ();
+}
+
+void FltkEntryResource::sizeAllocate (core::Allocation *allocation)
+{
+ if (!label) {
+ FltkResource::sizeAllocate(allocation);
+ } else {
+ DBG_OBJ_MSGF ("resize", 0,
+ "<b>sizeAllocate</b> (%d, %d; %d * (%d + %d))",
+ allocation->x, allocation->y, allocation->width,
+ allocation->ascent, allocation->descent);
+
+ this->allocation = *allocation;
+
+ /* push the Fl_Input over to the right of the label */
+ core::Allocation a = this->allocation;
+ a.x += this->label_w;
+ a.width -= this->label_w;
+ view->allocateFltkWidget (widget, &a);
+ }
+}
+
+void FltkEntryResource::widgetCallback (Fl_Widget *widget, void *data)
+{
+ ((FltkEntryResource*)data)->emitActivate ();
+}
+
+const char *FltkEntryResource::getText ()
+{
+ return ((Fl_Input*)widget)->value ();
+}
+
+void FltkEntryResource::setText (const char *text)
+{
+ if (initText)
+ free((char *)initText);
+ initText = strdup (text);
+
+ ((Fl_Input*)widget)->value (initText);
+}
+
+bool FltkEntryResource::isEditable ()
+{
+ return editable;
+}
+
+void FltkEntryResource::setEditable (bool editable)
+{
+ this->editable = editable;
+}
+
+void FltkEntryResource::setMaxLength (int maxlen)
+{
+ ((Fl_Input *)widget)->maximum_size(maxlen);
+}
+
+// ----------------------------------------------------------------------
+
+static int kf_backspace_word (int c, Fl_Text_Editor *e)
+{
+ int p1, p2 = e->insert_position();
+
+ e->previous_word();
+ p1 = e->insert_position();
+ e->buffer()->remove(p1, p2);
+ e->show_insert_position();
+ e->set_changed();
+ if (e->when() & FL_WHEN_CHANGED)
+ e->do_callback();
+ return 0;
+}
+
+FltkMultiLineTextResource::FltkMultiLineTextResource (FltkPlatform *platform,
+ int cols, int rows):
+ FltkSpecificResource <dw::core::ui::MultiLineTextResource> (platform)
+{
+ buffer = new Fl_Text_Buffer;
+ text_copy = NULL;
+ editable = false;
+
+ numCols = cols;
+ numRows = rows;
+
+ // Check values. Upper bound check is left to the caller.
+ if (numCols < 1) {
+ MSG_WARN("numCols = %d is set to 1.\n", numCols);
+ numCols = 1;
+ }
+ if (numRows < 1) {
+ MSG_WARN("numRows = %d is set to 1.\n", numRows);
+ numRows = 1;
+ }
+
+ init (platform);
+}
+
+FltkMultiLineTextResource::~FltkMultiLineTextResource ()
+{
+ /* Free memory avoiding a double-free of text buffers */
+ ((Fl_Text_Editor *) widget)->buffer (0);
+ delete buffer;
+ if (text_copy)
+ free(text_copy);
+}
+
+Fl_Widget *FltkMultiLineTextResource::createNewWidget (core::Allocation
+ *allocation)
+{
+ Fl_Text_Editor *text =
+ new Fl_Text_Editor (allocation->x, allocation->y, allocation->width,
+ allocation->ascent + allocation->descent);
+ text->wrap_mode(Fl_Text_Display::WRAP_AT_BOUNDS, 0);
+ text->buffer (buffer);
+ text->remove_key_binding(FL_BackSpace, FL_TEXT_EDITOR_ANY_STATE);
+ text->add_key_binding(FL_BackSpace, 0, Fl_Text_Editor::kf_backspace);
+ text->add_key_binding(FL_BackSpace, FL_CTRL, kf_backspace_word);
+ return text;
+}
+
+void FltkMultiLineTextResource::setWidgetStyle (Fl_Widget *widget,
+ core::style::Style *style)
+{
+ Fl_Text_Editor *ed = (Fl_Text_Editor *)widget;
+
+ FltkResource::setWidgetStyle(widget, style);
+
+ ed->textcolor(widget->labelcolor());
+ ed->cursor_color(ed->textcolor());
+ ed->textsize(ed->labelsize());
+ ed->textfont(ed->labelfont());
+}
+
+void FltkMultiLineTextResource::sizeRequest (core::Requisition *requisition)
+{
+ DBG_OBJ_ENTER0 ("resize", 0, "sizeRequest");
+
+ if (style) {
+ FltkFont *font = (FltkFont*)style->font;
+ fl_font(font->font,font->size);
+ // WORKAROUND: A bug with fl_width(uint_t) on non-xft X was present in
+ // 1.3.0 (STR #2688).
+ requisition->width =
+ (int)fl_width ("n") * numCols + 2 * RELIEF_X_THICKNESS;
+ requisition->ascent =
+ RELIEF_Y_THICKNESS + font->ascent +
+ (font->ascent + font->descent) * (numRows - 1);
+ requisition->descent =
+ font->descent +
+ RELIEF_Y_THICKNESS;
+ } else {
+ requisition->width = 1;
+ requisition->ascent = 1;
+ requisition->descent = 0;
+ }
+
+ DBG_OBJ_MSGF ("resize", 1, "result: %d * (%d + %d)",
+ requisition->width, requisition->ascent, requisition->descent);
+ DBG_OBJ_LEAVE ();
+}
+
+const char *FltkMultiLineTextResource::getText ()
+{
+ /* FLTK-1.3 insists upon returning a new copy of the buffer text, so
+ * we have to keep track of it.
+ */
+ if (text_copy)
+ free(text_copy);
+ text_copy = buffer->text();
+ return text_copy;
+}
+
+void FltkMultiLineTextResource::setText (const char *text)
+{
+ buffer->text (text);
+}
+
+bool FltkMultiLineTextResource::isEditable ()
+{
+ return editable;
+}
+
+void FltkMultiLineTextResource::setEditable (bool editable)
+{
+ this->editable = editable;
+}
+
+// ----------------------------------------------------------------------
+
+template <class I>
+FltkToggleButtonResource<I>::FltkToggleButtonResource (FltkPlatform *platform,
+ bool activated):
+ FltkSpecificResource <I> (platform)
+{
+ initActivated = activated;
+}
+
+
+template <class I>
+FltkToggleButtonResource<I>::~FltkToggleButtonResource ()
+{
+}
+
+
+template <class I>
+Fl_Widget *FltkToggleButtonResource<I>::createNewWidget (core::Allocation
+ *allocation)
+{
+ Fl_Button *button = createNewButton (allocation);
+ button->value (initActivated);
+ return button;
+}
+
+template <class I>
+void FltkToggleButtonResource<I>::setWidgetStyle (Fl_Widget *widget,
+ core::style::Style *style)
+{
+ FltkResource::setWidgetStyle(widget, style);
+
+ widget->selection_color(FL_BLACK);
+}
+
+
+template <class I>
+void FltkToggleButtonResource<I>::sizeRequest (core::Requisition *requisition)
+{
+ DBG_OBJ_ENTER0 ("resize", 0, "sizeRequest");
+
+ FltkFont *font = (FltkFont *)
+ (this->FltkResource::style ? this->FltkResource::style->font : NULL);
+
+ if (font) {
+ fl_font(font->font, font->size);
+ requisition->width = font->ascent + font->descent + 2*RELIEF_X_THICKNESS;
+ requisition->ascent = font->ascent + RELIEF_Y_THICKNESS;
+ requisition->descent = font->descent + RELIEF_Y_THICKNESS;
+ } else {
+ requisition->width = 1;
+ requisition->ascent = 1;
+ requisition->descent = 0;
+ }
+
+ DBG_OBJ_MSGF ("resize", 1, "result: %d * (%d + %d)",
+ requisition->width, requisition->ascent, requisition->descent);
+ DBG_OBJ_LEAVE ();
+}
+
+
+template <class I>
+bool FltkToggleButtonResource<I>::isActivated ()
+{
+ return ((Fl_Button*)this->widget)->value ();
+}
+
+
+template <class I>
+void FltkToggleButtonResource<I>::setActivated (bool activated)
+{
+ initActivated = activated;
+ ((Fl_Button*)this->widget)->value (initActivated);
+}
+
+// ----------------------------------------------------------------------
+
+FltkCheckButtonResource::FltkCheckButtonResource (FltkPlatform *platform,
+ bool activated):
+ FltkToggleButtonResource<dw::core::ui::CheckButtonResource> (platform,
+ activated)
+{
+ init (platform);
+}
+
+
+FltkCheckButtonResource::~FltkCheckButtonResource ()
+{
+}
+
+
+Fl_Button *FltkCheckButtonResource::createNewButton (core::Allocation
+ *allocation)
+{
+ Fl_Check_Button *cb =
+ new Fl_Check_Button (allocation->x, allocation->y, allocation->width,
+ allocation->ascent + allocation->descent);
+ return cb;
+}
+
+// ----------------------------------------------------------------------
+
+bool FltkRadioButtonResource::Group::FltkGroupIterator::hasNext ()
+{
+ return it.hasNext ();
+}
+
+dw::core::ui::RadioButtonResource
+*FltkRadioButtonResource::Group::FltkGroupIterator::getNext ()
+{
+ return (dw::core::ui::RadioButtonResource*)it.getNext ();
+}
+
+void FltkRadioButtonResource::Group::FltkGroupIterator::unref ()
+{
+ delete this;
+}
+
+
+FltkRadioButtonResource::Group::Group (FltkRadioButtonResource
+ *radioButtonResource)
+{
+ list = new lout::container::typed::List <FltkRadioButtonResource> (false);
+ connect (radioButtonResource);
+}
+
+FltkRadioButtonResource::Group::~Group ()
+{
+ delete list;
+}
+
+void FltkRadioButtonResource::Group::connect (FltkRadioButtonResource
+ *radioButtonResource)
+{
+ list->append (radioButtonResource);
+}
+
+void FltkRadioButtonResource::Group::unconnect (FltkRadioButtonResource
+ *radioButtonResource)
+{
+ list->removeRef (radioButtonResource);
+ if (list->isEmpty ())
+ delete this;
+}
+
+
+FltkRadioButtonResource::FltkRadioButtonResource (FltkPlatform *platform,
+ FltkRadioButtonResource
+ *groupedWith,
+ bool activated):
+ FltkToggleButtonResource<dw::core::ui::RadioButtonResource> (platform,
+ activated)
+{
+ init (platform);
+
+ if (groupedWith) {
+ group = groupedWith->group;
+ group->connect (this);
+ } else
+ group = new Group (this);
+}
+
+
+FltkRadioButtonResource::~FltkRadioButtonResource ()
+{
+ group->unconnect (this);
+}
+
+dw::core::ui::RadioButtonResource::GroupIterator
+*FltkRadioButtonResource::groupIterator ()
+{
+ return group->groupIterator ();
+}
+
+void FltkRadioButtonResource::widgetCallback (Fl_Widget *widget,
+ void *data)
+{
+ if (widget->when () & FL_WHEN_CHANGED)
+ ((FltkRadioButtonResource*)data)->buttonClicked ();
+}
+
+void FltkRadioButtonResource::buttonClicked ()
+{
+ for (Iterator <FltkRadioButtonResource> it = group->iterator ();
+ it.hasNext (); ) {
+ FltkRadioButtonResource *other = it.getNext ();
+ other->setActivated (other == this);
+ }
+}
+
+Fl_Button *FltkRadioButtonResource::createNewButton (core::Allocation
+ *allocation)
+{
+ /*
+ * Groups of Fl_Radio_Button must be added to one Fl_Group, which is
+ * not possible in this context. For this, we do the grouping ourself,
+ * based on FltkRadioButtonResource::Group.
+ *
+ * What we actually need for this, is a widget, which behaves like a
+ * check button, but looks like a radio button. The first depends on the
+ * type, the second on the style. Since the type is simpler to change
+ * than the style, we create a radio button, and then change the type
+ * (instead of creating a check button, and changing the style).
+ */
+
+ Fl_Button *button =
+ new Fl_Round_Button (allocation->x, allocation->y, allocation->width,
+ allocation->ascent + allocation->descent);
+ button->when (FL_WHEN_CHANGED);
+ button->callback (widgetCallback, this);
+ button->type (FL_TOGGLE_BUTTON);
+
+ return button;
+}
+
+// ----------------------------------------------------------------------
+
+template <class I> dw::core::Iterator *
+FltkSelectionResource<I>::iterator (dw::core::Content::Type mask, bool atEnd)
+{
+ /** \bug Implementation. */
+ return new core::EmptyIterator (this->getEmbed (), mask, atEnd);
+}
+
+// ----------------------------------------------------------------------
+
+FltkOptionMenuResource::FltkOptionMenuResource (FltkPlatform *platform):
+ FltkSelectionResource <dw::core::ui::OptionMenuResource> (platform)
+{
+ /* Fl_Menu_ does not like multiple menu items with the same label, and
+ * insert() treats some characters specially unless escaped, so let's
+ * do our own menu handling.
+ */
+ itemsAllocated = 0x10;
+ menu = new Fl_Menu_Item[itemsAllocated];
+ memset(menu, 0, itemsAllocated * sizeof(Fl_Menu_Item));
+ itemsUsed = 1; // menu[0].text == NULL, which is an end-of-menu marker.
+
+ init (platform);
+}
+
+FltkOptionMenuResource::~FltkOptionMenuResource ()
+{
+ for (int i = 0; i < itemsUsed; i++) {
+ if (menu[i].text)
+ free((char *) menu[i].text);
+ }
+ delete[] menu;
+}
+
+void FltkOptionMenuResource::setWidgetStyle (Fl_Widget *widget,
+ core::style::Style *style)
+{
+ Fl_Choice *ch = (Fl_Choice *)widget;
+
+ FltkResource::setWidgetStyle(widget, style);
+
+ ch->textcolor(widget->labelcolor());
+ ch->textfont(ch->labelfont());
+ ch->textsize(ch->labelsize());
+}
+
+Fl_Widget *FltkOptionMenuResource::createNewWidget (core::Allocation
+ *allocation)
+{
+ Fl_Choice *choice =
+ new CustChoice (allocation->x, allocation->y,
+ allocation->width,
+ allocation->ascent + allocation->descent);
+ choice->menu(menu);
+ return choice;
+}
+
+void FltkOptionMenuResource::widgetCallback (Fl_Widget *widget,
+ void *data)
+{
+}
+
+int FltkOptionMenuResource::getMaxItemWidth()
+{
+ int i, max = 0;
+
+ for (i = 0; i < itemsUsed; i++) {
+ int width = 0;
+ const char *str = menu[i].text;
+
+ if (str) {
+ width = fl_width(str);
+ if (width > max)
+ max = width;
+ }
+ }
+ return max;
+}
+
+void FltkOptionMenuResource::sizeRequest (core::Requisition *requisition)
+{
+ DBG_OBJ_ENTER0 ("resize", 0, "sizeRequest");
+
+ if (style) {
+ FltkFont *font = (FltkFont*)style->font;
+ fl_font(font->font, font->size);
+ int maxItemWidth = getMaxItemWidth ();
+ requisition->ascent = font->ascent + RELIEF_Y_THICKNESS;
+ requisition->descent = font->descent + RELIEF_Y_THICKNESS;
+ requisition->width = maxItemWidth
+ + (requisition->ascent + requisition->descent)
+ + 2 * RELIEF_X_THICKNESS;
+ } else {
+ requisition->width = 1;
+ requisition->ascent = 1;
+ requisition->descent = 0;
+ }
+
+ DBG_OBJ_MSGF ("resize", 1, "result: %d * (%d + %d)",
+ requisition->width, requisition->ascent, requisition->descent);
+ DBG_OBJ_LEAVE ();
+}
+
+void FltkOptionMenuResource::enlargeMenu ()
+{
+ Fl_Choice *ch = (Fl_Choice *)widget;
+ int selected = ch->value();
+ Fl_Menu_Item *newMenu;
+
+ itemsAllocated += 0x10;
+ newMenu = new Fl_Menu_Item[itemsAllocated];
+ memcpy(newMenu, menu, itemsUsed * sizeof(Fl_Menu_Item));
+ memset(newMenu + itemsUsed, 0, 0x10 * sizeof(Fl_Menu_Item));
+ delete[] menu;
+ menu = newMenu;
+ ch->menu(menu);
+ ch->value(selected);
+}
+
+Fl_Menu_Item *FltkOptionMenuResource::newItem()
+{
+ Fl_Menu_Item *item;
+
+ if (itemsUsed == itemsAllocated)
+ enlargeMenu();
+
+ item = menu + itemsUsed - 1;
+ itemsUsed++;
+
+ return item;
+}
+
+void FltkOptionMenuResource::addItem (const char *str,
+ bool enabled, bool selected)
+{
+ Fl_Menu_Item *item = newItem();
+
+ item->text = strdup(str);
+
+ if (enabled == false)
+ item->flags = FL_MENU_INACTIVE;
+
+ if (selected)
+ ((Fl_Choice *)widget)->value(item);
+
+ queueResize (true);
+}
+
+void FltkOptionMenuResource::setItem (int index, bool selected)
+{
+ if (selected)
+ ((Fl_Choice *)widget)->value(menu+index);
+}
+
+void FltkOptionMenuResource::pushGroup (const char *name, bool enabled)
+{
+ Fl_Menu_Item *item = newItem();
+
+ item->text = strdup(name);
+
+ if (enabled == false)
+ item->flags = FL_MENU_INACTIVE;
+
+ item->flags |= FL_SUBMENU;
+
+ queueResize (true);
+}
+
+void FltkOptionMenuResource::popGroup ()
+{
+ /* Item with NULL text field closes the submenu */
+ newItem();
+ queueResize (true);
+}
+
+bool FltkOptionMenuResource::isSelected (int index)
+{
+ return index == ((Fl_Choice *)widget)->value();
+}
+
+int FltkOptionMenuResource::getNumberOfItems()
+{
+ return ((Fl_Choice*)widget)->size();
+}
+
+// ----------------------------------------------------------------------
+
+class CustBrowser : public Fl_Browser {
+public:
+ CustBrowser(int x, int y, int w, int h) : Fl_Browser(x, y, w, h) {};
+ int full_width() const;
+ int full_height() const {return Fl_Browser::full_height();}
+ int avg_height() {return size() ? Fl_Browser_::incr_height() : 0;}
+};
+
+/*
+ * Fl_Browser_ has a full_width(), but it has a tendency to contain 0, so...
+ */
+int CustBrowser::full_width() const
+{
+ int max = 0;
+ void *item = item_first();
+
+ while (item) {
+ int w = item_width(item);
+
+ if (w > max)
+ max = w;
+
+ item = item_next(item);
+ }
+ return max;
+}
+
+FltkListResource::FltkListResource (FltkPlatform *platform,
+ core::ui::ListResource::SelectionMode
+ selectionMode, int rowCount):
+ FltkSelectionResource <dw::core::ui::ListResource> (platform),
+ currDepth(0)
+{
+ mode = selectionMode;
+ showRows = rowCount;
+ init (platform);
+}
+
+FltkListResource::~FltkListResource ()
+{
+}
+
+
+Fl_Widget *FltkListResource::createNewWidget (core::Allocation *allocation)
+{
+ CustBrowser *b =
+ new CustBrowser (allocation->x, allocation->y, allocation->width,
+ allocation->ascent + allocation->descent);
+
+ b->type((mode == SELECTION_MULTIPLE) ? FL_MULTI_BROWSER : FL_HOLD_BROWSER);
+ b->callback(widgetCallback, this);
+ b->when(FL_WHEN_CHANGED);
+ b->column_widths(colWidths);
+ b->column_char('\a'); // I just chose a nonprinting character.
+
+ return b;
+}
+
+void FltkListResource::setWidgetStyle (Fl_Widget *widget,
+ core::style::Style *style)
+{
+ Fl_Browser *b = (Fl_Browser *)widget;
+
+ FltkResource::setWidgetStyle(widget, style);
+
+ b->textfont(widget->labelfont());
+ b->textsize(widget->labelsize());
+ b->textcolor(widget->labelcolor());
+
+ colWidths[0] = b->textsize();
+ colWidths[1] = colWidths[0];
+ colWidths[2] = colWidths[0];
+ colWidths[3] = 0;
+}
+
+void FltkListResource::widgetCallback (Fl_Widget *widget, void *data)
+{
+ Fl_Browser *b = (Fl_Browser *) widget;
+
+ if (b->selected(b->value())) {
+ /* If it shouldn't be selectable, deselect it again. It would be nice to
+ * have a less unpleasant way to do this.
+ */
+ const char *inactive_code;
+ if ((inactive_code = strstr(b->text(b->value()), "@N"))) {
+ const char *ignore_codes = strstr(b->text(b->value()), "@.");
+
+ if (inactive_code < ignore_codes)
+ b->select(b->value(), 0);
+ }
+ }
+}
+
+void *FltkListResource::newItem (const char *str, bool enabled, bool selected)
+{
+ Fl_Browser *b = (Fl_Browser *) widget;
+ int index = b->size() + 1;
+ char *label = (char *)malloc(strlen(str) + 1 + currDepth + 4),
+ *s = label;
+
+ memset(s, '\a', currDepth);
+ s += currDepth;
+ if (!enabled) {
+ // FL_INACTIVE_COLOR
+ *s++ = '@';
+ *s++ = 'N';
+ }
+ // ignore further '@' chars
+ *s++ = '@';
+ *s++ = '.';
+
+ strcpy(s, str);
+
+ b->add(label);
+ free(label);
+
+ if (selected) {
+ b->select(index, selected);
+ if (b->type() == FL_HOLD_BROWSER) {
+ /* Left to its own devices, it sometimes has some suboptimal ideas
+ * about how to scroll, and sometimes doesn't seem to show everything
+ * where it thinks it is.
+ */
+ if (index > showRows) {
+ /* bottomline() and middleline() don't work because the widget is
+ * too tiny at this point for the bbox() call in
+ * Fl_Browser::lineposition() to do what one would want.
+ */
+ b->topline(index - showRows + 1);
+ } else {
+ b->topline(1);
+ }
+ }
+ }
+ queueResize (true);
+ return NULL;
+}
+
+void FltkListResource::addItem (const char *str, bool enabled, bool selected)
+{
+ // Fl_Browser_::incr_height() for item height won't do the right thing if
+ // the first item doesn't have anything to it.
+ if (!str || !*str)
+ str = " ";
+ newItem(str, enabled, selected);
+}
+
+void FltkListResource::setItem (int index, bool selected)
+{
+ Fl_Browser *b = (Fl_Browser *) widget;
+
+ b->select(index + 1, selected);
+}
+
+void FltkListResource::pushGroup (const char *name, bool enabled)
+{
+ bool en = false;
+ bool selected = false;
+
+ // Fl_Browser_::incr_height() for item height won't do the right thing if
+ // the first item doesn't have anything to it.
+ if (!name || !*name)
+ name = " ";
+
+ // TODO: Proper disabling of item groups
+ newItem(name, en, selected);
+
+ if (currDepth < 3)
+ currDepth++;
+}
+
+void FltkListResource::popGroup ()
+{
+ CustBrowser *b = (CustBrowser *) widget;
+
+ newItem(" ", false, false);
+ b->hide(b->size());
+
+ if (currDepth)
+ currDepth--;
+}
+
+int FltkListResource::getMaxItemWidth()
+{
+ return ((CustBrowser *) widget)->full_width();
+}
+
+void FltkListResource::sizeRequest (core::Requisition *requisition)
+{
+ DBG_OBJ_ENTER0 ("resize", 0, "sizeRequest");
+
+ if (style) {
+ CustBrowser *b = (CustBrowser *) widget;
+ int height = b->full_height();
+ requisition->width = getMaxItemWidth() + 4;
+
+ if (showRows * b->avg_height() < height) {
+ height = showRows * b->avg_height();
+ b->has_scrollbar(Fl_Browser_::VERTICAL_ALWAYS);
+ requisition->width += Fl::scrollbar_size();
+ } else {
+ b->has_scrollbar(0);
+ }
+
+ requisition->descent = style->font->descent + 2;
+ requisition->ascent = height - style->font->descent + 2;
+ } else {
+ requisition->width = 1;
+ requisition->ascent = 1;
+ requisition->descent = 0;
+ }
+
+ DBG_OBJ_MSGF ("resize", 1, "result: %d * (%d + %d)",
+ requisition->width, requisition->ascent, requisition->descent);
+ DBG_OBJ_LEAVE ();
+}
+
+int FltkListResource::getNumberOfItems()
+{
+ return ((Fl_Browser*)widget)->size();
+}
+
+bool FltkListResource::isSelected (int index)
+{
+ Fl_Browser *b = (Fl_Browser *) widget;
+
+ return b->selected(index + 1) ? true : false;
+}
+
+} // namespace ui
+} // namespace fltk
+} // namespace dw
+
diff --git a/dw/fltkui.hh b/dw/fltkui.hh
new file mode 100644
index 0000000..fa47992
--- /dev/null
+++ b/dw/fltkui.hh
@@ -0,0 +1,505 @@
+#ifndef __DW_FLTK_UI_HH__
+#define __DW_FLTK_UI_HH__
+
+#ifndef __INCLUDED_FROM_DW_FLTK_CORE_HH__
+# error Do not include this file directly, use "fltkcore.hh" instead.
+#endif
+
+#include <FL/Fl_Button.H>
+#include <FL/Fl_Menu.H>
+#include <FL/Fl_Text_Buffer.H>
+
+namespace dw {
+namespace fltk {
+
+/**
+ * \brief FLTK implementation of dw::core::ui.
+ *
+ * <div style="border: 2px solid #ff0000; margin-top: 0.5em;
+ * margin-bottom: 0.5em; padding: 0.5em 1em;
+ * background-color: #ffefe0"><b>Update:</b> The complicated design
+ * results from my insufficient knowledge of C++ some years ago; since
+ * then, I've learned how to deal with "diamond inheritance", as the
+ * (ideal, not actually implemented) design in the first diagram
+ * shows. It should be possible to implement this ideal design in a
+ * straightforward way, and so get rid of templates. --SG</div>
+ *
+ * The design should be like this:
+ *
+ * \dot
+ * digraph G {
+ * node [shape=record, fontname=Helvetica, fontsize=10];
+ * edge [arrowhead="none", arrowtail="empty", dir="both",
+ * labelfontname=Helvetica, labelfontsize=10, color="#404040",
+ * labelfontcolor="#000080"];
+ * fontname=Helvetica; fontsize=10;
+ *
+ * subgraph cluster_core {
+ * style="dashed"; color="#000080"; fontname=Helvetica; fontsize=10;
+ * label="dw::core::ui";
+ *
+ * Resource [color="#a0a0a0", URL="\ref dw::core::ui::Resource"];
+ * LabelButtonResource [color="#a0a0a0",
+ * URL="\ref dw::core::ui::LabelButtonResource"];
+ * EntryResource [color="#a0a0a0",
+ * URL="\ref dw::core::ui::EntryResource"];
+ * }
+ *
+ * subgraph cluster_fltk {
+ * style="dashed"; color="#000080"; fontname=Helvetica; fontsize=10;
+ * label="dw::fltk::ui";
+ *
+ * FltkResource [color="#a0a0a0", URL="\ref dw::fltk::ui::FltkResource"];
+ * FltkLabelButtonResource
+ * [URL="\ref dw::fltk::ui::FltkLabelButtonResource"];
+ * FltkEntryResource [URL="\ref dw::fltk::ui::FltkEntryResource"];
+ * }
+ *
+ * Resource -> LabelButtonResource;
+ * Resource -> EntryResource;
+ * FltkResource -> FltkLabelButtonResource;
+ * FltkResource -> FltkEntryResource;
+ * Resource -> FltkResource;
+ * LabelButtonResource -> FltkLabelButtonResource;
+ * EntryResource -> FltkEntryResource;
+ * }
+ * \enddot
+ *
+ * <center>[\ref uml-legend "legend"]</center>
+ *
+ * where dw::fltk::ui::FltkResource provides some base funtionality for all
+ * conctrete FLTK implementations of sub-interfaces of dw::core::ui::Resource.
+ * However, this is not directly possible in C++, since the base class
+ * dw::core::ui::Resource is ambiguous for
+ * dw::fltk::ui::FltkLabelButtonResource.
+ *
+ * To solve this, we have to remove the dependency between
+ * dw::fltk::ui::FltkResource and dw::core::ui::Resource, instead, the part
+ * of dw::core::ui::Resource, which is implemented in
+ * dw::fltk::ui::FltkResource, must be explicitly delegated from
+ * dw::fltk::ui::FltkLabelButtonResourceto dw::fltk::ui::FltkResource:
+ *
+ * \dot
+ * digraph G {
+ * node [shape=record, fontname=Helvetica, fontsize=10];
+ * edge [arrowhead="none", arrowtail="empty", dir="both",
+ * labelfontname=Helvetica, labelfontsize=10, color="#404040",
+ * labelfontcolor="#000080"];
+ * fontname=Helvetica; fontsize=10;
+ *
+ * subgraph cluster_core {
+ * style="dashed"; color="#000080"; fontname=Helvetica; fontsize=10;
+ * label="dw::core::ui";
+ *
+ * Resource [color="#a0a0a0", URL="\ref dw::core::ui::Resource"];
+ * LabelButtonResource [color="#a0a0a0",
+ * URL="\ref dw::core::ui::LabelButtonResource"];
+ * EntryResource [color="#a0a0a0",
+ * URL="\ref dw::core::ui::EntryResource"];
+ * }
+ *
+ * subgraph cluster_fltk {
+ * style="dashed"; color="#000080"; fontname=Helvetica; fontsize=10;
+ * label="dw::fltk::ui";
+ *
+ * FltkResource [color="#a0a0a0", URL="\ref dw::fltk::ui::FltkResource"];
+ * FltkLabelButtonResource
+ * [URL="\ref dw::fltk::ui::FltkLabelButtonResource"];
+ * FltkEntryResource [URL="\ref dw::fltk::ui::FltkEntryResource"];
+ * }
+ *
+ * Resource -> LabelButtonResource;
+ * Resource -> EntryResource;
+ * FltkResource -> FltkLabelButtonResource;
+ * FltkResource -> FltkEntryResource;
+ * LabelButtonResource -> FltkLabelButtonResource;
+ * EntryResource -> FltkEntryResource;
+ * }
+ * \enddot
+ *
+ * <center>[\ref uml-legend "legend"]</center>
+ *
+ * To make this a bit simpler, we use templates:
+ *
+ * \dot
+ * digraph G {
+ * node [shape=record, fontname=Helvetica, fontsize=10];
+ * edge [arrowhead="none", arrowtail="empty", dir="both",
+ * labelfontname=Helvetica, labelfontsize=10, color="#404040",
+ * labelfontcolor="#000080"];
+ * fontname=Helvetica; fontsize=10;
+ *
+ * subgraph cluster_core {
+ * style="dashed"; color="#000080"; fontname=Helvetica; fontsize=10;
+ * label="dw::core::ui";
+ *
+ * Resource [color="#a0a0a0", URL="\ref dw::core::ui::Resource"];
+ * LabelButtonResource [color="#a0a0a0",
+ * URL="\ref dw::core::ui::LabelButtonResource"];
+ * EntryResource [color="#a0a0a0",
+ * URL="\ref dw::core::ui::EntryResource"];
+ * }
+ *
+ * subgraph cluster_fltk {
+ * style="dashed"; color="#000080"; fontname=Helvetica; fontsize=10;
+ * label="dw::fltk::ui";
+ *
+ * FltkResource [color="#a0a0a0", URL="\ref dw::fltk::ui::FltkResource"];
+ * FltkSpecificResource [color="#a0a0a0",
+ * fillcolor="#ffffc0", style="filled"
+ * URL="\ref dw::fltk::ui::FltkSpecificResource"];
+ * FltkSpecificResource_button [color="#a0a0a0",
+ * label="FltkSpecificResource \<LabelButtonResource\>"];
+ * FltkSpecificResource_entry [color="#a0a0a0",
+ * label="FltkSpecificResource \<EntryResource\>"];
+ * FltkEntryResource [URL="\ref dw::fltk::ui::FltkEntryResource"];
+ * FltkLabelButtonResource
+ * [URL="\ref dw::fltk::ui::FltkLabelButtonResource"];
+ * }
+ *
+ * Resource -> LabelButtonResource;
+ * Resource -> EntryResource;
+ * FltkResource -> FltkSpecificResource;
+ * FltkSpecificResource -> FltkSpecificResource_button [arrowhead="open",
+ * arrowtail="none",
+ * dir="both",
+ * style="dashed",
+ * color="#808000"];
+ * FltkSpecificResource -> FltkSpecificResource_entry [arrowhead="open",
+ * arrowtail="none",
+ * dir="both",
+ * style="dashed",
+ * color="#808000"];
+ * LabelButtonResource -> FltkSpecificResource_button;
+ * EntryResource -> FltkSpecificResource_entry;
+ * FltkSpecificResource_button -> FltkLabelButtonResource;
+ * FltkSpecificResource_entry -> FltkEntryResource;
+ * }
+ * \enddot
+ *
+ * <center>[\ref uml-legend "legend"]</center>
+ */
+namespace ui {
+
+/**
+ * ...
+ */
+class FltkResource: public lout::object::Object
+{
+private:
+ bool enabled;
+
+protected:
+ FltkView *view;
+ Fl_Widget *widget;
+ core::Allocation allocation;
+ FltkPlatform *platform;
+
+ core::style::Style *style;
+
+ FltkResource (FltkPlatform *platform);
+ void init (FltkPlatform *platform);
+ virtual Fl_Widget *createNewWidget (core::Allocation *allocation) = 0;
+
+ virtual void setWidgetStyle (Fl_Widget *widget, core::style::Style *style);
+ void setDisplayed (bool displayed);
+ bool displayed();
+public:
+ ~FltkResource ();
+
+ virtual void attachView (FltkView *view);
+ virtual void detachView (FltkView *view);
+
+ void sizeAllocate (core::Allocation *allocation);
+ void draw (core::View *view, core::Rectangle *area);
+
+ void setStyle (core::style::Style *style);
+
+ bool isEnabled ();
+ void setEnabled (bool enabled);
+};
+
+
+template <class I> class FltkSpecificResource: public I, public FltkResource
+{
+public:
+ FltkSpecificResource (FltkPlatform *platform);
+ ~FltkSpecificResource ();
+
+ void sizeAllocate (core::Allocation *allocation);
+ void draw (core::View *view, core::Rectangle *area);
+ void setStyle (core::style::Style *style);
+
+ bool isEnabled ();
+ void setEnabled (bool enabled);
+};
+
+
+class FltkLabelButtonResource:
+ public FltkSpecificResource <dw::core::ui::LabelButtonResource>
+{
+private:
+ const char *label;
+
+ static void widgetCallback (Fl_Widget *widget, void *data);
+
+protected:
+ Fl_Widget *createNewWidget (core::Allocation *allocation);
+
+public:
+ FltkLabelButtonResource (FltkPlatform *platform, const char *label);
+ ~FltkLabelButtonResource ();
+
+ void sizeRequest (core::Requisition *requisition);
+
+ const char *getLabel ();
+ void setLabel (const char *label);
+};
+
+/**
+ * \bug Maximal length not supported yet.
+ * \todo Text values are not synchronized (not needed in dillo).
+ */
+class FltkEntryResource:
+ public FltkSpecificResource <dw::core::ui::EntryResource>
+{
+private:
+ int size;
+ bool password;
+ const char *initText;
+ char *label;
+ int label_w;
+ bool editable;
+
+ static void widgetCallback (Fl_Widget *widget, void *data);
+ void setDisplayed (bool displayed);
+
+protected:
+ Fl_Widget *createNewWidget (core::Allocation *allocation);
+ void setWidgetStyle (Fl_Widget *widget, core::style::Style *style);
+
+public:
+ FltkEntryResource (FltkPlatform *platform, int size, bool password,
+ const char *label);
+ ~FltkEntryResource ();
+
+ void sizeRequest (core::Requisition *requisition);
+ void sizeAllocate (core::Allocation *allocation);
+
+ const char *getText ();
+ void setText (const char *text);
+ bool isEditable ();
+ void setEditable (bool editable);
+ void setMaxLength (int maxlen);
+};
+
+
+class FltkMultiLineTextResource:
+ public FltkSpecificResource <dw::core::ui::MultiLineTextResource>
+{
+private:
+ Fl_Text_Buffer *buffer;
+ char *text_copy;
+ bool editable;
+ int numCols, numRows;
+
+protected:
+ Fl_Widget *createNewWidget (core::Allocation *allocation);
+ void setWidgetStyle (Fl_Widget *widget, core::style::Style *style);
+
+public:
+ FltkMultiLineTextResource (FltkPlatform *platform, int cols, int rows);
+ ~FltkMultiLineTextResource ();
+
+ void sizeRequest (core::Requisition *requisition);
+
+ const char *getText ();
+ void setText (const char *text);
+ bool isEditable ();
+ void setEditable (bool editable);
+};
+
+
+template <class I> class FltkToggleButtonResource:
+ public FltkSpecificResource <I>
+{
+private:
+ bool initActivated;
+
+protected:
+ virtual Fl_Button *createNewButton (core::Allocation *allocation) = 0;
+ Fl_Widget *createNewWidget (core::Allocation *allocation);
+ void setWidgetStyle (Fl_Widget *widget, core::style::Style *style);
+
+public:
+ FltkToggleButtonResource (FltkPlatform *platform,
+ bool activated);
+ ~FltkToggleButtonResource ();
+
+ void sizeRequest (core::Requisition *requisition);
+
+ bool isActivated ();
+ void setActivated (bool activated);
+};
+
+
+class FltkCheckButtonResource:
+ public FltkToggleButtonResource <dw::core::ui::CheckButtonResource>
+{
+protected:
+ Fl_Button *createNewButton (core::Allocation *allocation);
+
+public:
+ FltkCheckButtonResource (FltkPlatform *platform,
+ bool activated);
+ ~FltkCheckButtonResource ();
+};
+
+
+class FltkRadioButtonResource:
+ public FltkToggleButtonResource <dw::core::ui::RadioButtonResource>
+{
+private:
+ class Group
+ {
+ private:
+ class FltkGroupIterator:
+ public dw::core::ui::RadioButtonResource::GroupIterator
+ {
+ private:
+ lout::container::typed::Iterator <FltkRadioButtonResource> it;
+
+ public:
+ inline FltkGroupIterator (lout::container::typed::List
+ <FltkRadioButtonResource>
+ *list)
+ { it = list->iterator (); }
+
+ bool hasNext ();
+ dw::core::ui::RadioButtonResource *getNext ();
+ void unref ();
+ };
+
+ lout::container::typed::List <FltkRadioButtonResource> *list;
+
+ protected:
+ ~Group ();
+
+ public:
+ Group (FltkRadioButtonResource *radioButtonResource);
+
+ inline lout::container::typed::Iterator <FltkRadioButtonResource>
+ iterator ()
+ {
+ return list->iterator ();
+ }
+
+ inline dw::core::ui::RadioButtonResource::GroupIterator
+ *groupIterator ()
+ {
+ return new FltkGroupIterator (list);
+ }
+
+ void connect (FltkRadioButtonResource *radioButtonResource);
+ void unconnect (FltkRadioButtonResource *radioButtonResource);
+ };
+
+ Group *group;
+
+ static void widgetCallback (Fl_Widget *widget, void *data);
+ void buttonClicked ();
+
+protected:
+ Fl_Button *createNewButton (core::Allocation *allocation);
+
+public:
+ FltkRadioButtonResource (FltkPlatform *platform,
+ FltkRadioButtonResource *groupedWith,
+ bool activated);
+ ~FltkRadioButtonResource ();
+
+ GroupIterator *groupIterator ();
+};
+
+
+template <class I> class FltkSelectionResource:
+ public FltkSpecificResource <I>
+{
+protected:
+ virtual bool setSelectedItems() { return false; }
+ virtual void addItem (const char *str, bool enabled, bool selected) = 0;
+ virtual void setItem (int index, bool selected) = 0;
+ virtual void pushGroup (const char *name, bool enabled) = 0;
+ virtual void popGroup () = 0;
+public:
+ FltkSelectionResource (FltkPlatform *platform) :
+ FltkSpecificResource<I> (platform) {};
+ dw::core::Iterator *iterator (dw::core::Content::Type mask, bool atEnd);
+};
+
+
+class FltkOptionMenuResource:
+ public FltkSelectionResource <dw::core::ui::OptionMenuResource>
+{
+protected:
+ Fl_Widget *createNewWidget (core::Allocation *allocation);
+ virtual bool setSelectedItems() { return true; }
+ void setWidgetStyle (Fl_Widget *widget, core::style::Style *style);
+ int getNumberOfItems();
+ int getMaxItemWidth ();
+private:
+ static void widgetCallback (Fl_Widget *widget, void *data);
+ void enlargeMenu();
+ Fl_Menu_Item *newItem();
+ Fl_Menu_Item *menu;
+ int itemsAllocated, itemsUsed;
+public:
+ FltkOptionMenuResource (FltkPlatform *platform);
+ ~FltkOptionMenuResource ();
+
+ void addItem (const char *str, bool enabled, bool selected);
+ void setItem (int index, bool selected);
+ void pushGroup (const char *name, bool enabled);
+ void popGroup ();
+
+ void sizeRequest (core::Requisition *requisition);
+ bool isSelected (int index);
+};
+
+class FltkListResource:
+ public FltkSelectionResource <dw::core::ui::ListResource>
+{
+protected:
+ Fl_Widget *createNewWidget (core::Allocation *allocation);
+ void setWidgetStyle (Fl_Widget *widget, core::style::Style *style);
+ int getNumberOfItems();
+ int getMaxItemWidth ();
+private:
+ static void widgetCallback (Fl_Widget *widget, void *data);
+ void *newItem (const char *str, bool enabled, bool selected);
+ int currDepth;
+ int colWidths[4];
+ int showRows;
+ ListResource::SelectionMode mode;
+public:
+ FltkListResource (FltkPlatform *platform,
+ core::ui::ListResource::SelectionMode selectionMode,
+ int rows);
+ ~FltkListResource ();
+
+ void addItem (const char *str, bool enabled, bool selected);
+ void setItem (int index, bool selected);
+ void pushGroup (const char *name, bool enabled);
+ void popGroup ();
+
+ void sizeRequest (core::Requisition *requisition);
+ bool isSelected (int index);
+};
+
+
+} // namespace ui
+} // namespace fltk
+} // namespace dw
+
+
+#endif // __DW_FLTK_UI_HH__
diff --git a/dw/fltkviewbase.cc b/dw/fltkviewbase.cc
new file mode 100644
index 0000000..3b1c0cc
--- /dev/null
+++ b/dw/fltkviewbase.cc
@@ -0,0 +1,744 @@
+/*
+ * RTFL (originally part of dillo)
+ *
+ * Copyright 2005-2007 Sebastian Geerken <sgeerken@dillo.org>
+ *
+ * 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; with the following exception:
+ *
+ * The copyright holders of RTFL give you permission to link this file
+ * statically or dynamically against all versions of the graphviz
+ * library, which are published by AT&T Corp. under one of the following
+ * licenses:
+ *
+ * - Common Public License version 1.0 as published by International
+ * Business Machines Corporation (IBM), or
+ * - Eclipse Public License version 1.0 as published by the Eclipse
+ * Foundation.
+ *
+ * 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/>.
+ */
+
+
+
+#include "fltkviewport.hh"
+
+#include <FL/Fl.H>
+#include <FL/fl_draw.H>
+
+#include <stdio.h>
+#include "../lout/msg.h"
+
+extern Fl_Widget* fl_oldfocus;
+
+using namespace lout::object;
+using namespace lout::container::typed;
+
+namespace dw {
+namespace fltk {
+
+FltkViewBase::BackBuffer::BackBuffer ()
+{
+ w = 0;
+ h = 0;
+ created = false;
+}
+
+FltkViewBase::BackBuffer::~BackBuffer ()
+{
+ if (created)
+ fl_delete_offscreen (offscreen);
+}
+
+void FltkViewBase::BackBuffer::setSize (int w, int h)
+{
+ if (!created || w > this->w || h > this->h) {
+ this->w = w;
+ this->h = h;
+ if (created)
+ fl_delete_offscreen (offscreen);
+ offscreen = fl_create_offscreen (w, h);
+ created = true;
+ }
+}
+
+FltkViewBase::BackBuffer *FltkViewBase::backBuffer;
+bool FltkViewBase::backBufferInUse;
+
+FltkViewBase::FltkViewBase (int x, int y, int w, int h, const char *label):
+ Fl_Group (x, y, w, h, label)
+{
+ Fl_Group::current(0);
+ canvasWidth = 1;
+ canvasHeight = 1;
+ bgColor = FL_WHITE;
+ mouse_x = mouse_y = 0;
+ focused_child = NULL;
+ exposeArea = NULL;
+ if (backBuffer == NULL) {
+ backBuffer = new BackBuffer ();
+ }
+ box(FL_NO_BOX);
+ resizable(NULL);
+}
+
+FltkViewBase::~FltkViewBase ()
+{
+ cancelQueueDraw ();
+}
+
+void FltkViewBase::setBufferedDrawing (bool b) {
+ if (b && backBuffer == NULL) {
+ backBuffer = new BackBuffer ();
+ } else if (!b && backBuffer != NULL) {
+ delete backBuffer;
+ backBuffer = NULL;
+ }
+}
+
+void FltkViewBase::draw ()
+{
+ int d = damage ();
+
+ if ((d & FL_DAMAGE_USER1) && !(d & FL_DAMAGE_EXPOSE)) {
+ lout::container::typed::Iterator <core::Rectangle> it;
+
+ for (it = drawRegion.rectangles (); it.hasNext (); ) {
+ draw (it.getNext (), DRAW_BUFFERED);
+ }
+
+ drawRegion.clear ();
+ d &= ~FL_DAMAGE_USER1;
+ }
+
+ if (d & FL_DAMAGE_CHILD) {
+ drawChildWidgets ();
+ d &= ~FL_DAMAGE_CHILD;
+ }
+
+ if (d) {
+ dw::core::Rectangle rect (
+ translateViewXToCanvasX (x ()),
+ translateViewYToCanvasY (y ()),
+ w (),
+ h ());
+
+ if (d == FL_DAMAGE_SCROLL) {
+ // a clipping rectangle has already been set by fltk::scrollrect ()
+ draw (&rect, DRAW_PLAIN);
+ } else {
+ draw (&rect, DRAW_CLIPPED);
+ drawRegion.clear ();
+ }
+ }
+}
+
+void FltkViewBase::draw (const core::Rectangle *rect,
+ DrawType type)
+{
+ int X = translateCanvasXToViewX (rect->x);
+ int Y = translateCanvasYToViewY (rect->y);
+ int W, H;
+
+ // fl_clip_box() can't handle values greater than SHRT_MAX!
+ if (X > x () + w () || Y > y () + h ())
+ return;
+
+ W = X + rect->width > x () + w () ? x () + w () - X : rect->width;
+ H = Y + rect->height > y () + h () ? y () + h () - Y : rect->height;
+
+ fl_clip_box(X, Y, W, H, X, Y, W, H);
+
+ core::Rectangle r (translateViewXToCanvasX (X),
+ translateViewYToCanvasY (Y), W, H);
+
+ if (r.isEmpty ())
+ return;
+
+ exposeArea = &r;
+
+ if (type == DRAW_BUFFERED && backBuffer && !backBufferInUse) {
+ backBufferInUse = true;
+ backBuffer->setSize (X + W, Y + H); // would be nicer to use (W, H)...
+ fl_begin_offscreen (backBuffer->offscreen);
+ fl_push_matrix ();
+ fl_color (bgColor);
+ fl_rectf (X, Y, W, H);
+ theLayout->expose (this, &r);
+ fl_pop_matrix ();
+ fl_end_offscreen ();
+ fl_copy_offscreen (X, Y, W, H, backBuffer->offscreen, X, Y);
+ backBufferInUse = false;
+ } else if (type == DRAW_BUFFERED || type == DRAW_CLIPPED) {
+ // if type == DRAW_BUFFERED but we do not have backBuffer available
+ // we fall back to clipped drawing
+ fl_push_clip (X, Y, W, H);
+ fl_color (bgColor);
+ fl_rectf (X, Y, W, H);
+ theLayout->expose (this, &r);
+ fl_pop_clip ();
+ } else {
+ fl_color (bgColor);
+ fl_rectf (X, Y, W, H);
+ theLayout->expose (this, &r);
+ }
+ // DEBUG:
+ //fl_color(FL_RED);
+ //fl_rect(X, Y, W, H);
+
+ exposeArea = NULL;
+}
+
+void FltkViewBase::drawChildWidgets () {
+ for (int i = children () - 1; i >= 0; i--) {
+ Fl_Widget& w = *child(i);
+#if 0
+PORT1.3
+ if (w.damage() & DAMAGE_CHILD_LABEL) {
+ draw_outside_label(w);
+ w.set_damage(w.damage() & ~DAMAGE_CHILD_LABEL);
+ }
+#endif
+ update_child(w);
+ }
+}
+
+core::ButtonState getDwButtonState ()
+{
+ int s1 = Fl::event_state ();
+ int s2 = (core::ButtonState)0;
+
+ if (s1 & FL_SHIFT) s2 |= core::SHIFT_MASK;
+ if (s1 & FL_CTRL) s2 |= core::CONTROL_MASK;
+ if (s1 & FL_ALT) s2 |= core::META_MASK;
+ if (s1 & FL_BUTTON1) s2 |= core::BUTTON1_MASK;
+ if (s1 & FL_BUTTON2) s2 |= core::BUTTON2_MASK;
+ if (s1 & FL_BUTTON3) s2 |= core::BUTTON3_MASK;
+
+ return (core::ButtonState)s2;
+}
+
+/*
+ * We handle Tab to determine which FLTK widget should get focus.
+ *
+ * Presumably a proper solution that allows focusing links, etc., would live
+ * in Textblock and use iterators.
+ */
+int FltkViewBase::manageTabToFocus()
+{
+ int i, ret = 0;
+ Fl_Widget *old_child = NULL;
+
+ if (this == Fl::focus()) {
+ // if we have focus, give it to a child. Go forward typically,
+ // or backward with Shift pressed.
+ if (!(Fl::event_state() & FL_SHIFT)) {
+ for (i = 0; i < children(); i++) {
+ if (child(i)->take_focus()) {
+ ret = 1;
+ break;
+ }
+ }
+ } else {
+ for (i = children() - 1; i >= 0; i--) {
+ if (child(i)->take_focus()) {
+ ret = 1;
+ break;
+ }
+ }
+ }
+ } else {
+ // tabbing between children
+ old_child = Fl::focus();
+
+ if (!(ret = Fl_Group::handle (FL_KEYBOARD))) {
+ // group didn't have any more children to focus.
+ Fl::focus(this);
+ return 1;
+ } else {
+ // which one did it focus? (Note i == children() if not found)
+ i = find(Fl::focus());
+ }
+ }
+ if (ret) {
+ if (i >= 0 && i < children()) {
+ Fl_Widget *c = child(i);
+ int canvasX = translateViewXToCanvasX(c->x()),
+ canvasY = translateViewYToCanvasY(c->y());
+
+ theLayout->scrollTo(core::HPOS_INTO_VIEW, core::VPOS_INTO_VIEW,
+ canvasX, canvasY, c->w(), c->h());
+
+ // Draw the children who gained and lost focus. Otherwise a
+ // widget that had been only partly visible still shows its old
+ // appearance in the previously-visible portion.
+ core::Rectangle r(canvasX, canvasY, c->w(), c->h());
+
+ queueDraw(&r);
+
+ if (old_child) {
+ r.x = translateViewXToCanvasX(old_child->x());
+ r.y = translateViewYToCanvasY(old_child->y());
+ r.width = old_child->w();
+ r.height = old_child->h();
+ queueDraw(&r);
+ }
+ }
+ }
+ return ret;
+}
+
+int FltkViewBase::handle (int event)
+{
+ bool processed;
+
+ /**
+ * \todo Consider, whether this from the FLTK documentation has any
+ * impacts: "To receive fltk::RELEASE events you must return non-zero
+ * when passed a fltk::PUSH event. "
+ */
+ switch(event) {
+ case FL_PUSH:
+ /* Hide the tooltip */
+ theLayout->cancelTooltip();
+
+ processed =
+ theLayout->buttonPress (this, Fl::event_clicks () + 1,
+ translateViewXToCanvasX (Fl::event_x ()),
+ translateViewYToCanvasY (Fl::event_y ()),
+ getDwButtonState (), Fl::event_button ());
+ _MSG("PUSH => %s\n", processed ? "true" : "false");
+ if (processed) {
+ /* pressed dw content; give focus to the view */
+ if (Fl::event_button() != FL_RIGHT_MOUSE)
+ Fl::focus(this);
+ return true;
+ }
+ break;
+ case FL_RELEASE:
+ processed =
+ theLayout->buttonRelease (this, Fl::event_clicks () + 1,
+ translateViewXToCanvasX (Fl::event_x ()),
+ translateViewYToCanvasY (Fl::event_y ()),
+ getDwButtonState (), Fl::event_button ());
+ _MSG("RELEASE => %s\n", processed ? "true" : "false");
+ if (processed)
+ return true;
+ break;
+ case FL_MOVE:
+ mouse_x = Fl::event_x();
+ mouse_y = Fl::event_y();
+ processed =
+ theLayout->motionNotify (this,
+ translateViewXToCanvasX (mouse_x),
+ translateViewYToCanvasY (mouse_y),
+ getDwButtonState ());
+ _MSG("MOVE => %s\n", processed ? "true" : "false");
+ if (processed)
+ return true;
+ break;
+ case FL_DRAG:
+ processed =
+ theLayout->motionNotify (this,
+ translateViewXToCanvasX (Fl::event_x ()),
+ translateViewYToCanvasY (Fl::event_y ()),
+ getDwButtonState ());
+ _MSG("DRAG => %s\n", processed ? "true" : "false");
+ if (processed)
+ return true;
+ break;
+ case FL_ENTER:
+ theLayout->enterNotify (this,
+ translateViewXToCanvasX (Fl::event_x ()),
+ translateViewYToCanvasY (Fl::event_y ()),
+ getDwButtonState ());
+ break;
+ case FL_HIDE:
+ /* WORKAROUND: strangely, the tooltip window is not automatically hidden
+ * with its parent. Here we fake a LEAVE to achieve it. */
+ case FL_LEAVE:
+ theLayout->leaveNotify (this, getDwButtonState ());
+ break;
+ case FL_FOCUS:
+ if (focused_child && find(focused_child) < children()) {
+ /* strangely, find() == children() if the child is not found */
+ focused_child->take_focus();
+ }
+ return 1;
+ case FL_UNFOCUS:
+ focused_child = fl_oldfocus;
+ return 0;
+ case FL_KEYBOARD:
+ if (Fl::event_key() == FL_Tab)
+ return manageTabToFocus();
+ break;
+ default:
+ break;
+ }
+ return Fl_Group::handle (event);
+}
+
+// ----------------------------------------------------------------------
+
+void FltkViewBase::setLayout (core::Layout *layout)
+{
+ theLayout = layout;
+ if (usesViewport())
+ theLayout->viewportSizeChanged(this, w(), h());
+}
+
+void FltkViewBase::setCanvasSize (int width, int ascent, int descent)
+{
+ canvasWidth = width;
+ canvasHeight = ascent + descent;
+}
+
+void FltkViewBase::setCursor (core::style::Cursor cursor)
+{
+ static Fl_Cursor mapDwToFltk[] = {
+ FL_CURSOR_CROSS,
+ FL_CURSOR_DEFAULT,
+ FL_CURSOR_HAND,
+ FL_CURSOR_MOVE,
+ FL_CURSOR_WE,
+ FL_CURSOR_NESW,
+ FL_CURSOR_NWSE,
+ FL_CURSOR_NS,
+ FL_CURSOR_NWSE,
+ FL_CURSOR_NESW,
+ FL_CURSOR_NS,
+ FL_CURSOR_WE,
+ FL_CURSOR_INSERT,
+ FL_CURSOR_WAIT,
+ FL_CURSOR_HELP
+ };
+
+ fl_cursor (mapDwToFltk[cursor]);
+}
+
+void FltkViewBase::setBgColor (core::style::Color *color)
+{
+ bgColor = color ?
+ ((FltkColor*)color)->colors[dw::core::style::Color::SHADING_NORMAL] :
+ FL_WHITE;
+}
+
+void FltkViewBase::startDrawing (core::Rectangle *area)
+{
+}
+
+void FltkViewBase::finishDrawing (core::Rectangle *area)
+{
+}
+
+void FltkViewBase::queueDraw (core::Rectangle *area)
+{
+ drawRegion.addRectangle (area);
+ damage (FL_DAMAGE_USER1);
+}
+
+void FltkViewBase::queueDrawTotal ()
+{
+ damage (FL_DAMAGE_EXPOSE);
+}
+
+void FltkViewBase::cancelQueueDraw ()
+{
+}
+
+void FltkViewBase::drawPoint (core::style::Color *color,
+ core::style::Color::Shading shading,
+ int x, int y)
+{
+}
+
+void FltkViewBase::drawLine (core::style::Color *color,
+ core::style::Color::Shading shading,
+ int x1, int y1, int x2, int y2)
+{
+ fl_color(((FltkColor*)color)->colors[shading]);
+ // we clip with a large border (5000px), as clipping causes artefacts
+ // with non-solid line styles.
+ // However it's still better than no clipping at all.
+ clipPoint (&x1, &y1, 5000);
+ clipPoint (&x2, &y2, 5000);
+ fl_line (translateCanvasXToViewX (x1),
+ translateCanvasYToViewY (y1),
+ translateCanvasXToViewX (x2),
+ translateCanvasYToViewY (y2));
+}
+
+void FltkViewBase::drawTypedLine (core::style::Color *color,
+ core::style::Color::Shading shading,
+ core::style::LineType type, int width,
+ int x1, int y1, int x2, int y2)
+{
+ char dashes[3], w, ng, d, gap, len;
+ const int f = 2;
+
+ w = (width == 1) ? 0 : width;
+ if (type == core::style::LINE_DOTTED) {
+ /* customized drawing for dotted lines */
+ len = (x2 == x1) ? y2 - y1 + 1 : (y2 == y1) ? x2 - x1 + 1 : 0;
+ ng = len / f*width;
+ d = len % f*width;
+ gap = ng ? d/ng + (w > 3 ? 2 : 0) : 0;
+ dashes[0] = 1; dashes[1] = f*width-gap; dashes[2] = 0;
+ fl_line_style(FL_DASH + FL_CAP_ROUND, w, dashes);
+
+ /* These formulas also work, but ain't pretty ;)
+ * fl_line_style(FL_DOT + FL_CAP_ROUND, w);
+ * dashes[0] = 1; dashes[1] = 3*width-2; dashes[2] = 0;
+ */
+ } else if (type == core::style::LINE_DASHED) {
+ fl_line_style(FL_DASH + FL_CAP_ROUND, w);
+ }
+
+ fl_color(((FltkColor*)color)->colors[shading]);
+ drawLine (color, shading, x1, y1, x2, y2);
+
+ if (type != core::style::LINE_NORMAL)
+ fl_line_style(FL_SOLID);
+}
+
+void FltkViewBase::drawRectangle (core::style::Color *color,
+ core::style::Color::Shading shading,
+ bool filled,
+ int X, int Y, int width, int height)
+{
+ fl_color(((FltkColor*)color)->colors[shading]);
+ if (width < 0) {
+ X += width;
+ width = -width;
+ }
+ if (height < 0) {
+ Y += height;
+ height = -height;
+ }
+
+ int x1 = X;
+ int y1 = Y;
+ int x2 = X + width;
+ int y2 = Y + height;
+
+ // We only support rectangles with line width 1px, so we clip with
+ // a rectangle 1px wider and higher than what we actually expose.
+ // This is only really necessary for non-filled rectangles.
+ clipPoint (&x1, &y1, 1);
+ clipPoint (&x2, &y2, 1);
+
+ x1 = translateCanvasXToViewX (x1);
+ y1 = translateCanvasYToViewY (y1);
+ x2 = translateCanvasXToViewX (x2);
+ y2 = translateCanvasYToViewY (y2);
+
+ if (filled)
+ fl_rectf (x1, y1, x2 - x1, y2 - y1);
+ else
+ fl_rect (x1, y1, x2 - x1, y2 - y1);
+}
+
+void FltkViewBase::drawArc (core::style::Color *color,
+ core::style::Color::Shading shading, bool filled,
+ int centerX, int centerY, int width, int height,
+ int angle1, int angle2)
+{
+ fl_color(((FltkColor*)color)->colors[shading]);
+ int x = translateCanvasXToViewX (centerX) - width / 2;
+ int y = translateCanvasYToViewY (centerY) - height / 2;
+
+ fl_arc(x, y, width, height, angle1, angle2);
+ if (filled) {
+ // WORKAROUND: We call both fl_arc and fl_pie due to a FLTK bug
+ // (STR #2703) that was present in 1.3.0.
+ fl_pie(x, y, width, height, angle1, angle2);
+ }
+}
+
+void FltkViewBase::drawPolygon (core::style::Color *color,
+ core::style::Color::Shading shading,
+ bool filled, bool convex, core::Point *points,
+ int npoints)
+{
+ if (npoints > 0) {
+ fl_color(((FltkColor*)color)->colors[shading]);
+
+ if (filled) {
+ if (convex)
+ fl_begin_polygon();
+ else
+ fl_begin_complex_polygon();
+ } else
+ fl_begin_loop();
+
+ for (int i = 0; i < npoints; i++) {
+ fl_vertex(translateCanvasXToViewX(points[i].x),
+ translateCanvasYToViewY(points[i].y));
+ }
+ if (filled) {
+ if (convex)
+ fl_end_polygon();
+ else
+ fl_end_complex_polygon();
+ } else
+ fl_end_loop();
+ }
+}
+
+core::View *FltkViewBase::getClippingView (int x, int y, int width, int height)
+{
+ fl_push_clip (translateCanvasXToViewX (x), translateCanvasYToViewY (y),
+ width, height);
+ return this;
+}
+
+void FltkViewBase::mergeClippingView (core::View *clippingView)
+{
+ fl_pop_clip ();
+}
+
+// ----------------------------------------------------------------------
+
+FltkWidgetView::FltkWidgetView (int x, int y, int w, int h,
+ const char *label):
+ FltkViewBase (x, y, w, h, label)
+{
+}
+
+FltkWidgetView::~FltkWidgetView ()
+{
+}
+
+void FltkWidgetView::drawText (core::style::Font *font,
+ core::style::Color *color,
+ core::style::Color::Shading shading,
+ int X, int Y, const char *text, int len)
+{
+ //printf ("drawText (..., %d, %d, '", X, Y);
+ //for (int i = 0; i < len; i++)
+ // putchar (text[i]);
+ //printf ("'\n");
+
+ FltkFont *ff = (FltkFont*)font;
+ fl_font(ff->font, ff->size);
+ fl_color(((FltkColor*)color)->colors[shading]);
+
+ if (!font->letterSpacing && !font->fontVariant) {
+ fl_draw(text, len,
+ translateCanvasXToViewX (X), translateCanvasYToViewY (Y));
+ } else {
+ /* Nonzero letter spacing adjustment, draw each glyph individually */
+ int viewX = translateCanvasXToViewX (X),
+ viewY = translateCanvasYToViewY (Y);
+ int curr = 0, next = 0, nb;
+ char chbuf[4];
+ int c, cu, width;
+
+ if (font->fontVariant == core::style::FONT_VARIANT_SMALL_CAPS) {
+ int sc_fontsize = lout::misc::roundInt(ff->size * 0.78);
+ for (curr = 0; next < len; curr = next) {
+ next = theLayout->nextGlyph(text, curr);
+ c = fl_utf8decode(text + curr, text + next, &nb);
+ if ((cu = fl_toupper(c)) == c) {
+ /* already uppercase, just draw the character */
+ fl_font(ff->font, ff->size);
+ width = (int)fl_width(text + curr, next - curr);
+ if (curr && width)
+ viewX += font->letterSpacing;
+ fl_draw(text + curr, next - curr, viewX, viewY);
+ viewX += width;
+ } else {
+ /* make utf8 string for converted char */
+ nb = fl_utf8encode(cu, chbuf);
+ fl_font(ff->font, sc_fontsize);
+ width = (int)fl_width(chbuf, nb);
+ if (curr && width)
+ viewX += font->letterSpacing;
+ fl_draw(chbuf, nb, viewX, viewY);
+ viewX += width;
+ }
+ }
+ } else {
+ while (next < len) {
+ next = theLayout->nextGlyph(text, curr);
+ width = (int)fl_width(text + curr, next - curr);
+ if (curr && width)
+ viewX += font->letterSpacing;
+ fl_draw(text + curr, next - curr, viewX, viewY);
+ viewX += width;
+ curr = next;
+ }
+ }
+ }
+}
+
+/*
+ * "simple" in that it ignores letter-spacing, etc. This was added for image
+ * alt text where none of that matters.
+ */
+void FltkWidgetView::drawSimpleWrappedText (core::style::Font *font,
+ core::style::Color *color,
+ core::style::Color::Shading shading,
+ int X, int Y, int W, int H,
+ const char *text)
+{
+ FltkFont *ff = (FltkFont*)font;
+ fl_font(ff->font, ff->size);
+ fl_color(((FltkColor*)color)->colors[shading]);
+ fl_draw(text,
+ translateCanvasXToViewX (X), translateCanvasYToViewY (Y),
+ W, H, FL_ALIGN_TOP|FL_ALIGN_LEFT|FL_ALIGN_WRAP, NULL, 0);
+}
+
+void FltkWidgetView::drawImage (core::Imgbuf *imgbuf, int xRoot, int yRoot,
+ int X, int Y, int width, int height)
+{
+ ((FltkImgbuf*)imgbuf)->draw (this,
+ translateCanvasXToViewX (xRoot),
+ translateCanvasYToViewY (yRoot),
+ X, Y, width, height);
+}
+
+bool FltkWidgetView::usesFltkWidgets ()
+{
+ return true;
+}
+
+void FltkWidgetView::addFltkWidget (Fl_Widget *widget,
+ core::Allocation *allocation)
+{
+ allocateFltkWidget (widget, allocation);
+ add (widget);
+}
+
+void FltkWidgetView::removeFltkWidget (Fl_Widget *widget)
+{
+ remove (widget);
+}
+
+void FltkWidgetView::allocateFltkWidget (Fl_Widget *widget,
+ core::Allocation *allocation)
+{
+ widget->resize (translateCanvasXToViewX (allocation->x),
+ translateCanvasYToViewY (allocation->y),
+ allocation->width,
+ allocation->ascent + allocation->descent);
+}
+
+void FltkWidgetView::drawFltkWidget (Fl_Widget *widget,
+ core::Rectangle *area)
+{
+ draw_child (*widget);
+ draw_outside_label(*widget);
+}
+
+} // namespace fltk
+} // namespace dw
diff --git a/dw/fltkviewbase.hh b/dw/fltkviewbase.hh
new file mode 100644
index 0000000..eb4ec32
--- /dev/null
+++ b/dw/fltkviewbase.hh
@@ -0,0 +1,141 @@
+#ifndef __DW_FLTKVIEWBASE_HH__
+#define __DW_FLTKVIEWBASE_HH__
+
+#include <time.h> // for time_t
+#include <sys/time.h> // for time_t in FreeBSD
+
+#include <FL/Fl_Group.H>
+#include <FL/x.H>
+
+#include "fltkcore.hh"
+
+namespace dw {
+namespace fltk {
+
+class FltkViewBase: public FltkView, public Fl_Group
+{
+private:
+ class BackBuffer {
+ private:
+ int w;
+ int h;
+ bool created;
+
+ public:
+ Fl_Offscreen offscreen;
+
+ BackBuffer ();
+ ~BackBuffer ();
+ void setSize(int w, int h);
+ };
+
+ typedef enum { DRAW_PLAIN, DRAW_CLIPPED, DRAW_BUFFERED } DrawType;
+
+ int bgColor;
+ core::Region drawRegion;
+ core::Rectangle *exposeArea;
+ static BackBuffer *backBuffer;
+ static bool backBufferInUse;
+
+ void draw (const core::Rectangle *rect, DrawType type);
+ void drawChildWidgets ();
+ int manageTabToFocus();
+ inline void clipPoint (int *x, int *y, int border) {
+ if (exposeArea) {
+ if (*x < exposeArea->x - border)
+ *x = exposeArea->x - border;
+ if (*x > exposeArea->x + exposeArea->width + border)
+ *x = exposeArea->x + exposeArea->width + border;
+ if (*y < exposeArea->y - border)
+ *y = exposeArea->y - border;
+ if (*y > exposeArea->y + exposeArea->height + border)
+ *y = exposeArea->y + exposeArea->height + border;
+ }
+ }
+protected:
+ core::Layout *theLayout;
+ int canvasWidth, canvasHeight;
+ int mouse_x, mouse_y;
+ Fl_Widget *focused_child;
+
+ virtual int translateViewXToCanvasX (int x) = 0;
+ virtual int translateViewYToCanvasY (int y) = 0;
+ virtual int translateCanvasXToViewX (int x) = 0;
+ virtual int translateCanvasYToViewY (int y) = 0;
+
+public:
+ FltkViewBase (int x, int y, int w, int h, const char *label = 0);
+ ~FltkViewBase ();
+
+ void draw();
+ int handle (int event);
+
+ void setLayout (core::Layout *layout);
+ void setCanvasSize (int width, int ascent, int descent);
+ void setCursor (core::style::Cursor cursor);
+ void setBgColor (core::style::Color *color);
+
+ void startDrawing (core::Rectangle *area);
+ void finishDrawing (core::Rectangle *area);
+ void queueDraw (core::Rectangle *area);
+ void queueDrawTotal ();
+ void cancelQueueDraw ();
+ void drawPoint (core::style::Color *color,
+ core::style::Color::Shading shading,
+ int x, int y);
+ void drawLine (core::style::Color *color,
+ core::style::Color::Shading shading,
+ int x1, int y1, int x2, int y2);
+ void drawTypedLine (core::style::Color *color,
+ core::style::Color::Shading shading,
+ core::style::LineType type, int width,
+ int x1, int y1, int x2, int y2);
+ void drawRectangle (core::style::Color *color,
+ core::style::Color::Shading shading, bool filled,
+ int x, int y, int width, int height);
+ void drawArc (core::style::Color *color,
+ core::style::Color::Shading shading, bool filled,
+ int centerX, int centerY, int width, int height,
+ int angle1, int angle2);
+ void drawPolygon (core::style::Color *color,
+ core::style::Color::Shading shading,
+ bool filled, bool convex,
+ core::Point *points, int npoints);
+
+ core::View *getClippingView (int x, int y, int width, int height);
+ void mergeClippingView (core::View *clippingView);
+ void setBufferedDrawing (bool b);
+};
+
+
+class FltkWidgetView: public FltkViewBase
+{
+public:
+ FltkWidgetView (int x, int y, int w, int h, const char *label = 0);
+ ~FltkWidgetView ();
+
+ void drawText (core::style::Font *font,
+ core::style::Color *color,
+ core::style::Color::Shading shading,
+ int x, int y, const char *text, int len);
+ void drawSimpleWrappedText (core::style::Font *font,
+ core::style::Color *color,
+ core::style::Color::Shading shading,
+ int x, int y, int w, int h,
+ const char *text);
+ void drawImage (core::Imgbuf *imgbuf, int xRoot, int yRoot,
+ int x, int y, int width, int height);
+
+ bool usesFltkWidgets ();
+ void addFltkWidget (Fl_Widget *widget, core::Allocation *allocation);
+ void removeFltkWidget (Fl_Widget *widget);
+ void allocateFltkWidget (Fl_Widget *widget,
+ core::Allocation *allocation);
+ void drawFltkWidget (Fl_Widget *widget, core::Rectangle *area);
+};
+
+} // namespace fltk
+} // namespace dw
+
+#endif // __DW_FLTKVIEWBASE_HH__
+
diff --git a/dw/fltkviewport.cc b/dw/fltkviewport.cc
new file mode 100644
index 0000000..804b62f
--- /dev/null
+++ b/dw/fltkviewport.cc
@@ -0,0 +1,558 @@
+/*
+ * RTFL (originally part of dillo)
+ *
+ * Copyright 2005-2007 Sebastian Geerken <sgeerken@dillo.org>
+ *
+ * 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; with the following exception:
+ *
+ * The copyright holders of RTFL give you permission to link this file
+ * statically or dynamically against all versions of the graphviz
+ * library, which are published by AT&T Corp. under one of the following
+ * licenses:
+ *
+ * - Common Public License version 1.0 as published by International
+ * Business Machines Corporation (IBM), or
+ * - Eclipse Public License version 1.0 as published by the Eclipse
+ * Foundation.
+ *
+ * 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/>.
+ */
+
+
+
+#include "fltkviewport.hh"
+
+#include <FL/Fl.H>
+#include <FL/fl_draw.H>
+#include <FL/names.h>
+
+#include <stdio.h>
+#include "../lout/msg.h"
+#include "../lout/debug.hh"
+
+using namespace lout;
+using namespace lout::object;
+using namespace lout::container::typed;
+
+namespace dw {
+namespace fltk {
+
+/*
+ * Lets SHIFT+{Left,Right} go to the parent
+ */
+class CustScrollbar : public Fl_Scrollbar
+{
+public:
+ CustScrollbar(int x, int y, int w, int h) : Fl_Scrollbar(x,y,w,h) {};
+ int handle(int e) {
+ if (e == FL_SHORTCUT && Fl::event_state() == FL_SHIFT &&
+ (Fl::event_key() == FL_Left || Fl::event_key() == FL_Right))
+ return 0;
+ return Fl_Scrollbar::handle(e);
+ }
+};
+
+FltkViewport::FltkViewport (int X, int Y, int W, int H, const char *label):
+ FltkWidgetView (X, Y, W, H, label)
+{
+ DBG_OBJ_CREATE ("dw::fltk::FltkViewport");
+
+ hscrollbar = new CustScrollbar (x (), y (), 1, 1);
+ hscrollbar->type(FL_HORIZONTAL);
+ hscrollbar->callback (hscrollbarCallback, this);
+ hscrollbar->hide();
+ add (hscrollbar);
+
+ vscrollbar = new Fl_Scrollbar (x (), y(), 1, 1);
+ vscrollbar->type(FL_VERTICAL);
+ vscrollbar->callback (vscrollbarCallback, this);
+ vscrollbar->hide();
+ add (vscrollbar);
+
+ hasDragScroll = 1;
+ scrollX = scrollY = scrollDX = scrollDY = 0;
+ horScrolling = verScrolling = dragScrolling = 0;
+
+ gadgetOrientation[0] = GADGET_HORIZONTAL;
+ gadgetOrientation[1] = GADGET_HORIZONTAL;
+ gadgetOrientation[2] = GADGET_VERTICAL;
+ gadgetOrientation[3] = GADGET_HORIZONTAL;
+
+ gadgets =
+ new container::typed::List <object::TypedPointer < Fl_Widget> >
+ (true);
+}
+
+FltkViewport::~FltkViewport ()
+{
+ delete gadgets;
+ DBG_OBJ_DELETE ();
+}
+
+void FltkViewport::adjustScrollbarsAndGadgetsAllocation ()
+{
+ int hdiff = 0, vdiff = 0;
+ int visibility = 0;
+
+ _MSG(" >>FltkViewport::adjustScrollbarsAndGadgetsAllocation\n");
+ if (hscrollbar->visible ())
+ visibility |= 1;
+ if (vscrollbar->visible ())
+ visibility |= 2;
+
+ if (gadgets->size () > 0) {
+ switch (gadgetOrientation [visibility]) {
+ case GADGET_VERTICAL:
+ hdiff = SCROLLBAR_THICKNESS;
+ vdiff = SCROLLBAR_THICKNESS * gadgets->size ();
+ break;
+
+ case GADGET_HORIZONTAL:
+ hdiff = SCROLLBAR_THICKNESS * gadgets->size ();
+ vdiff = SCROLLBAR_THICKNESS;
+ break;
+ }
+ } else {
+ hdiff = vscrollbar->visible () ? SCROLLBAR_THICKNESS : 0;
+ vdiff = hscrollbar->visible () ? SCROLLBAR_THICKNESS : 0;
+ }
+
+ hscrollbar->resize(x (), y () + h () - SCROLLBAR_THICKNESS,
+ w () - hdiff, SCROLLBAR_THICKNESS);
+ vscrollbar->resize(x () + w () - SCROLLBAR_THICKNESS, y (),
+ SCROLLBAR_THICKNESS, h () - vdiff);
+
+ int X = x () + w () - SCROLLBAR_THICKNESS;
+ int Y = y () + h () - SCROLLBAR_THICKNESS;
+ for (Iterator <TypedPointer < Fl_Widget> > it = gadgets->iterator ();
+ it.hasNext (); ) {
+ Fl_Widget *widget = it.getNext()->getTypedValue ();
+ widget->resize(x (), y (), SCROLLBAR_THICKNESS, SCROLLBAR_THICKNESS);
+
+ switch (gadgetOrientation [visibility]) {
+ case GADGET_VERTICAL:
+ Y -= SCROLLBAR_THICKNESS;
+ break;
+
+ case GADGET_HORIZONTAL:
+ X -= SCROLLBAR_THICKNESS;
+ break;
+ }
+ }
+}
+
+void FltkViewport::adjustScrollbarValues ()
+{
+ hscrollbar->value (scrollX, hscrollbar->w (), 0, canvasWidth);
+ vscrollbar->value (scrollY, vscrollbar->h (), 0, canvasHeight);
+}
+
+void FltkViewport::hscrollbarChanged ()
+{
+ scroll (hscrollbar->value () - scrollX, 0);
+}
+
+void FltkViewport::vscrollbarChanged ()
+{
+ scroll (0, vscrollbar->value () - scrollY);
+}
+
+void FltkViewport::vscrollbarCallback (Fl_Widget *vscrollbar,void *viewportPtr)
+{
+ ((FltkViewport*)viewportPtr)->vscrollbarChanged ();
+}
+
+void FltkViewport::hscrollbarCallback (Fl_Widget *hscrollbar,void *viewportPtr)
+{
+ ((FltkViewport*)viewportPtr)->hscrollbarChanged ();
+}
+
+// ----------------------------------------------------------------------
+
+void FltkViewport::resize(int X, int Y, int W, int H)
+{
+ bool dimension_changed = W != w() || H != h();
+
+ Fl_Group::resize(X, Y, W, H);
+ if (dimension_changed) {
+ theLayout->viewportSizeChanged (this, W, H);
+ adjustScrollbarsAndGadgetsAllocation ();
+ }
+}
+
+void FltkViewport::draw_area (void *data, int x, int y, int w, int h)
+{
+ FltkViewport *vp = (FltkViewport*) data;
+ fl_push_clip(x, y, w, h);
+
+ vp->FltkWidgetView::draw ();
+
+ for (Iterator <TypedPointer < Fl_Widget> > it = vp->gadgets->iterator();
+ it.hasNext (); ) {
+ Fl_Widget *widget = it.getNext()->getTypedValue ();
+ vp->draw_child (*widget);
+ }
+
+ fl_pop_clip();
+
+}
+
+void FltkViewport::draw ()
+{
+ int hdiff = vscrollbar->visible () ? SCROLLBAR_THICKNESS : 0;
+ int vdiff = hscrollbar->visible () ? SCROLLBAR_THICKNESS : 0;
+ int d = damage();
+
+ if (d & FL_DAMAGE_SCROLL) {
+ clear_damage (FL_DAMAGE_SCROLL);
+ fl_scroll(x(), y(), w() - hdiff, h() - vdiff,
+ -scrollDX, -scrollDY, draw_area, this);
+ clear_damage (d & ~FL_DAMAGE_SCROLL);
+ }
+
+ if (d) {
+ draw_area(this, x(), y(), w () - hdiff, h () - vdiff);
+
+ if (d == FL_DAMAGE_ALL || hscrollbar->damage ())
+ draw_child (*hscrollbar);
+ if (d == FL_DAMAGE_ALL || vscrollbar->damage ())
+ draw_child (*vscrollbar);
+
+ if (d == FL_DAMAGE_ALL && hdiff && vdiff) {
+ fl_color(FL_BACKGROUND_COLOR);
+ fl_rectf(x()+w()-hdiff, y()+h()-vdiff, hdiff, vdiff);
+ }
+ }
+
+ scrollDX = 0;
+ scrollDY = 0;
+}
+
+int FltkViewport::handle (int event)
+{
+ _MSG("FltkViewport::handle %s\n", fl_eventnames[event]);
+
+ switch(event) {
+ case FL_KEYBOARD:
+ /* When the viewport has focus (and not one of its children), FLTK
+ * sends the event here. Returning zero tells FLTK to resend the
+ * event as SHORTCUT, which we finally route to the parent. */
+
+ /* As we don't know the exact keybindings set by the user, we ask for
+ * all of them (except for the minimum needed to keep form navigation).*/
+ if (Fl::event_key() != FL_Tab || Fl::event_ctrl())
+ return 0;
+ break;
+
+ case FL_SHORTCUT:
+ /* send it to the parent (UI) */
+ return 0;
+
+ case FL_FOCUS:
+ /** \bug Draw focus box. */
+ break;
+
+ case FL_UNFOCUS:
+ /** \bug Undraw focus box. */
+ break;
+
+ case FL_PUSH:
+ if (vscrollbar->visible() && Fl::event_inside(vscrollbar)) {
+ if (vscrollbar->handle(event))
+ verScrolling = 1;
+ } else if (hscrollbar->visible() && Fl::event_inside(hscrollbar)) {
+ if (hscrollbar->handle(event))
+ horScrolling = 1;
+ } else if (FltkWidgetView::handle(event) == 0 &&
+ Fl::event_button() == FL_MIDDLE_MOUSE) {
+ if (!hasDragScroll) {
+ /* let the parent widget handle it... */
+ return 0;
+ } else {
+ /* receive FL_DRAG and FL_RELEASE */
+ dragScrolling = 1;
+ dragX = Fl::event_x();
+ dragY = Fl::event_y();
+ setCursor (core::style::CURSOR_MOVE);
+ }
+ }
+ return 1;
+ break;
+
+ case FL_DRAG:
+ if (Fl::event_inside(this))
+ Fl::remove_timeout(selectionScroll);
+ if (dragScrolling) {
+ scroll(dragX - Fl::event_x(), dragY - Fl::event_y());
+ dragX = Fl::event_x();
+ dragY = Fl::event_y();
+ return 1;
+ } else if (verScrolling) {
+ vscrollbar->handle(event);
+ return 1;
+ } else if (horScrolling) {
+ hscrollbar->handle(event);
+ return 1;
+ } else if (!Fl::event_inside(this)) {
+ mouse_x = Fl::event_x();
+ mouse_y = Fl::event_y();
+ if (!Fl::has_timeout(selectionScroll, this))
+ Fl::add_timeout(0.025, selectionScroll, this);
+ }
+ break;
+
+ case FL_MOUSEWHEEL:
+ return (Fl::event_dx() ? hscrollbar : vscrollbar)->handle(event);
+ break;
+
+ case FL_RELEASE:
+ Fl::remove_timeout(selectionScroll);
+ if (Fl::event_button() == FL_MIDDLE_MOUSE) {
+ setCursor (core::style::CURSOR_DEFAULT);
+ } else if (verScrolling) {
+ vscrollbar->handle(event);
+ } else if (horScrolling) {
+ hscrollbar->handle(event);
+ }
+ horScrolling = verScrolling = dragScrolling = 0;
+ break;
+
+ case FL_ENTER:
+ /* could be the result of, e.g., closing another window. */
+ mouse_x = Fl::event_x();
+ mouse_y = Fl::event_y();
+ positionChanged();
+ break;
+
+ case FL_LEAVE:
+ mouse_x = mouse_y = -1;
+ break;
+ }
+
+ return FltkWidgetView::handle (event);
+}
+
+// ----------------------------------------------------------------------
+
+void FltkViewport::setCanvasSize (int width, int ascent, int descent)
+{
+ FltkWidgetView::setCanvasSize (width, ascent, descent);
+ adjustScrollbarValues ();
+}
+
+/*
+ * This is used to simulate mouse motion (e.g., when scrolling).
+ */
+void FltkViewport::positionChanged ()
+{
+ if (!dragScrolling && mouse_x >= x() && mouse_x < x()+w() && mouse_y >= y()
+ && mouse_y < y()+h())
+ (void)theLayout->motionNotify (this,
+ translateViewXToCanvasX (mouse_x),
+ translateViewYToCanvasY (mouse_y),
+ (core::ButtonState)0);
+}
+
+/*
+ * For scrollbars, this currently sets the same step to both vertical and
+ * horizontal. It may be differentiated if necessary.
+ */
+void FltkViewport::setScrollStep(int step)
+{
+ vscrollbar->linesize(step);
+ hscrollbar->linesize(step);
+}
+
+bool FltkViewport::usesViewport ()
+{
+ return true;
+}
+
+int FltkViewport::getHScrollbarThickness ()
+{
+ return SCROLLBAR_THICKNESS;
+}
+
+int FltkViewport::getVScrollbarThickness ()
+{
+ return SCROLLBAR_THICKNESS;
+}
+
+void FltkViewport::scrollTo (int x, int y)
+{
+ int hdiff = vscrollbar->visible () ? SCROLLBAR_THICKNESS : 0;
+ int vdiff = hscrollbar->visible () ? SCROLLBAR_THICKNESS : 0;
+
+ x = misc::min (x, canvasWidth - w() + hdiff);
+ x = misc::max (x, 0);
+
+ y = misc::min (y, canvasHeight - h() + vdiff);
+ y = misc::max (y, 0);
+
+ if (x == scrollX && y == scrollY) {
+ return;
+ }
+
+ /* multiple calls to scroll can happen before a redraw occurs.
+ * scrollDX and scrollDY can therefore be non-zero here.
+ */
+ updateCanvasWidgets (x - scrollX, y - scrollY);
+ scrollDX += x - scrollX;
+ scrollDY += y - scrollY;
+
+ scrollX = x;
+ scrollY = y;
+
+ adjustScrollbarValues ();
+ damage(FL_DAMAGE_SCROLL);
+ theLayout->scrollPosChanged (this, scrollX, scrollY);
+ positionChanged();
+}
+
+void FltkViewport::scroll (int dx, int dy)
+{
+ scrollTo (scrollX + dx, scrollY + dy);
+}
+
+void FltkViewport::scroll (core::ScrollCommand cmd)
+{
+ if (cmd == core::SCREEN_UP_CMD) {
+ scroll (0, -h () + vscrollbar->linesize ());
+ } else if (cmd == core::SCREEN_DOWN_CMD) {
+ scroll (0, h () - vscrollbar->linesize ());
+ } else if (cmd == core::SCREEN_LEFT_CMD) {
+ scroll (-w() + hscrollbar->linesize (), 0);
+ } else if (cmd == core::SCREEN_RIGHT_CMD) {
+ scroll (w() - hscrollbar->linesize (), 0);
+ } else if (cmd == core::LINE_UP_CMD) {
+ scroll (0, (int) -vscrollbar->linesize ());
+ } else if (cmd == core::LINE_DOWN_CMD) {
+ scroll (0, (int) vscrollbar->linesize ());
+ } else if (cmd == core::LEFT_CMD) {
+ scroll ((int) -hscrollbar->linesize (), 0);
+ } else if (cmd == core::RIGHT_CMD) {
+ scroll ((int) hscrollbar->linesize (), 0);
+ } else if (cmd == core::TOP_CMD) {
+ scrollTo (scrollX, 0);
+ } else if (cmd == core::BOTTOM_CMD) {
+ scrollTo (scrollX, canvasHeight); /* gets adjusted in scrollTo () */
+ }
+}
+
+/*
+ * Scrolling in response to selection where the cursor is outside the view.
+ */
+void FltkViewport::selectionScroll ()
+{
+ int distance;
+ int dx = 0, dy = 0;
+
+ if ((distance = x() - mouse_x) > 0)
+ dx = -distance * hscrollbar->linesize () / 48 - 1;
+ else if ((distance = mouse_x - (x() + w())) > 0)
+ dx = distance * hscrollbar->linesize () / 48 + 1;
+ if ((distance = y() - mouse_y) > 0)
+ dy = -distance * vscrollbar->linesize () / 48 - 1;
+ else if ((distance = mouse_y - (y() + h())) > 0)
+ dy = distance * vscrollbar->linesize () / 48 + 1;
+
+ scroll (dx, dy);
+}
+
+void FltkViewport::selectionScroll (void *data)
+{
+ ((FltkViewport *)data)->selectionScroll ();
+ Fl::repeat_timeout(0.025, selectionScroll, data);
+}
+
+void FltkViewport::setViewportSize (int width, int height,
+ int hScrollbarThickness,
+ int vScrollbarThickness)
+{
+ int adjustReq =
+ (hscrollbar->visible() ? !hScrollbarThickness : hScrollbarThickness) ||
+ (vscrollbar->visible() ? !vScrollbarThickness : vScrollbarThickness);
+
+ _MSG("FltkViewport::setViewportSize old_w,old_h=%dx%d -> w,h=%dx%d\n"
+ "\t hThick=%d hVis=%d, vThick=%d vVis=%d, adjustReq=%d\n",
+ w(),h(),width,height,
+ hScrollbarThickness,hscrollbar->visible(),
+ vScrollbarThickness,vscrollbar->visible(), adjustReq);
+
+ (hScrollbarThickness > 0) ? hscrollbar->show () : hscrollbar->hide ();
+ (vScrollbarThickness > 0) ? vscrollbar->show () : vscrollbar->hide ();
+
+ /* If no scrollbar, go to the beginning */
+ scroll(hScrollbarThickness ? 0 : -scrollX,
+ vScrollbarThickness ? 0 : -scrollY);
+
+ /* Adjust when scrollbar visibility changes */
+ if (adjustReq)
+ adjustScrollbarsAndGadgetsAllocation ();
+}
+
+void FltkViewport::updateCanvasWidgets (int dx, int dy)
+{
+ // scroll all child widgets except scroll bars
+ for (int i = children () - 1; i > 0; i--) {
+ Fl_Widget *widget = child (i);
+
+ if (widget == hscrollbar || widget == vscrollbar)
+ continue;
+
+ widget->position(widget->x () - dx, widget->y () - dy);
+ }
+}
+
+int FltkViewport::translateViewXToCanvasX (int X)
+{
+ return X - x () + scrollX;
+}
+
+int FltkViewport::translateViewYToCanvasY (int Y)
+{
+ return Y - y () + scrollY;
+}
+
+int FltkViewport::translateCanvasXToViewX (int X)
+{
+ return X + x () - scrollX;
+}
+
+int FltkViewport::translateCanvasYToViewY (int Y)
+{
+ return Y + y () - scrollY;
+}
+
+// ----------------------------------------------------------------------
+
+void FltkViewport::setGadgetOrientation (bool hscrollbarVisible,
+ bool vscrollbarVisible,
+ FltkViewport::GadgetOrientation
+ gadgetOrientation)
+{
+ this->gadgetOrientation[(hscrollbarVisible ? 0 : 1) |
+ (vscrollbarVisible ? 0 : 2)] = gadgetOrientation;
+ adjustScrollbarsAndGadgetsAllocation ();
+}
+
+void FltkViewport::addGadget (Fl_Widget *gadget)
+{
+ /** \bug Reparent? */
+
+ gadgets->append (new TypedPointer < Fl_Widget> (gadget));
+ adjustScrollbarsAndGadgetsAllocation ();
+}
+
+
+} // namespace fltk
+} // namespace dw
diff --git a/dw/fltkviewport.hh b/dw/fltkviewport.hh
new file mode 100644
index 0000000..1569a7d
--- /dev/null
+++ b/dw/fltkviewport.hh
@@ -0,0 +1,84 @@
+#ifndef __DW_FLTKVIEWPORT_HH__
+#define __DW_FLTKVIEWPORT_HH__
+
+#include <FL/Fl_Group.H>
+#include <FL/Fl_Scrollbar.H>
+
+#include "core.hh"
+#include "fltkcore.hh"
+#include "fltkviewbase.hh"
+
+namespace dw {
+namespace fltk {
+
+class FltkViewport: public FltkWidgetView
+{
+public:
+ enum GadgetOrientation { GADGET_VERTICAL, GADGET_HORIZONTAL };
+
+private:
+ enum { SCROLLBAR_THICKNESS = 15 };
+
+ int scrollX, scrollY;
+ int scrollDX, scrollDY;
+ int hasDragScroll, dragScrolling, dragX, dragY;
+ int horScrolling, verScrolling;
+
+ Fl_Scrollbar *vscrollbar, *hscrollbar;
+
+ GadgetOrientation gadgetOrientation[4];
+ lout::container::typed::List <lout::object::TypedPointer < Fl_Widget> >
+ *gadgets;
+
+ void adjustScrollbarsAndGadgetsAllocation ();
+ void adjustScrollbarValues ();
+ void hscrollbarChanged ();
+ void vscrollbarChanged ();
+ void positionChanged ();
+
+ static void hscrollbarCallback (Fl_Widget *hscrollbar, void *viewportPtr);
+ static void vscrollbarCallback (Fl_Widget *vscrollbar, void *viewportPtr);
+
+ void selectionScroll();
+ static void selectionScroll(void *vport);
+
+ void updateCanvasWidgets (int oldScrollX, int oldScrollY);
+ static void draw_area (void *data, int x, int y, int w, int h);
+
+protected:
+ int translateViewXToCanvasX (int x);
+ int translateViewYToCanvasY (int y);
+ int translateCanvasXToViewX (int x);
+ int translateCanvasYToViewY (int y);
+
+public:
+ FltkViewport (int x, int y, int w, int h, const char *label = 0);
+ ~FltkViewport ();
+
+ void resize(int x, int y, int w, int h);
+ void draw ();
+ int handle (int event);
+
+ void setCanvasSize (int width, int ascent, int descent);
+
+ bool usesViewport ();
+ int getHScrollbarThickness ();
+ int getVScrollbarThickness ();
+ void scroll(int dx, int dy);
+ void scroll(dw::core::ScrollCommand cmd);
+ void scrollTo (int x, int y);
+ void setViewportSize (int width, int height,
+ int hScrollbarThickness, int vScrollbarThickness);
+ void setScrollStep(int step);
+
+ void setGadgetOrientation (bool hscrollbarVisible, bool vscrollbarVisible,
+ GadgetOrientation gadgetOrientation);
+ void setDragScroll (bool enable) { hasDragScroll = enable ? 1 : 0; }
+ void addGadget (Fl_Widget *gadget);
+};
+
+} // namespace fltk
+} // namespace dw
+
+#endif // __DW_FLTKVIEWPORT_HH__
+
diff --git a/dw/imgbuf.hh b/dw/imgbuf.hh
new file mode 100644
index 0000000..f9870bc
--- /dev/null
+++ b/dw/imgbuf.hh
@@ -0,0 +1,229 @@
+#ifndef __DW_IMGBUF_HH__
+#define __DW_IMGBUF_HH__
+
+#ifndef __INCLUDED_FROM_DW_CORE_HH__
+# error Do not include this file directly, use "core.hh" instead.
+#endif
+
+#include "../lout/debug.hh"
+
+namespace dw {
+namespace core {
+
+/**
+ * \brief The platform independent interface for image buffers.
+ *
+ * %Image buffers depend on the platform (see \ref dw-images-and-backgrounds),
+ * but have this general, platform independent interface. The purpose of
+ * an image buffer is
+ *
+ * <ol>
+ * <li> storing the image data,
+ * <li> handling scaled versions of this buffer, and
+ * <li> drawing.
+ * </ol>
+ *
+ * The latter must be done independently from the window.
+ *
+ * <h3>Creating</h3>
+ *
+ * %Image buffers are created by calling dw::core::Platform::createImgbuf.
+ *
+ * <h3>Storing %Image Data</h3>
+ *
+ * dw::core::Imgbuf supports five image types, which are listed in the table
+ * below. The representation defines, how the colors are stored within
+ * the data, which is passed to dw::core::Imgbuf::copyRow.
+ *
+ * <table>
+ * <tr><th>Type (dw::core::Imgbuf::Type) <th>Bytes per
+ * Pixel <th>Representation
+ * <tr><td>dw::core::Imgbuf::RGB <td>3 <td>red, green, blue
+ * <tr><td>dw::core::Imgbuf::RGBA <td>4 <td>red, green, blue, alpha
+ * <tr><td>dw::core::Imgbuf::GRAY <td>1 <td>gray value
+ * <tr><td>dw::core::Imgbuf::INDEXED <td>1 <td>index to colormap
+ * <tr><td>dw::core::Imgbuf::INDEXED_ALPHA <td>1 <td>index to colormap
+ * </table>
+ *
+ * The last two types need a colormap, which is set by
+ * dw::core::Imgbuf::setCMap, which must be called before
+ * dw::core::Imgbuf::copyRow. This function expects the colors as 32 bit
+ * unsigned integers, which have the format 0xrrbbgg (for indexed
+ * images), or 0xaarrggbb (for indexed alpha), respectively.
+ *
+ *
+ * <h3>Scaling</h3>
+ *
+ * The buffer with the original size, which was created by
+ * dw::core::Platform::createImgbuf, is called root buffer. Imgbuf provides
+ * the ability to scale buffers. Generally, both root buffers, as well as
+ * scaled buffers, may be shared, memory management is done by reference
+ * counters.
+ *
+ * Via dw::core::Imgbuf::getScaledBuf, you can retrieve a scaled buffer.
+ * Generally, something like this must work always, in an efficient way:
+ *
+ * \code
+ * dw::core::Imgbuf *curBuf, *oldBuf;
+ * int width, heigt,
+ * // ...
+ * oldBuf = curBuf;
+ * curBuf = oldBuf->getScaledBuf(oldBuf, width, height);
+ * oldBuf->unref();
+ * \endcode
+ *
+ * \em oldBuf may both be a root buffer, or a scaled buffer.
+ *
+ * The root buffer keeps a list of all children, and all methods
+ * operating on the image data (dw::core::Imgbuf::copyRow and
+ * dw::core::Imgbuf::setCMap) are delegated to the scaled buffers, when
+ * processed, and inherited, when a new scaled buffer is created. This
+ * means, that they must only be performed for the root buffer.
+ *
+ * A possible implementation could be (dw::fltk::FltkImgbuf does it this way):
+ *
+ * <ul>
+ * <li> If the method is called with an already scaled image buffer, this is
+ * delegated to the root buffer.
+ *
+ * <li> If the given size is the original size, the root buffer is
+ * returned, with an increased reference counter.
+ *
+ * <li> Otherwise, if this buffer has already been scaled to the given
+ * size, return this scaled buffer, with an increased reference
+ * counter.
+ *
+ * <li> Otherwise, return a new scaled buffer with reference counter 1.
+ * </ul>
+ *
+ * Special care is to be taken, when the root buffer is not used anymore,
+ * i.e. after dw::core::Imgbuf::unref the reference counter is 0, but there
+ * are still scaled buffers. Since all methods operating on the image data
+ * (dw::core::Imgbuf::copyRow and dw::core::Imgbuf::setCMap) are called for
+ * the root buffer, the root buffer is still needed, and so must not be
+ * deleted at this point. This is, how dw::fltk::FltkImgbuf solves this
+ * problem:
+ *
+ * <ul>
+ * <li> dw::fltk::FltkImgbuf::unref does, for root buffers, check, not only
+ * whether dw::fltk::FltkImgbuf::refCount is 0, but also, whether
+ * there are children left. When the latter is the case, the buffer
+ * is not deleted.
+ *
+ * <li> There is an additional check in dw::fltk::FltkImgbuf::detachScaledBuf,
+ * which deals with the case, that dw::fltk::FltkImgbuf::refCount is 0,
+ * and the last scaled buffer is removed.
+ * </ul>
+ *
+ * In the following example:
+ *
+ * \code
+ * dw::fltk::FltkPlatform *platform = new dw::fltk::FltkPlatform ();
+ * dw::core::Layout *layout = new dw::core::Layout (platform);
+ *
+ * dw::core::Imgbuf *rootbuf =
+ * layout->createImgbuf (dw::core::Imgbuf::RGB, 100, 100);
+ * dw::core::Imgbuf *scaledbuf = rootbuf->getScaledBuf (50, 50);
+ * rootbuf->unref ();
+ * scaledbuf->unref ();
+ * \endcode
+ *
+ * the root buffer is not deleted, when dw::core::Imgbuf::unref is called,
+ * since a scaled buffer is left. After calling dw::core::Imgbuf::unref for
+ * the scaled buffer, it is deleted, and after it, the root buffer.
+ *
+ * <h3>Drawing</h3>
+ *
+ * dw::core::Imgbuf provides no methods for drawing, instead, this is
+ * done by the views (implementation of dw::core::View).
+ *
+ * There are two situations, when drawing is necessary:
+ *
+ * <ol>
+ * <li> To react on expose events, the function dw::core::View::drawImage
+ * should be used, with the following parameters:
+ * <ul>
+ * <li> of course, the image buffer,
+ * <li> where the root of the image would be displayed (as \em xRoot
+ * and \em yRoot), and
+ * <li> the region within the image, which should be displayed (\em x,
+ * \em y, \em width, \em height).
+ * </ul>
+ *
+ * <li> When a row has been copied, it has to be drawn. To determine the
+ * area, which has to be drawn, the dw::core::Imgbuf::getRowArea
+ * should be used. The result can then passed
+ * to dw::core::View::drawImage.
+ * </ol>
+ *
+ * \sa \ref dw-images-and-backgrounds
+ */
+class Imgbuf: public lout::object::Object, public lout::signal::ObservedObject
+{
+public:
+ enum Type { RGB, RGBA, GRAY, INDEXED, INDEXED_ALPHA };
+
+ inline Imgbuf () {
+ DBG_OBJ_CREATE ("dw::core::Imgbuf");
+ DBG_OBJ_BASECLASS (lout::object::Object);
+ DBG_OBJ_BASECLASS (lout::signal::ObservedObject);
+ }
+
+ /*
+ * Methods called from the image decoding
+ */
+
+ virtual void setCMap (int *colors, int num_colors) = 0;
+ virtual void copyRow (int row, const byte *data) = 0;
+ virtual void newScan () = 0;
+
+ /*
+ * Methods called from dw::Image
+ */
+
+ virtual Imgbuf* getScaledBuf (int width, int height) = 0;
+ virtual void getRowArea (int row, dw::core::Rectangle *area) = 0;
+ virtual int getRootWidth () = 0;
+ virtual int getRootHeight () = 0;
+
+
+ /**
+ * Creates an image buffer with same parameters (type, gamma etc.)
+ * except size.
+ */
+ virtual Imgbuf *createSimilarBuf (int width, int height) = 0;
+
+ /**
+ * Copies another image buffer into this image buffer.
+ */
+ virtual void copyTo (Imgbuf *dest, int xDestRoot, int yDestRoot,
+ int xSrc, int ySrc, int widthSrc, int heightSrc) = 0;
+
+ /*
+ * Reference counting.
+ */
+
+ virtual void ref () = 0;
+ virtual void unref () = 0;
+
+ /**
+ * \todo Comment
+ */
+ virtual bool lastReference () = 0;
+
+
+ /**
+ * \todo Comment
+ */
+ virtual void setDeleteOnUnref (bool deleteOnUnref) = 0;
+
+ /**
+ * \todo Comment
+ */
+ virtual bool isReferred () = 0;
+};
+
+} // namespace core
+} // namespace dw
+
+#endif // __DW_IMGBUF_HH__
diff --git a/dw/imgrenderer.cc b/dw/imgrenderer.cc
new file mode 100644
index 0000000..1868122
--- /dev/null
+++ b/dw/imgrenderer.cc
@@ -0,0 +1,77 @@
+/*
+ * RTFL (originally part of dillo)
+ *
+ * Copyright 2013 Sebastian Geerken <sgeerken@dillo.org>
+ *
+ * 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; with the following exception:
+ *
+ * The copyright holders of RTFL give you permission to link this file
+ * statically or dynamically against all versions of the graphviz
+ * library, which are published by AT&T Corp. under one of the following
+ * licenses:
+ *
+ * - Common Public License version 1.0 as published by International
+ * Business Machines Corporation (IBM), or
+ * - Eclipse Public License version 1.0 as published by the Eclipse
+ * Foundation.
+ *
+ * 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/>.
+ */
+
+#include "core.hh"
+
+namespace dw {
+namespace core {
+
+using namespace lout::container;
+using namespace lout::object;
+
+void ImgRendererDist::setBuffer (core::Imgbuf *buffer, bool resize)
+{
+ for (typed::Iterator <TypedPointer <ImgRenderer> > it =
+ children->iterator (); it.hasNext (); ) {
+ TypedPointer <ImgRenderer> *tp = it.getNext ();
+ tp->getTypedValue()->setBuffer (buffer, resize);
+ }
+}
+
+void ImgRendererDist::drawRow (int row)
+{
+ for (typed::Iterator <TypedPointer <ImgRenderer> > it =
+ children->iterator (); it.hasNext (); ) {
+ TypedPointer <ImgRenderer> *tp = it.getNext ();
+ tp->getTypedValue()->drawRow (row);
+ }
+}
+
+
+void ImgRendererDist::finish ()
+{
+ for (typed::Iterator <TypedPointer <ImgRenderer> > it =
+ children->iterator (); it.hasNext (); ) {
+ TypedPointer <ImgRenderer> *tp = it.getNext ();
+ tp->getTypedValue()->finish ();
+ }
+}
+
+void ImgRendererDist::fatal ()
+{
+ for (typed::Iterator <TypedPointer <ImgRenderer> > it =
+ children->iterator (); it.hasNext (); ) {
+ TypedPointer <ImgRenderer> *tp = it.getNext ();
+ tp->getTypedValue()->fatal ();
+ }
+}
+
+
+} // namespace core
+} // namespace dw
diff --git a/dw/imgrenderer.hh b/dw/imgrenderer.hh
new file mode 100644
index 0000000..e3b5e95
--- /dev/null
+++ b/dw/imgrenderer.hh
@@ -0,0 +1,87 @@
+#ifndef __DW_IMGRENDERER_HH__
+#define __DW_IMGRENDERER_HH__
+
+#ifndef __INCLUDED_FROM_DW_CORE_HH__
+# error Do not include this file directly, use "core.hh" instead.
+#endif
+
+namespace dw {
+namespace core {
+
+/**
+ * \brief ...
+ *
+ * \sa \ref dw-images-and-backgrounds
+ */
+class ImgRenderer
+{
+public:
+ virtual ~ImgRenderer () { }
+
+ /**
+ * \brief Called, when an image buffer is attached.
+ *
+ * This is typically the case when all meta data (size, depth) has been read.
+ */
+ virtual void setBuffer (core::Imgbuf *buffer, bool resize = false) = 0;
+
+ /**
+ * \brief Called, when data from a row is available and has been copied into
+ * the image buffer.
+ *
+ * The implementation will typically queue the respective area for drawing.
+ */
+ virtual void drawRow (int row) = 0;
+
+ /**
+ * \brief Called, when all image data has been retrieved.
+ *
+ * The implementation may use this instead of "drawRow" for drawing, to
+ * limit the number of draws.
+ */
+ virtual void finish () = 0;
+
+ /**
+ * \brief Called, when there are problems with the retrieval of image data.
+ *
+ * The implementation may use this to indicate an error.
+ */
+ virtual void fatal () = 0;
+};
+
+/**
+ * \brief Implementation of ImgRenderer, which distributes all calls
+ * to a set of other implementations of ImgRenderer.
+ *
+ * The order of the call children is not defined, especially not
+ * identical to the order in which they have been added.
+ */
+class ImgRendererDist: public ImgRenderer
+{
+ lout::container::typed::HashSet <lout::object::TypedPointer <ImgRenderer> >
+ *children;
+
+public:
+ inline ImgRendererDist ()
+ { children = new lout::container::typed::HashSet
+ <lout::object::TypedPointer <ImgRenderer> > (true); }
+ ~ImgRendererDist () { delete children; }
+
+ void setBuffer (core::Imgbuf *buffer, bool resize);
+ void drawRow (int row);
+ void finish ();
+ void fatal ();
+
+ void put (ImgRenderer *child)
+ { children->put (new lout::object::TypedPointer <ImgRenderer> (child)); }
+ void remove (ImgRenderer *child)
+ { lout::object::TypedPointer <ImgRenderer> tp (child);
+ children->remove (&tp); }
+};
+
+} // namespace core
+} // namespace dw
+
+#endif // __DW_IMGRENDERER_HH__
+
+
diff --git a/dw/iterator.cc b/dw/iterator.cc
new file mode 100644
index 0000000..de934d0
--- /dev/null
+++ b/dw/iterator.cc
@@ -0,0 +1,920 @@
+/*
+ * RTFL (originally part of dillo)
+ *
+ * Copyright 2005-2007 Sebastian Geerken <sgeerken@dillo.org>
+ *
+ * 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; with the following exception:
+ *
+ * The copyright holders of RTFL give you permission to link this file
+ * statically or dynamically against all versions of the graphviz
+ * library, which are published by AT&T Corp. under one of the following
+ * licenses:
+ *
+ * - Common Public License version 1.0 as published by International
+ * Business Machines Corporation (IBM), or
+ * - Eclipse Public License version 1.0 as published by the Eclipse
+ * Foundation.
+ *
+ * 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/>.
+ */
+
+
+
+#include "core.hh"
+#include <limits.h>
+
+using namespace lout;
+
+namespace dw {
+namespace core {
+
+// --------------
+// Iterator
+// --------------
+
+Iterator::Iterator(Widget *widget, Content::Type mask, bool atEnd)
+{
+ this->widget = widget;
+ this->mask = mask;
+}
+
+Iterator::Iterator(Iterator &it): object::Comparable ()
+{
+ widget = it.widget;
+ content = it.content;
+}
+
+Iterator::~Iterator()
+{
+}
+
+bool Iterator::equals (Object *other)
+{
+ Iterator *otherIt = (Iterator*)other;
+ return
+ this == otherIt ||
+ (getWidget() == otherIt->getWidget() && compareTo(otherIt) == 0);
+}
+
+void Iterator::intoStringBuffer(misc::StringBuffer *sb)
+{
+ sb->append ("{ widget = ");
+ //widget->intoStringBuffer (sb);
+ sb->appendPointer (widget);
+ sb->append (" (");
+ sb->append (widget->getClassName());
+ sb->append (")>");
+
+ sb->append (", mask = ");
+ Content::maskIntoStringBuffer (mask, sb);
+
+ sb->append (", content = ");
+ Content::intoStringBuffer (&content, sb);
+
+ sb->append (" }");
+}
+
+/**
+ * \brief Delete the iterator.
+ *
+ * The destructor is hidden, implementations may use optimizations for
+ * the allocation. (Will soon be the case for dw::core::EmptyIteratorFactory.)
+ */
+void Iterator::unref ()
+{
+ delete this;
+}
+
+/**
+ * \brief Scrolls the viewport, so that the region between \em it1 and
+ * \em it2 is seen, according to \em hpos and \em vpos.
+ *
+ * The parameters \em start and \em end have the same meaning as in
+ * dw::core::Iterator::getAllocation, \em start refers
+ * to \em it1, while \em end rerers to \em it2.
+ *
+ * If \em it1 and \em it2 point to the same location (see code), only
+ * \em it1 is regarded, and both belowstart and belowend refer to it.
+ */
+void Iterator::scrollTo (Iterator *it1, Iterator *it2, int start, int end,
+ HPosition hpos, VPosition vpos)
+{
+ Allocation alloc1, alloc2, alloc;
+ int x1, x2, y1, y2;
+ DeepIterator *eit1, *eit2, *eit3;
+ int curStart, curEnd, cmp;
+ bool atStart;
+
+ if (it1->equals(it2)) {
+ it1->getAllocation (start, end, &alloc);
+ it1->getWidget()->getLayout()->scrollTo (hpos, vpos, alloc.x, alloc.y,
+ alloc.width,
+ alloc.ascent + alloc.descent);
+ } else {
+ // First, determine the rectangle all iterators from it1 and it2
+ // allocate, i.e. the smallest rectangle containing all allocations of
+ // these iterators.
+ eit1 = new DeepIterator (it1);
+ eit2 = new DeepIterator (it2);
+
+ x1 = INT_MAX;
+ x2 = INT_MIN;
+ y1 = INT_MAX;
+ y2 = INT_MIN;
+
+ for (eit3 = (DeepIterator*)eit1->clone (), atStart = true;
+ (cmp = eit3->compareTo (eit2)) <= 0;
+ eit3->next (), atStart = false) {
+ if (atStart)
+ curStart = start;
+ else
+ curStart = 0;
+
+ if (cmp == 0)
+ curEnd = end;
+ else
+ curEnd = INT_MAX;
+
+ eit3->getAllocation (curStart, curEnd, &alloc);
+ x1 = misc::min (x1, alloc.x);
+ x2 = misc::max (x2, alloc.x + alloc.width);
+ y1 = misc::min (y1, alloc.y);
+ y2 = misc::max (y2, alloc.y + alloc.ascent + alloc.descent);
+ }
+
+ delete eit3;
+ delete eit2;
+ delete eit1;
+
+ it1->getAllocation (start, INT_MAX, &alloc1);
+ it2->getAllocation (0, end, &alloc2);
+
+ if (alloc1.x > alloc2.x) {
+ //
+ // This is due to a line break within the region. When the line is
+ // longer than the viewport, and the region is actually quite short,
+ // the user would not see anything of the region, as in this figure
+ // (with region marked as "#"):
+ //
+ // +----------+ ,-- alloc1
+ // | | V
+ // | | ### ###
+ // ### ### | |
+ // ^ | | <-- viewport
+ // | +----------+
+ // `-- alloc2
+ // |----------------------------|
+ // width
+ //
+ // Therefore, we make the region smaller, so that the region will be
+ // displayed like this:
+ //
+ // ,-- alloc1
+ // +----|-----+
+ // | V |
+ // | ### ###|
+ // ### ### | |
+ // ^ | | <-- viewport
+ // `-- alloc2 +----------+
+ // |----------|
+ // width
+ //
+
+ /** \todo Changes in the viewport size, until the idle function is
+ * called, are not regarded. */
+
+ if (it1->getWidget()->getLayout()->getUsesViewport() &&
+ x2 - x1 > it1->getWidget()->getLayout()->getWidthViewport()) {
+ x1 = x2 - it1->getWidget()->getLayout()->getWidthViewport();
+ x2 = x1 + it1->getWidget()->getLayout()->getWidthViewport();
+ }
+ }
+
+ if (alloc1.y > alloc2.y) {
+ // This is similar to the case above, e.g. if the region ends in
+ // another table column.
+ if (it1->getWidget()->getLayout()->getUsesViewport() &&
+ y2 - y1 > it1->getWidget()->getLayout()->getHeightViewport()) {
+ y1 = y2 - it1->getWidget()->getLayout()->getHeightViewport();
+ y2 = y1 + it1->getWidget()->getLayout()->getHeightViewport();
+ }
+ }
+
+ it1->getWidget()->getLayout()->scrollTo (hpos, vpos,
+ x1, y1, x2 - x1, y2 - y1);
+ }
+}
+
+
+void Iterator::print ()
+{
+ misc::StringBuffer sb;
+ intoStringBuffer (&sb);
+ printf ("%s", sb.getChars ());
+}
+
+// -------------------
+// EmptyIterator
+// -------------------
+
+EmptyIterator::EmptyIterator (Widget *widget, Content::Type mask, bool atEnd):
+ Iterator (widget, mask, atEnd)
+{
+ this->content.type = (atEnd ? Content::END : Content::START);
+}
+
+EmptyIterator::EmptyIterator (EmptyIterator &it): Iterator (it)
+{
+}
+
+object::Object *EmptyIterator::clone ()
+{
+ return new EmptyIterator (*this);
+}
+
+int EmptyIterator::compareTo (object::Comparable *other)
+{
+ EmptyIterator *otherIt = (EmptyIterator*)other;
+
+ if (content.type == otherIt->content.type)
+ return 0;
+ else if (content.type == Content::START)
+ return -1;
+ else
+ return +1;
+}
+
+bool EmptyIterator::next ()
+{
+ content.type = Content::END;
+ return false;
+}
+
+bool EmptyIterator::prev ()
+{
+ content.type = Content::START;
+ return false;
+}
+
+void EmptyIterator::highlight (int start, int end, HighlightLayer layer)
+{
+}
+
+void EmptyIterator::unhighlight (int direction, HighlightLayer layer)
+{
+}
+
+void EmptyIterator::getAllocation (int start, int end, Allocation *allocation)
+{
+}
+
+// ------------------
+// TextIterator
+// ------------------
+
+TextIterator::TextIterator (Widget *widget, Content::Type mask, bool atEnd,
+ const char *text): Iterator (widget, mask, atEnd)
+{
+ this->content.type = (atEnd ? Content::END : Content::START);
+ this->text = (mask & Content::TEXT) ? text : NULL;
+}
+
+TextIterator::TextIterator (TextIterator &it): Iterator (it)
+{
+ text = it.text;
+}
+
+int TextIterator::compareTo (object::Comparable *other)
+{
+ TextIterator *otherIt = (TextIterator*)other;
+
+ if (content.type == otherIt->content.type)
+ return 0;
+
+ switch (content.type) {
+ case Content::START:
+ return -1;
+
+ case Content::TEXT:
+ if (otherIt->content.type == Content::START)
+ return +1;
+ else
+ return -1;
+
+ case Content::END:
+ return +1;
+
+ default:
+ misc::assertNotReached();
+ return 0;
+ }
+}
+
+bool TextIterator::next ()
+{
+ if (content.type == Content::START && text != NULL) {
+ content.type = Content::TEXT;
+ content.text = text;
+ return true;
+ } else {
+ content.type = Content::END;
+ return false;
+ }
+}
+
+bool TextIterator::prev ()
+{
+ if (content.type == Content::END && text != NULL) {
+ content.type = Content::TEXT;
+ content.text = text;
+ return true;
+ } else {
+ content.type = Content::START;
+ return false;
+ }
+}
+
+void TextIterator::getAllocation (int start, int end, Allocation *allocation)
+{
+ // Return the allocation of the widget.
+ *allocation = *(getWidget()->getAllocation ());
+}
+
+// ------------------
+// DeepIterator
+// ------------------
+
+DeepIterator::Stack::~Stack ()
+{
+ for (int i = 0; i < size (); i++)
+ get(i)->unref ();
+}
+
+/*
+ * The following two methods are used by dw::core::DeepIterator::DeepIterator,
+ * when the passed dw::core::Iterator points to a widget. Since a
+ * dw::core::DeepIterator never returns a widget, the dw::core::Iterator has
+ * to be corrected, by searching for the next content downwards (within the
+ * widget pointed to), forwards, and backwards (in the traversed tree).
+ */
+
+/*
+ * Search downwards. If fromEnd is true, start search at the end,
+ * otherwise at the beginning.
+ */
+Iterator *DeepIterator::searchDownward (Iterator *it, Content::Type mask,
+ bool fromEnd)
+{
+ Iterator *it2, *it3;
+
+ //DEBUG_MSG (1, "%*smoving down (%swards) from %s\n",
+ // indent, "", from_end ? "back" : "for", a_Dw_iterator_text (it));
+
+ assert (it->getContent()->type & Content::ANY_WIDGET);
+ it2 = it->getContent()->widget->iterator (mask, fromEnd);
+
+ if (it2 == NULL) {
+ // Moving downwards failed.
+ //DEBUG_MSG (1, "%*smoving down failed\n", indent, "");
+ return NULL;
+ }
+
+ while (fromEnd ? it2->prev () : it2->next ()) {
+ //DEBUG_MSG (1, "%*sexamining %s\n",
+ // indent, "", a_Dw_iterator_text (it2));
+
+ if (it2->getContent()->type & Content::ANY_WIDGET) {
+ // Another widget. Search in it downwards.
+ it3 = searchDownward (it2, mask, fromEnd);
+ if (it3 != NULL) {
+ it2->unref ();
+ return it3;
+ }
+ // Else continue in this widget.
+ } else {
+ // Success!
+ //DEBUG_MSG (1, "%*smoving down succeeded: %s\n",
+ // indent, "", a_Dw_iterator_text (it2));
+ return it2;
+ }
+ }
+
+ // Nothing found.
+ it2->unref ();
+ //DEBUG_MSG (1, "%*smoving down failed (nothing found)\n", indent, "");
+ return NULL;
+}
+
+/*
+ * Search sidewards. fromEnd specifies the direction, false means forwards,
+ * true means backwards.
+ */
+Iterator *DeepIterator::searchSideward (Iterator *it, Content::Type mask,
+ bool fromEnd)
+{
+ Iterator *it2, *it3;
+
+ //DEBUG_MSG (1, "%*smoving %swards from %s\n",
+ // indent, "", from_end ? "back" : "for", a_Dw_iterator_text (it));
+
+ assert (it->getContent()->type & Content::ANY_WIDGET);
+ it2 = it->cloneIterator ();
+
+ while (fromEnd ? it2->prev () : it2->next ()) {
+ if (it2->getContent()->type & Content::ANY_WIDGET) {
+ // Search downwards in this widget.
+ it3 = searchDownward (it2, mask, fromEnd);
+ if (it3 != NULL) {
+ it2->unref ();
+ //DEBUG_MSG (1, "%*smoving %swards succeeded: %s\n",
+ // indent, "", from_end ? "back" : "for",
+ // a_Dw_iterator_text (it3));
+ return it3;
+ }
+ // Else continue in this widget.
+ } else {
+ // Success!
+ // DEBUG_MSG (1, "%*smoving %swards succeeded: %s\n",
+ // indent, "", from_end ? "back" : "for",
+ // a_Dw_iterator_text (it2));
+ return it2;
+ }
+ }
+
+ /* Nothing found, go upwards in the tree (if possible). */
+ it2->unref ();
+ Widget *respParent = getRespectiveParent (it->getWidget(), it->getMask());
+ if (respParent) {
+ it2 = respParent->iterator (mask, false);
+ while (true) {
+ if (!it2->next ())
+ misc::assertNotReached ();
+
+ if (it2->getContent()->type & Content::ANY_WIDGET &&
+ it2->getContent()->widget == it->getWidget ()) {
+ it3 = searchSideward (it2, mask, fromEnd);
+ it2->unref ();
+ //DEBUG_MSG (1, "%*smoving %swards succeeded: %s\n",
+ // indent, "", from_end ? "back" : "for",
+ // a_Dw_iterator_text (it3));
+ return it3;
+ }
+ }
+ }
+
+ // Nothing found at all.
+ // DEBUG_MSG (1, "%*smoving %swards failed (nothing found)\n",
+ // indent, "", from_end ? "back" : "for");
+ return NULL;
+}
+
+Widget *DeepIterator::getRespectiveParent (Widget *widget, Content::Type mask)
+{
+ // Return, depending on which is requested indirectly (follow
+ // references or containments) the parent (container) or the
+ // generator. At this point, the type of the parent/generator is
+ // not known (since the parent/generator is not known), so we have
+ // to examine the mask. This is the reason why only one of
+ // WIDGET_OOF_CONT and WIDGET_OOF_REF is allowed.
+
+ return (mask & Content::WIDGET_OOF_REF) ?
+ widget->getGenerator() : widget->getParent();
+}
+
+int DeepIterator::getRespectiveLevel (Widget *widget, Content::Type mask)
+{
+ // Similar to getRespectiveParent.
+
+ return (mask & Content::WIDGET_OOF_REF) ?
+ widget->getGeneratorLevel() : widget->getLevel();
+}
+
+/**
+ * \brief Create a new deep iterator from an existing dw::core::Iterator.
+ *
+ * The content of the return value will be the content of \em it. If within
+ * the widget tree, there is no non-widget content, the resulting deep
+ * iterator is empty (denoted by dw::core::DeepIterator::stack == NULL).
+ *
+ * Notes:
+ *
+ * <ol>
+ * <li> The mask of \em i" must include DW_CONTENT_WIDGET, but
+ * dw::core::DeepIterator::next will never return widgets.
+ * </ol>
+ */
+DeepIterator::DeepIterator (Iterator *it)
+{
+ //printf ("Starting creating DeepIterator %p ...\n", this);
+ //printf ("Initial iterator: ");
+ //it->print ();
+ //printf ("\n");
+
+ // Widgets out of flow are either followed widtin containers, or
+ // generators. Both (and also nothing at all) is not allowed. See
+ // also comment in getRespectiveParent.
+ int oofMask =
+ it->getMask() & (Content::WIDGET_OOF_CONT | Content::WIDGET_OOF_REF);
+ assert (oofMask == Content::WIDGET_OOF_CONT ||
+ oofMask == Content::WIDGET_OOF_REF);
+
+ //DEBUG_MSG (1, "a_Dw_ext_iterator_new: %s\n", a_Dw_iterator_text (it));
+
+ // Clone input iterator, so the iterator passed as parameter
+ // remains untouched.
+ it = it->cloneIterator ();
+ this->mask = it->getMask ();
+
+ hasContents = true;
+
+ // If it points to a widget, find a near non-widget content,
+ // since an DeepIterator should never return widgets.
+ if (it->getContent()->type & Content::ANY_WIDGET) {
+ Iterator *it2;
+
+ // The second argument of searchDownward is actually a matter of
+ // taste :-)
+ if ((it2 = searchDownward (it, mask, false)) ||
+ (it2 = searchSideward (it, mask, false)) ||
+ (it2 = searchSideward (it, mask, true))) {
+ it->unref ();
+ it = it2;
+ } else {
+ // This may happen, when a page does not contain any non-widget
+ // content.
+ //DEBUG_MSG (1, "a_Dw_ext_iterator_new got totally helpless!\n");
+ it->unref ();
+ hasContents = false;
+ }
+ }
+
+ //DEBUG_MSG (1, " => %s\n", a_Dw_iterator_text (it));
+
+ if (hasContents) {
+ // If this widget has parents, we must construct appropriate iterators.
+ //
+ // \todo There may be a faster way instead of iterating through the
+ // parent widgets.
+
+ //printf ("Starting with: ");
+ //it->print ();
+ //printf ("\n");
+
+ // Construct the iterators.
+ int thisLevel = getRespectiveLevel (it->getWidget()), level;
+ Widget *w;
+ for (w = it->getWidget (), level = thisLevel;
+ getRespectiveParent (w) != NULL;
+ w = getRespectiveParent (w), level--) {
+ Iterator *it = getRespectiveParent(w)->iterator (mask, false);
+
+ //printf (" parent: %s %p\n", w->getClassName (), w);
+
+ stack.put (it, level - 1);
+ while (true) {
+ //printf (" ");
+ //it->print ();
+ //printf ("\n");
+
+ bool hasNext = it->next();
+ assert (hasNext);
+
+ if (it->getContent()->type & Content::ANY_WIDGET &&
+ it->getContent()->widget == w)
+ break;
+ }
+
+ //printf (" %d: ", level - 1);
+ //it->print ();
+ //printf ("\n");
+ }
+
+ stack.put (it, thisLevel);
+ content = *(it->getContent());
+ }
+
+ //printf ("... done creating DeepIterator %p.\n", this);
+}
+
+
+DeepIterator::~DeepIterator ()
+{
+ //printf ("Deleting DeepIterator %p ...\n", this);
+}
+
+object::Object *DeepIterator::clone ()
+{
+ DeepIterator *it = new DeepIterator ();
+
+ for (int i = 0; i < stack.size (); i++)
+ it->stack.put (stack.get(i)->cloneIterator (), i);
+
+ it->mask = mask;
+ it->content = content;
+ it->hasContents = hasContents;
+
+ return it;
+}
+
+int DeepIterator::compareTo (object::Comparable *other)
+{
+ DeepIterator *otherDeepIterator = (DeepIterator*)other;
+
+ //printf ("Compare: %s\n", stack.toString ());
+ //printf (" to: %s\n", otherDeepIterator->stack.toString ());
+
+ // Search the highest level, where the widgets are the same.
+ int level = 0;
+
+ // The Comparable interface does not define "uncomparable". Deep
+ // iterators are only comparable if they belong to the same widget
+ // tree, so have the same widget at the bottom at the
+ // stack. If this is not the case, we abort.
+
+ assert (stack.size() > 0);
+ assert (otherDeepIterator->stack.size() > 0);
+
+ //printf ("Equal? The %s %p (of %p) and the %s %p (of %p)?\n",
+ // stack.get(0)->getWidget()->getClassName(),
+ // stack.get(0)->getWidget(), this,
+ // otherDeepIterator->stack.get(0)->getWidget()->getClassName(),
+ // otherDeepIterator->stack.get(0)->getWidget(), otherDeepIterator);
+
+ assert (stack.get(0)->getWidget()
+ == otherDeepIterator->stack.get(level)->getWidget());
+
+ while (stack.get(level)->getWidget ()
+ == otherDeepIterator->stack.get(level)->getWidget ()) {
+ if (level == stack.size() - 1 ||
+ level == otherDeepIterator->stack.size() - 1)
+ break;
+ level++;
+ }
+
+ //printf (" => level = %d (temorally)\n", level);
+
+ while (stack.get(level)->getWidget ()
+ != otherDeepIterator->stack.get(level)->getWidget ())
+ level--;
+
+ //printf (" => level = %d (finally)\n", level);
+
+ return stack.get(level)->compareTo (otherDeepIterator->stack.get(level));
+}
+
+DeepIterator *DeepIterator::createVariant(Iterator *it)
+{
+ /** \todo Not yet implemented, and actually not yet needed very much. */
+ return new DeepIterator (it);
+}
+
+bool DeepIterator::isEmpty () {
+ return !hasContents;
+}
+
+/**
+ * \brief Move iterator forward and store content it.
+ *
+ * Returns true on success.
+ */
+bool DeepIterator::next ()
+{
+ Iterator *it = stack.getTop ();
+
+ if (it->next ()) {
+ if (it->getContent()->type & Content::ANY_WIDGET) {
+ // Widget: new iterator on stack, to search in this widget.
+ stack.push (it->getContent()->widget->iterator (mask, false));
+ return next ();
+ } else {
+ // Simply return the content of the iterartor.
+ content = *(it->getContent ());
+ return true;
+ }
+ } else {
+ // No more data in the top-most widget.
+ if (stack.size () > 1) {
+ // Pop iterator from stack, and move to next item in the old one.
+ stack.pop ();
+ return next ();
+ } else {
+ // Stack is empty.
+ content.type = Content::END;
+ return false;
+ }
+ }
+}
+
+/**
+ * \brief Move iterator backward and store content it.
+ *
+ * Returns true on success.
+ */
+bool DeepIterator::prev ()
+{
+ Iterator *it = stack.getTop ();
+
+ if (it->prev ()) {
+ if (it->getContent()->type & Content::ANY_WIDGET) {
+ // Widget: new iterator on stack, to search in this widget.
+ stack.push (it->getContent()->widget->iterator (mask, true));
+ return prev ();
+ } else {
+ // Simply return the content of the iterartor.
+ content = *(it->getContent ());
+ return true;
+ }
+ } else {
+ // No more data in the top-most widget.
+ if (stack.size () > 1) {
+ // Pop iterator from stack, and move to next item in the old one.
+ stack.pop ();
+ return prev ();
+ } else {
+ // Stack is empty.
+ content.type = Content::START;
+ return false;
+ }
+ }
+}
+
+// -----------------
+// CharIterator
+// -----------------
+
+CharIterator::CharIterator ()
+{
+ it = NULL;
+}
+
+/**
+ * \brief ...
+ *
+ * If followReferences is true, only the reference are followed, when
+ * the container and generator for a widget is different. If false,
+ * only the container is followed.
+ */
+CharIterator::CharIterator (Widget *widget, bool followReferences)
+{
+ Iterator *i =
+ widget->iterator (Content::maskForSelection (followReferences), false);
+ it = new DeepIterator (i);
+ i->unref ();
+ ch = START;
+}
+
+CharIterator::~CharIterator ()
+{
+ if (it)
+ delete it;
+}
+
+object::Object *CharIterator::clone()
+{
+ CharIterator *cloned = new CharIterator ();
+ cloned->it = it->cloneDeepIterator ();
+ cloned->ch = ch;
+ cloned->pos = pos;
+ return cloned;
+}
+
+int CharIterator::compareTo(object::Comparable *other)
+{
+ CharIterator *otherIt = (CharIterator*)other;
+ int c = it->compareTo(otherIt->it);
+ if (c != 0)
+ return c;
+ else
+ return pos - otherIt->pos;
+}
+
+bool CharIterator::next ()
+{
+ if (ch == START || it->getContent()->type == Content::BREAK ||
+ (it->getContent()->type == Content::TEXT &&
+ it->getContent()->text[pos] == 0)) {
+ if (it->next()) {
+ if (it->getContent()->type == Content::BREAK)
+ ch = '\n';
+ else { // if (it->getContent()->type == Content::TEXT)
+ pos = 0;
+ ch = it->getContent()->text[pos];
+ if (ch == 0)
+ // should not happen, actually
+ return next ();
+ }
+ return true;
+ }
+ else {
+ ch = END;
+ return false;
+ }
+ } else if (ch == END)
+ return false;
+ else {
+ // at this point, it->getContent()->type == Content::TEXT
+ pos++;
+ ch = it->getContent()->text[pos];
+ if (ch == 0) {
+ if (it->getContent()->space) {
+ ch = ' ';
+ } else {
+ return next ();
+ }
+ }
+
+ return true;
+ }
+}
+
+bool CharIterator::prev ()
+{
+ if (ch == END || it->getContent()->type == Content::BREAK ||
+ (it->getContent()->type == Content::TEXT && pos == 0)) {
+ if (it->prev()) {
+ if (it->getContent()->type == Content::BREAK)
+ ch = '\n';
+ else { // if (it->getContent()->type == Content::TEXT)
+ if (it->getContent()->text[0] == 0)
+ return prev ();
+ else {
+ pos = strlen (it->getContent()->text);
+ if (it->getContent()->space) {
+ ch = ' ';
+ } else {
+ pos--;
+ ch = it->getContent()->text[pos];
+ }
+ }
+ }
+ return true;
+ }
+ else {
+ ch = START;
+ return false;
+ }
+ } else if (ch == START)
+ return false;
+ else {
+ // at this point, it->getContent()->type == Content::TEXT
+ pos--;
+ ch = it->getContent()->text[pos];
+ return true;
+ }
+}
+
+void CharIterator::highlight (CharIterator *it1, CharIterator *it2,
+ HighlightLayer layer)
+{
+ if (it2->getChar () == CharIterator::END)
+ it2->prev ();
+
+ if (it1->it->compareTo (it2->it) == 0)
+ // Only one content => highlight part of it.
+ it1->it->highlight (it1->pos, it2->pos, layer);
+ else {
+ DeepIterator *it = it1->it->cloneDeepIterator ();
+ int c;
+ bool start;
+ for (start = true;
+ (c = it->compareTo (it2->it)) <= 0;
+ it->next (), start = false) {
+ int endOfWord =
+ it->getContent()->type == Content::TEXT ?
+ strlen (it->getContent()->text) : 1;
+ if (start) // first iteration
+ it->highlight (it1->pos, endOfWord, layer);
+ else if (c == 0) // last iteration
+ it->highlight (0, it2->pos, layer);
+ else
+ it->highlight (0, endOfWord, layer);
+ }
+ delete it;
+ }
+}
+
+void CharIterator::unhighlight (CharIterator *it1, CharIterator *it2,
+ HighlightLayer layer)
+{
+ if (it1->it->compareTo (it2->it) == 0)
+ // Only one content => unhighlight it (only for efficiency).
+ it1->it->unhighlight (0, layer);
+ else {
+ DeepIterator *it = it1->it->cloneDeepIterator ();
+ for (; it->compareTo (it2->it) <= 0; it->next ())
+ it->unhighlight (-1, layer);
+ delete it;
+ }
+}
+
+} // namespace core
+} // namespace dw
diff --git a/dw/iterator.hh b/dw/iterator.hh
new file mode 100644
index 0000000..abf31d0
--- /dev/null
+++ b/dw/iterator.hh
@@ -0,0 +1,271 @@
+#ifndef __ITERATOR_HH__
+#define __ITERATOR_HH__
+
+#ifndef __INCLUDED_FROM_DW_CORE_HH__
+# error Do not include this file directly, use "core.hh" instead.
+#endif
+
+namespace dw {
+namespace core {
+
+/**
+ * \brief Iterators are used to iterate through the contents of a widget.
+ *
+ * When using iterators, you should care about the results of
+ * dw::core::Widget::hasContents.
+ *
+ * \sa dw::core::Widget::iterator
+ */
+class Iterator: public lout::object::Comparable
+{
+protected:
+ Iterator(Widget *widget, Content::Type mask, bool atEnd);
+ Iterator(Iterator &it);
+ ~Iterator();
+
+ Content content;
+
+private:
+ Widget *widget;
+ Content::Type mask;
+
+public:
+ bool equals (Object *other);
+ void intoStringBuffer(lout::misc::StringBuffer *sb);
+
+ inline Widget *getWidget () { return widget; }
+ inline Content *getContent () { return &content; }
+ inline Content::Type getMask () { return mask; }
+
+ virtual void unref ();
+
+ /**
+ * \brief Move iterator forward and store content it.
+ *
+ * Returns true on success.
+ */
+ virtual bool next () = 0;
+
+ /**
+ * \brief Move iterator backward and store content it.
+ *
+ * Returns true on success.
+ */
+ virtual bool prev () = 0;
+
+ /**
+ * \brief Extend highlighted region to contain part of the current content.
+ *
+ * For text, start and end define the
+ * characters, otherwise, the shape is defined as [0, 1], i.e. for
+ * highlighting a whole dw::core::Content, pass 0 and >= 1.
+ * To unhighlight see also dw::core::Iterator::unhighlight.
+ */
+ virtual void highlight (int start, int end, HighlightLayer layer) = 0;
+
+ /**
+ * \brief Shrink highlighted region to no longer contain the
+ * current content.
+ *
+ * The direction parameter indicates whether the highlighted region should
+ * be reduced from the start (direction > 0) or from the end
+ * (direction < 0). If direction is 0 all content is unhighlighted.
+ */
+ virtual void unhighlight (int direction, HighlightLayer layer) = 0;
+
+ /**
+ * \brief Return the shape, which a part of the item, the iterator points
+ * on, allocates.
+ *
+ * The parameters start and end have the same meaning as in
+ * DwIterator::highlight().
+ */
+ virtual void getAllocation (int start, int end, Allocation *allocation) = 0;
+
+ inline Iterator *cloneIterator () { return (Iterator*)clone(); }
+
+ static void scrollTo (Iterator *it1, Iterator *it2, int start, int end,
+ HPosition hpos, VPosition vpos);
+
+ virtual void print ();
+};
+
+
+/**
+ * \brief This implementation of dw::core::Iterator can be used by widgets
+ * with no contents.
+ */
+class EmptyIterator: public Iterator
+{
+private:
+ EmptyIterator (EmptyIterator &it);
+
+public:
+ EmptyIterator (Widget *widget, Content::Type mask, bool atEnd);
+
+ lout::object::Object *clone();
+ int compareTo(lout::object::Comparable *other);
+ bool next ();
+ bool prev ();
+ void highlight (int start, int end, HighlightLayer layer);
+ void unhighlight (int direction, HighlightLayer layer);
+ void getAllocation (int start, int end, Allocation *allocation);
+};
+
+
+/**
+ * \brief This implementation of dw::core::Iterator can be used by widgets
+ * having one text word as contents
+ */
+class TextIterator: public Iterator
+{
+private:
+ /** May be NULL, in this case, the next is skipped. */
+ const char *text;
+
+ TextIterator (TextIterator &it);
+
+public:
+ TextIterator (Widget *widget, Content::Type mask, bool atEnd,
+ const char *text);
+
+ int compareTo(lout::object::Comparable *other);
+
+ bool next ();
+ bool prev ();
+ void getAllocation (int start, int end, Allocation *allocation);
+};
+
+
+/**
+ * \brief A stack of iterators, to iterate recursively through a widget tree.
+ *
+ * This class is similar to dw::core::Iterator, but not
+ * created by a widget, but explicitly from another iterator. Deep
+ * iterators do not have the limitation, that iteration is only done within
+ * a widget, instead, child widgets are iterated through recursively.
+ */
+class DeepIterator: public lout::object::Comparable
+{
+private:
+ class Stack: public lout::container::typed::Vector<Iterator>
+ {
+ public:
+ inline Stack (): lout::container::typed::Vector<Iterator> (4, false) { }
+ ~Stack ();
+ inline Iterator *getTop () { return get (size () - 1); }
+ inline void push (Iterator *it) { put(it, -1); }
+ inline void pop() { getTop()->unref (); remove (size () - 1); }
+ };
+
+ Stack stack;
+
+ static Iterator *searchDownward (Iterator *it, Content::Type mask,
+ bool fromEnd);
+ static Iterator *searchSideward (Iterator *it, Content::Type mask,
+ bool fromEnd);
+
+ Content::Type mask;
+ Content content;
+ bool hasContents;
+
+ inline DeepIterator () { }
+
+ static Widget *getRespectiveParent (Widget *widget, Content::Type mask);
+ inline Widget *getRespectiveParent (Widget *widget) {
+ return getRespectiveParent (widget, mask);
+ }
+
+ static int getRespectiveLevel (Widget *widget, Content::Type mask);
+ inline int getRespectiveLevel (Widget *widget) {
+ return getRespectiveLevel (widget, mask);
+ }
+
+public:
+ DeepIterator(Iterator *it);
+ ~DeepIterator();
+
+ lout::object::Object *clone ();
+
+ DeepIterator *createVariant(Iterator *it);
+ inline Iterator *getTopIterator () { return stack.getTop(); }
+ inline Content *getContent () { return &content; }
+
+ bool isEmpty ();
+
+ bool next ();
+ bool prev ();
+ inline DeepIterator *cloneDeepIterator() { return (DeepIterator*)clone(); }
+ int compareTo(lout::object::Comparable *other);
+
+ /**
+ * \brief Highlight a part of the current content.
+ *
+ * Unhighlight the current content by passing -1 as start (see also
+ * (dw::core::Iterator::unhighlight). For text, start and end define the
+ * characters, otherwise, the shape is defined as [0, 1], i.e. for
+ * highlighting a whole dw::core::Content, pass 0 and >= 1.
+ */
+ inline void highlight (int start, int end, HighlightLayer layer)
+ { stack.getTop()->highlight (start, end, layer); }
+
+ /**
+ * \brief Return the shape, which a part of the item, the iterator points
+ * on, allocates.
+ *
+ * The parameters start and end have the same meaning as in
+ * DwIterator::highlight().
+ */
+ inline void getAllocation (int start, int end, Allocation *allocation)
+ { stack.getTop()->getAllocation (start, end, allocation); }
+
+ inline void unhighlight (int direction, HighlightLayer layer)
+ { stack.getTop()->unhighlight (direction, layer); }
+
+ inline static void scrollTo (DeepIterator *it1, DeepIterator *it2,
+ int start, int end,
+ HPosition hpos, VPosition vpos)
+ { Iterator::scrollTo(it1->stack.getTop(), it2->stack.getTop(),
+ start, end, hpos, vpos); }
+};
+
+class CharIterator: public lout::object::Comparable
+{
+public:
+ // START and END must not clash with any char value
+ // neither for signed nor unsigned char.
+ enum { START = 257, END = 258 };
+
+private:
+ DeepIterator *it;
+ int pos, ch;
+
+ CharIterator ();
+
+public:
+ CharIterator (Widget *widget, bool followReferences);
+ ~CharIterator ();
+
+ lout::object::Object *clone();
+ int compareTo(lout::object::Comparable *other);
+
+ bool next ();
+ bool prev ();
+ inline int getChar() { return ch; }
+ inline CharIterator *cloneCharIterator() { return (CharIterator*)clone(); }
+
+ static void highlight (CharIterator *it1, CharIterator *it2,
+ HighlightLayer layer);
+ static void unhighlight (CharIterator *it1, CharIterator *it2,
+ HighlightLayer layer);
+
+ inline static void scrollTo (CharIterator *it1, CharIterator *it2,
+ HPosition hpos, VPosition vpos)
+ { DeepIterator::scrollTo(it1->it, it2->it, it1->pos, it2->pos,
+ hpos, vpos); }
+};
+
+} // namespace core
+} // namespace dw
+
+#endif // __ITERATOR_HH__
diff --git a/dw/layout.cc b/dw/layout.cc
new file mode 100644
index 0000000..96de6c2
--- /dev/null
+++ b/dw/layout.cc
@@ -0,0 +1,1445 @@
+/*
+ * RTFL (originally part of dillo)
+ *
+ * Copyright 2005-2007 Sebastian Geerken <sgeerken@dillo.org>
+ *
+ * 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; with the following exception:
+ *
+ * The copyright holders of RTFL give you permission to link this file
+ * statically or dynamically against all versions of the graphviz
+ * library, which are published by AT&T Corp. under one of the following
+ * licenses:
+ *
+ * - Common Public License version 1.0 as published by International
+ * Business Machines Corporation (IBM), or
+ * - Eclipse Public License version 1.0 as published by the Eclipse
+ * Foundation.
+ *
+ * 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/>.
+ */
+
+
+
+#include "core.hh"
+
+#include "../lout/msg.h"
+#include "../lout/debug.hh"
+#include "../lout/misc.hh"
+
+using namespace lout;
+using namespace lout::container;
+using namespace lout::object;
+
+namespace dw {
+namespace core {
+
+bool Layout::LayoutImgRenderer::readyToDraw ()
+{
+ return true;
+}
+
+void Layout::LayoutImgRenderer::getBgArea (int *x, int *y, int *width,
+ int *height)
+{
+ // TODO Actually not padding area, but visible area?
+ getRefArea (x, y, width, height);
+}
+
+void Layout::LayoutImgRenderer::getRefArea (int *xRef, int *yRef, int *widthRef,
+ int *heightRef)
+{
+ *xRef = 0;
+ *yRef = 0;
+ *widthRef = misc::max (layout->viewportWidth
+ - (layout->canvasHeightGreater ?
+ layout->vScrollbarThickness : 0),
+ layout->canvasWidth);
+ *heightRef = misc::max (layout->viewportHeight
+ - layout->hScrollbarThickness,
+ layout->canvasAscent + layout->canvasDescent);
+}
+
+style::StyleImage *Layout::LayoutImgRenderer::getBackgroundImage ()
+{
+ return layout->bgImage;
+}
+
+style::BackgroundRepeat Layout::LayoutImgRenderer::getBackgroundRepeat ()
+{
+ return layout->bgRepeat;
+}
+
+style::BackgroundAttachment
+ Layout::LayoutImgRenderer::getBackgroundAttachment ()
+{
+ return layout->bgAttachment;
+}
+
+style::Length Layout::LayoutImgRenderer::getBackgroundPositionX ()
+{
+ return layout->bgPositionX;
+}
+
+style::Length Layout::LayoutImgRenderer::getBackgroundPositionY ()
+{
+ return layout->bgPositionY;
+}
+
+void Layout::LayoutImgRenderer::draw (int x, int y, int width, int height)
+{
+ layout->queueDraw (x, y, width, height);
+}
+
+// ----------------------------------------------------------------------
+
+void Layout::Receiver::resizeQueued (bool extremesChanged)
+{
+}
+
+void Layout::Receiver::canvasSizeChanged (int width, int ascent, int descent)
+{
+}
+
+// ----------------------------------------------------------------------
+
+bool Layout::Emitter::emitToReceiver (lout::signal::Receiver *receiver,
+ int signalNo, int argc,
+ lout::object::Object **argv)
+{
+ Receiver *layoutReceiver = (Receiver*)receiver;
+
+ switch (signalNo) {
+ case CANVAS_SIZE_CHANGED:
+ layoutReceiver->canvasSizeChanged (((Integer*)argv[0])->getValue (),
+ ((Integer*)argv[1])->getValue (),
+ ((Integer*)argv[2])->getValue ());
+ break;
+
+ case RESIZE_QUEUED:
+ layoutReceiver->resizeQueued (((Boolean*)argv[0])->getValue ());
+ break;
+
+ default:
+ misc::assertNotReached ();
+ }
+
+ return false;
+}
+
+void Layout::Emitter::emitResizeQueued (bool extremesChanged)
+{
+ Boolean ec (extremesChanged);
+ Object *argv[1] = { &ec };
+ emitVoid (RESIZE_QUEUED, 1, argv);
+}
+
+void Layout::Emitter::emitCanvasSizeChanged (int width,
+ int ascent, int descent)
+{
+ Integer w (width), a (ascent), d (descent);
+ Object *argv[3] = { &w, &a, &d };
+ emitVoid (CANVAS_SIZE_CHANGED, 3, argv);
+}
+
+// ----------------------------------------------------------------------
+
+bool Layout::LinkReceiver::enter (Widget *widget, int link, int img,
+ int x, int y)
+{
+ return false;
+}
+
+bool Layout::LinkReceiver::press (Widget *widget, int link, int img,
+ int x, int y, EventButton *event)
+{
+ return false;
+}
+
+bool Layout::LinkReceiver::release (Widget *widget, int link, int img,
+ int x, int y, EventButton *event)
+{
+ return false;
+}
+
+bool Layout::LinkReceiver::click (Widget *widget, int link, int img,
+ int x, int y, EventButton *event)
+{
+ return false;
+}
+
+// ----------------------------------------------------------------------
+
+bool Layout::LinkEmitter::emitToReceiver (lout::signal::Receiver *receiver,
+ int signalNo, int argc,
+ lout::object::Object **argv)
+{
+ LinkReceiver *linkReceiver = (LinkReceiver*)receiver;
+
+ switch (signalNo) {
+ case ENTER:
+ return linkReceiver->enter ((Widget*)argv[0],
+ ((Integer*)argv[1])->getValue (),
+ ((Integer*)argv[2])->getValue (),
+ ((Integer*)argv[3])->getValue (),
+ ((Integer*)argv[4])->getValue ());
+
+ case PRESS:
+ return linkReceiver->press ((Widget*)argv[0],
+ ((Integer*)argv[1])->getValue (),
+ ((Integer*)argv[2])->getValue (),
+ ((Integer*)argv[3])->getValue (),
+ ((Integer*)argv[4])->getValue (),
+ (EventButton*)argv[5]);
+
+ case RELEASE:
+ return linkReceiver->release ((Widget*)argv[0],
+ ((Integer*)argv[1])->getValue (),
+ ((Integer*)argv[2])->getValue (),
+ ((Integer*)argv[3])->getValue (),
+ ((Integer*)argv[4])->getValue (),
+ (EventButton*)argv[5]);
+
+ case CLICK:
+ return linkReceiver->click ((Widget*)argv[0],
+ ((Integer*)argv[1])->getValue (),
+ ((Integer*)argv[2])->getValue (),
+ ((Integer*)argv[3])->getValue (),
+ ((Integer*)argv[4])->getValue (),
+ (EventButton*)argv[5]);
+
+ default:
+ misc::assertNotReached ();
+ }
+ return false;
+}
+
+bool Layout::LinkEmitter::emitEnter (Widget *widget, int link, int img,
+ int x, int y)
+{
+ Integer ilink (link), iimg (img), ix (x), iy (y);
+ Object *argv[5] = { widget, &ilink, &iimg, &ix, &iy };
+ return emitBool (ENTER, 5, argv);
+}
+
+bool Layout::LinkEmitter::emitPress (Widget *widget, int link, int img,
+ int x, int y, EventButton *event)
+{
+ Integer ilink (link), iimg (img), ix (x), iy (y);
+ Object *argv[6] = { widget, &ilink, &iimg, &ix, &iy, event };
+ return emitBool (PRESS, 6, argv);
+}
+
+bool Layout::LinkEmitter::emitRelease (Widget *widget, int link, int img,
+ int x, int y, EventButton *event)
+{
+ Integer ilink (link), iimg (img), ix (x), iy (y);
+ Object *argv[6] = { widget, &ilink, &iimg, &ix, &iy, event };
+ return emitBool (RELEASE, 6, argv);
+}
+
+bool Layout::LinkEmitter::emitClick (Widget *widget, int link, int img,
+ int x, int y, EventButton *event)
+{
+ Integer ilink (link), iimg (img), ix (x), iy (y);
+ Object *argv[6] = { widget, &ilink, &iimg, &ix, &iy, event };
+ return emitBool (CLICK, 6, argv);
+}
+
+// ---------------------------------------------------------------------
+
+Layout::Anchor::~Anchor ()
+{
+ free(name);
+}
+
+// ---------------------------------------------------------------------
+
+Layout::ScrollTarget::~ScrollTarget ()
+{
+}
+
+Layout::ScrollTargetBase::ScrollTargetBase (HPosition hPos, VPosition vPos)
+{
+ this->hPos = hPos;
+ this->vPos = vPos;
+}
+
+HPosition Layout::ScrollTargetBase::getHPos ()
+{
+ return hPos;
+}
+
+VPosition Layout::ScrollTargetBase::getVPos ()
+{
+ return vPos;
+}
+
+Layout::ScrollTargetFixed::ScrollTargetFixed (HPosition hPos, VPosition vPos,
+ int x, int y, int width, int height) :
+ ScrollTargetBase (hPos, vPos)
+{
+ this->x = x;
+ this->y = y;
+ this->width = width;
+ this->height = height;
+}
+
+int Layout::ScrollTargetFixed::getX ()
+{
+ return x;
+}
+
+int Layout::ScrollTargetFixed::getY ()
+{
+ return y;
+}
+
+int Layout::ScrollTargetFixed::getWidth ()
+{
+ return width;
+}
+
+int Layout::ScrollTargetFixed::getHeight ()
+{
+ return height;
+}
+
+Layout::ScrollTargetWidget::ScrollTargetWidget (HPosition hPos, VPosition vPos,
+ Widget *widget) :
+ ScrollTargetBase (hPos, vPos)
+{
+ this->widget = widget;
+}
+
+int Layout::ScrollTargetWidget::getX ()
+{
+ return widget->allocation.x;
+}
+
+int Layout::ScrollTargetWidget::getY ()
+{
+ return widget->allocation.y;
+}
+
+int Layout::ScrollTargetWidget::getWidth ()
+{
+ return widget->allocation.width;
+}
+
+int Layout::ScrollTargetWidget::getHeight ()
+{
+ return widget->allocation.ascent + widget->allocation.descent;
+}
+
+// ----------------------------------------------------------------------
+
+Layout::Layout (Platform *platform)
+{
+ this->platform = platform;
+ view = NULL;
+ topLevel = NULL;
+ widgetAtPoint = NULL;
+
+ queueQueueResizeList = new typed::Stack<QueueResizeItem> (true);
+ queueResizeList = new typed::Vector<Widget> (4, false);
+
+ DBG_OBJ_CREATE ("dw::core::Layout");
+
+ bgColor = NULL;
+ bgImage = NULL;
+ cursor = style::CURSOR_DEFAULT;
+
+ canvasWidth = canvasAscent = canvasDescent = 0;
+
+ usesViewport = false;
+ drawAfterScrollReq = false;
+ scrollX = scrollY = 0;
+ viewportWidth = viewportHeight = 0;
+ hScrollbarThickness = vScrollbarThickness = 0;
+
+ DBG_OBJ_SET_NUM ("viewportWidth", viewportWidth);
+ DBG_OBJ_SET_NUM ("viewportHeight", viewportHeight);
+ DBG_OBJ_SET_NUM ("hScrollbarThickness", hScrollbarThickness);
+ DBG_OBJ_SET_NUM ("vScrollbarThickness", vScrollbarThickness);
+
+ requestedAnchor = NULL;
+ scrollTarget = NULL;
+ scrollIdleId = -1;
+ scrollIdleNotInterrupted = false;
+
+ anchorsTable =
+ new container::typed::HashTable <object::String, Anchor> (true, true);
+
+ resizeIdleId = -1;
+
+ textZone = new misc::ZoneAllocator (16 * 1024);
+
+ DBG_OBJ_ASSOC_CHILD (&findtextState);
+ DBG_OBJ_ASSOC_CHILD (&selectionState);
+
+ platform->setLayout (this);
+
+ selectionState.setLayout(this);
+
+ queueResizeCounter = sizeAllocateCounter = sizeRequestCounter =
+ getExtremesCounter = 0;
+
+ layoutImgRenderer = NULL;
+
+ resizeIdleCounter = queueResizeCounter = sizeAllocateCounter
+ = sizeRequestCounter = getExtremesCounter = 0;
+}
+
+Layout::~Layout ()
+{
+ widgetAtPoint = NULL;
+
+ if (layoutImgRenderer) {
+ if (bgImage)
+ bgImage->removeExternalImgRenderer (layoutImgRenderer);
+ delete layoutImgRenderer;
+ }
+
+ if (scrollIdleId != -1)
+ platform->removeIdle (scrollIdleId);
+ if (resizeIdleId != -1)
+ platform->removeIdle (resizeIdleId);
+ if (bgColor)
+ bgColor->unref ();
+ if (bgImage)
+ bgImage->unref ();
+ if (topLevel) {
+ detachWidget (topLevel);
+ Widget *w = topLevel;
+ topLevel = NULL;
+ delete w;
+ }
+
+ delete queueQueueResizeList;
+ delete queueResizeList;
+ delete platform;
+ delete view;
+ delete anchorsTable;
+ delete textZone;
+
+ if (requestedAnchor)
+ free (requestedAnchor);
+ if (scrollTarget)
+ delete scrollTarget;
+
+ DBG_OBJ_DELETE ();
+}
+
+void Layout::detachWidget (Widget *widget)
+{
+ // Called form ~Layout. Sometimes, the widgets (not only the toplevel widget)
+ // do some stuff after the layout has been deleted, so *all* widgets have to
+ // be detached, and check "layout != NULL" at relevant points.
+
+ // Could be replaced by a virtual method in Widget, like getWidgetAtPoint,
+ // if performace were really a problem.
+
+ widget->layout = NULL;
+ Iterator *it =
+ widget->iterator ((Content::Type)
+ (Content::WIDGET_IN_FLOW | Content::WIDGET_OOF_CONT),
+ false);
+ while (it->next ())
+ detachWidget (it->getContent()->widget);
+
+ it->unref ();
+}
+
+void Layout::addWidget (Widget *widget)
+{
+ if (topLevel) {
+ MSG_WARN("widget already set\n");
+ return;
+ }
+
+ topLevel = widget;
+ widget->layout = this;
+ widget->container = NULL;
+ DBG_OBJ_SET_PTR_O (widget, "container", widget->container);
+
+ queueResizeList->clear ();
+ widget->notifySetAsTopLevel ();
+
+ findtextState.setWidget (widget);
+
+ canvasHeightGreater = false;
+ DBG_OBJ_SET_SYM ("canvasHeightGreater",
+ canvasHeightGreater ? "true" : "false");
+
+ // Do not directly call Layout::queueResize(), but
+ // Widget::queueResize(), so that all flags are set properly,
+ // queueResizeList is filled, etc.
+ topLevel->queueResize (-1, false);
+}
+
+void Layout::removeWidget ()
+{
+ /**
+ * \bug Some more attributes must be reset here.
+ */
+ topLevel = NULL;
+ queueResizeList->clear ();
+ widgetAtPoint = NULL;
+ canvasWidth = canvasAscent = canvasDescent = 0;
+ scrollX = scrollY = 0;
+
+ view->setCanvasSize (canvasWidth, canvasAscent, canvasDescent);
+ if (view->usesViewport ())
+ view->setViewportSize (viewportWidth, viewportHeight, 0, 0);
+ view->queueDrawTotal ();
+
+ setAnchor (NULL);
+ updateAnchor ();
+
+ emitter.emitCanvasSizeChanged (canvasWidth, canvasAscent, canvasDescent);
+
+ findtextState.setWidget (NULL);
+ selectionState.reset ();
+
+ updateCursor ();
+}
+
+void Layout::setWidget (Widget *widget)
+{
+ DBG_OBJ_ASSOC_CHILD (widget);
+
+ widgetAtPoint = NULL;
+ if (topLevel) {
+ Widget *w = topLevel;
+ topLevel = NULL;
+ delete w;
+ }
+ textZone->zoneFree ();
+ addWidget (widget);
+
+ updateCursor ();
+}
+
+/**
+ * \brief Attach a view to the layout.
+ *
+ * It will become a child of the layout,
+ * and so it will be destroyed, when the layout will be destroyed.
+ */
+void Layout::attachView (View *view)
+{
+ if (this->view)
+ MSG_ERR("attachView: Multiple views for layout!\n");
+
+ DBG_OBJ_ASSOC_CHILD (view);
+
+ this->view = view;
+ platform->attachView (view);
+
+ /*
+ * The layout of the view is set later, first, we "project" the current
+ * state of the layout into the new view. A view must handle this without
+ * a layout. See also at the end of this function.
+ */
+ if (bgColor)
+ view->setBgColor (bgColor);
+ view->setCursor (cursor);
+ view->setCanvasSize (canvasWidth, canvasAscent, canvasDescent);
+
+ if (view->usesViewport ()) {
+ if (usesViewport) {
+ view->scrollTo (scrollX, scrollY);
+ view->setViewportSize (viewportWidth, viewportHeight,
+ hScrollbarThickness, vScrollbarThickness);
+ hScrollbarThickness = misc::max (hScrollbarThickness,
+ view->getHScrollbarThickness ());
+ vScrollbarThickness = misc::max (vScrollbarThickness,
+ view->getVScrollbarThickness ());
+ }
+ else {
+ usesViewport = true;
+ scrollX = scrollY = 0;
+ viewportWidth = viewportHeight = 100; // random values
+ hScrollbarThickness = view->getHScrollbarThickness ();
+ vScrollbarThickness = view->getVScrollbarThickness ();
+ }
+
+ DBG_OBJ_SET_NUM ("viewportWidth", viewportWidth);
+ DBG_OBJ_SET_NUM ("viewportHeight", viewportHeight);
+ DBG_OBJ_SET_NUM ("hScrollbarThickness", hScrollbarThickness);
+ DBG_OBJ_SET_NUM ("vScrollbarThickness", vScrollbarThickness);
+ }
+
+ /*
+ * This is the last call within this function, so that it is safe for
+ * the implementation of dw::core::View::setLayout, to call methods
+ * of dw::core::Layout.
+ */
+ view->setLayout (this);
+}
+
+void Layout::detachView (View *view)
+{
+ if (this->view != view)
+ MSG_ERR("detachView: this->view: %p view %p\n", this->view, view);
+
+ view->setLayout (NULL);
+ platform->detachView (view);
+ this->view = NULL;
+ /**
+ * \todo Actually, viewportMarkerWidthDiff and
+ * viewportMarkerHeightDiff have to be recalculated here, since the
+ * effective (i.e. maximal) values may change, after the view has been
+ * detached. Same applies to the usage of viewports.
+ */
+}
+
+void Layout::scroll(ScrollCommand cmd)
+{
+ if (view->usesViewport ())
+ view->scroll(cmd);
+}
+
+/**
+ * \brief Scrolls all viewports, so that the region [x, y, width, height]
+ * is seen, according to hpos and vpos.
+ */
+void Layout::scrollTo (HPosition hpos, VPosition vpos,
+ int x, int y, int width, int height)
+{
+ scrollTo0 (new ScrollTargetFixed (hpos, vpos, x, y, width, height), true);
+}
+
+void Layout::scrollToWidget (HPosition hpos, VPosition vpos, Widget *widget)
+{
+ scrollTo0 (new ScrollTargetWidget (hpos, vpos, widget), true);
+}
+
+void Layout::scrollTo0 (ScrollTarget *scrollTarget, bool scrollingInterrupted)
+{
+ if (usesViewport) {
+ _MSG("scrollTo (%d, %d, %s)\n",
+ x, y, scrollingInterrupted ? "true" : "false");
+
+ if (this->scrollTarget)
+ delete this->scrollTarget;
+
+ this->scrollTarget = scrollTarget;
+
+ if (scrollIdleId == -1) {
+ scrollIdleId = platform->addIdle (&Layout::scrollIdle);
+ scrollIdleNotInterrupted = true;
+ }
+
+ scrollIdleNotInterrupted =
+ scrollIdleNotInterrupted || !scrollingInterrupted;
+ }
+}
+
+void Layout::scrollIdle ()
+{
+ DBG_OBJ_ENTER0 ("scroll", 0, "scrollIdle");
+
+ bool xChanged = true;
+ switch (scrollTarget->getHPos ()) {
+ case HPOS_LEFT:
+ scrollX = scrollTarget->getX ();
+ break;
+ case HPOS_CENTER:
+ scrollX =
+ scrollTarget->getX () - (viewportWidth - currVScrollbarThickness()
+ - scrollTarget->getWidth ()) / 2;
+ break;
+ case HPOS_RIGHT:
+ scrollX =
+ scrollTarget->getX () - (viewportWidth - currVScrollbarThickness()
+ - scrollTarget->getWidth ());
+ break;
+ case HPOS_INTO_VIEW:
+ xChanged = calcScrollInto (scrollTarget->getX (),
+ scrollTarget->getWidth (), &scrollX,
+ viewportWidth - currVScrollbarThickness());
+ break;
+ case HPOS_NO_CHANGE:
+ xChanged = false;
+ break;
+ }
+
+ bool yChanged = true;
+ switch (scrollTarget->getVPos ()) {
+ case VPOS_TOP:
+ scrollY = scrollTarget->getY ();
+ break;
+ case VPOS_CENTER:
+ scrollY =
+ scrollTarget->getY () - (viewportHeight - currHScrollbarThickness()
+ - scrollTarget->getHeight ()) / 2;
+ break;
+ case VPOS_BOTTOM:
+ scrollY =
+ scrollTarget->getY () - (viewportHeight - currHScrollbarThickness()
+ - scrollTarget->getHeight ());
+ break;
+ case VPOS_INTO_VIEW:
+ yChanged = calcScrollInto (scrollTarget->getY (),
+ scrollTarget->getHeight (), &scrollY,
+ viewportHeight - currHScrollbarThickness());
+ break;
+ case VPOS_NO_CHANGE:
+ yChanged = false;
+ break;
+ }
+
+ DBG_OBJ_MSGF ("scroll", 1, "xChanged = %s, yChanged = %s",
+ xChanged ? "true" : "false", yChanged ? "true" : "false");
+
+ if (xChanged || yChanged) {
+ adjustScrollPos ();
+ view->scrollTo (scrollX, scrollY);
+ }
+
+ // The following code was once inside the block above ("if
+ // (xChanged || yChanged)"). I'm not sure but it looks that this
+ // should be outside, or at least setting drawAfterScrollReq in
+ // Layout::draw should consider whether the scroll position will
+ // change (but this would be rather difficult). --SG
+
+ if (drawAfterScrollReq) {
+ drawAfterScrollReq = false;
+ view->queueDrawTotal ();
+ }
+
+ delete scrollTarget;
+ scrollTarget = NULL;
+
+ scrollIdleId = -1;
+
+ DBG_OBJ_LEAVE ();
+}
+
+void Layout::adjustScrollPos ()
+{
+ scrollX = misc::min (scrollX,
+ canvasWidth - (viewportWidth - vScrollbarThickness));
+ scrollX = misc::max (scrollX, 0);
+
+ scrollY = misc::min (scrollY,
+ canvasAscent + canvasDescent - (viewportHeight - hScrollbarThickness));
+ scrollY = misc::max (scrollY, 0);
+
+ _MSG("adjustScrollPos: scrollX=%d scrollY=%d\n", scrollX, scrollY);
+}
+
+bool Layout::calcScrollInto (int requestedValue, int requestedSize,
+ int *value, int viewportSize)
+{
+ if (requestedSize > viewportSize) {
+ // The viewport size is smaller than the size of the region which will
+ // be shown. If the region is already visible, do not change the
+ // position. Otherwise, show the left/upper border, this is most likely
+ // what is needed.
+ if (*value >= requestedValue &&
+ *value + viewportSize < requestedValue + requestedSize)
+ return false;
+ else
+ requestedSize = viewportSize;
+ }
+
+ if (requestedValue < *value) {
+ *value = requestedValue;
+ return true;
+ } else if (requestedValue + requestedSize > *value + viewportSize) {
+ *value = requestedValue - viewportSize + requestedSize;
+ return true;
+ } else
+ return false;
+}
+
+void Layout::draw (View *view, Rectangle *area)
+{
+ DBG_OBJ_ENTER ("draw", 0, "draw", "%d, %d, %d * %d",
+ area->x, area->y, area->width, area->height);
+
+ Rectangle widgetArea, intersection, widgetDrawArea;
+
+ // First of all, draw background image. (Unlike background *color*,
+ // this is not a feature of the views.)
+ if (bgImage != NULL && bgImage->getImgbufSrc() != NULL)
+ style::drawBackgroundImage (view, bgImage, bgRepeat, bgAttachment,
+ bgPositionX, bgPositionY,
+ area->x, area->y, area->width,
+ area->height, 0, 0,
+ // Reference area: maximum of canvas size and
+ // viewport size.
+ misc::max (viewportWidth
+ - (canvasHeightGreater ?
+ vScrollbarThickness : 0),
+ canvasWidth),
+ misc::max (viewportHeight
+ - hScrollbarThickness,
+ canvasAscent + canvasDescent));
+
+ if (scrollIdleId != -1) {
+ /* scroll is pending, defer draw until after scrollIdle() */
+ drawAfterScrollReq = true;
+ DBG_OBJ_MSGF ("draw", 1, "scrollIdleId = %d => delayed", scrollIdleId);
+ } else if (topLevel) {
+ /* Draw the top level widget. */
+ widgetArea.x = topLevel->allocation.x;
+ widgetArea.y = topLevel->allocation.y;
+ widgetArea.width = topLevel->allocation.width;
+ widgetArea.height = topLevel->getHeight ();
+
+ if (area->intersectsWith (&widgetArea, &intersection)) {
+ DBG_OBJ_MSG ("draw", 1, "drawing toplevel widget");
+
+ view->startDrawing (&intersection);
+
+ /* Intersection in widget coordinates. */
+ widgetDrawArea.x = intersection.x - topLevel->allocation.x;
+ widgetDrawArea.y = intersection.y - topLevel->allocation.y;
+ widgetDrawArea.width = intersection.width;
+ widgetDrawArea.height = intersection.height;
+
+ topLevel->draw (view, &widgetDrawArea);
+
+ view->finishDrawing (&intersection);
+ } else
+ DBG_OBJ_MSG ("draw", 1, "no intersection");
+ } else
+ DBG_OBJ_MSG ("draw", 1, "no toplevel widget");
+
+ DBG_OBJ_LEAVE ();
+}
+
+int Layout::currHScrollbarThickness()
+{
+ return (canvasWidth > viewportWidth) ? hScrollbarThickness : 0;
+}
+
+int Layout::currVScrollbarThickness()
+{
+ return (canvasAscent + canvasDescent > viewportHeight) ?
+ vScrollbarThickness : 0;
+}
+
+/**
+ * Sets the anchor to scroll to.
+ */
+void Layout::setAnchor (const char *anchor)
+{
+ _MSG("setAnchor (%s)\n", anchor);
+
+ if (requestedAnchor)
+ free (requestedAnchor);
+ requestedAnchor = anchor ? strdup (anchor) : NULL;
+ updateAnchor ();
+}
+
+/**
+ * Used, when the widget is not allocated yet.
+ */
+char *Layout::addAnchor (Widget *widget, const char* name)
+{
+ return addAnchor (widget, name, -1);
+}
+
+char *Layout::addAnchor (Widget *widget, const char* name, int y)
+{
+ String key (name);
+ if (anchorsTable->contains (&key))
+ return NULL;
+ else {
+ Anchor *anchor = new Anchor ();
+ anchor->name = strdup (name);
+ anchor->widget = widget;
+ anchor->y = y;
+
+ anchorsTable->put (new String (name), anchor);
+ updateAnchor ();
+
+ return anchor->name;
+ }
+}
+
+void Layout::changeAnchor (Widget *widget, char* name, int y)
+{
+ String key (name);
+ Anchor *anchor = anchorsTable->get (&key);
+ assert (anchor);
+ assert (anchor->widget == widget);
+ anchor->y = y;
+ updateAnchor ();
+}
+
+void Layout::removeAnchor (Widget *widget, char* name)
+{
+ String key (name);
+ anchorsTable->remove (&key);
+}
+
+void Layout::updateAnchor ()
+{
+ Anchor *anchor;
+ if (requestedAnchor) {
+ String key (requestedAnchor);
+ anchor = anchorsTable->get (&key);
+ } else
+ anchor = NULL;
+
+ if (anchor == NULL) {
+ /** \todo Copy comment from old docs. */
+ if (scrollIdleId != -1 && !scrollIdleNotInterrupted) {
+ platform->removeIdle (scrollIdleId);
+ scrollIdleId = -1;
+ }
+ } else
+ if (anchor->y != -1)
+ scrollTo0 (new ScrollTargetFixed (HPOS_NO_CHANGE, VPOS_TOP,
+ 0, anchor->y, 0, 0), false);
+}
+
+void Layout::setCursor (style::Cursor cursor)
+{
+ if (cursor != this->cursor) {
+ this->cursor = cursor;
+ view->setCursor (cursor);
+ }
+}
+
+void Layout::updateCursor ()
+{
+ if (widgetAtPoint && widgetAtPoint->style)
+ setCursor (widgetAtPoint->style->cursor);
+ else
+ setCursor (style::CURSOR_DEFAULT);
+}
+
+void Layout::setBgColor (style::Color *color)
+{
+ color->ref ();
+
+ if (bgColor)
+ bgColor->unref ();
+
+ bgColor = color;
+
+ if (view)
+ view->setBgColor (bgColor);
+}
+
+void Layout::setBgImage (style::StyleImage *bgImage,
+ style::BackgroundRepeat bgRepeat,
+ style::BackgroundAttachment bgAttachment,
+ style::Length bgPositionX, style::Length bgPositionY)
+{
+ if (layoutImgRenderer && this->bgImage)
+ this->bgImage->removeExternalImgRenderer (layoutImgRenderer);
+
+ if (bgImage)
+ bgImage->ref ();
+
+ if (this->bgImage)
+ this->bgImage->unref ();
+
+ this->bgImage = bgImage;
+ this->bgRepeat = bgRepeat;
+ this->bgAttachment = bgAttachment;
+ this->bgPositionX = bgPositionX;
+ this->bgPositionY = bgPositionY;
+
+ if (bgImage) {
+ // Create instance of LayoutImgRenderer when needed. Until this
+ // layout is deleted, "layoutImgRenderer" will be kept, since it
+ // is not specific to the style, but only to this layout.
+ if (layoutImgRenderer == NULL)
+ layoutImgRenderer = new LayoutImgRenderer (this);
+ bgImage->putExternalImgRenderer (layoutImgRenderer);
+ }
+}
+
+
+void Layout::resizeIdle ()
+{
+ DBG_OBJ_ENTER0 ("resize", 0, "resizeIdle");
+
+ enterResizeIdle ();
+
+ //static int calls = 0;
+ //printf ("Layout::resizeIdle calls = %d\n", ++calls);
+
+ assert (resizeIdleId != -1);
+
+ for (typed::Iterator <Widget> it = queueResizeList->iterator();
+ it.hasNext (); ) {
+ Widget *widget = it.getNext ();
+
+ //printf (" the %stop-level %s %p was queued (extremes changed: %s)\n",
+ // widget->parent ? "non-" : "", widget->getClassName(), widget,
+ // widget->extremesQueued () ? "yes" : "no");
+
+ if (widget->resizeQueued ()) {
+ widget->setFlags (Widget::NEEDS_RESIZE);
+ widget->unsetFlags (Widget::RESIZE_QUEUED);
+ }
+
+ if (widget->allocateQueued ()) {
+ widget->setFlags (Widget::NEEDS_ALLOCATE);
+ widget->unsetFlags (Widget::ALLOCATE_QUEUED);
+ }
+
+ if (widget->extremesQueued ()) {
+ widget->setFlags (Widget::EXTREMES_CHANGED);
+ widget->unsetFlags (Widget::EXTREMES_QUEUED);
+ }
+ }
+ queueResizeList->clear ();
+
+ // Reset already here, since in this function, queueResize() may be
+ // called again.
+ resizeIdleId = -1;
+
+ // If this method is triggered by a viewport change, we can save
+ // time when the toplevel widget is not affected (as for a toplevel
+ // image resource).
+ if (topLevel && (topLevel->needsResize () || topLevel->needsAllocate ())) {
+ Requisition requisition;
+ Allocation allocation;
+
+ topLevel->sizeRequest (&requisition);
+ DBG_OBJ_MSGF ("resize", 1, "toplevel size: %d * (%d + %d)",
+ requisition.width, requisition.ascent, requisition.descent);
+
+ // This method is triggered by Widget::queueResize, which will,
+ // in any case, set NEEDS_ALLOCATE (indirectly, as ALLOCATE_QUEUED).
+ // This assertion helps to find inconsistences. (Cases where
+ // this method is triggered by a viewport change, but the
+ // toplevel widget is not affected, are filtered out some lines
+ // above: "if (topLevel && topLevel->needsResize ())".)
+ assert (topLevel->needsAllocate ());
+
+ allocation.x = allocation.y = 0;
+ allocation.width = requisition.width;
+ allocation.ascent = requisition.ascent;
+ allocation.descent = requisition.descent;
+ topLevel->sizeAllocate (&allocation);
+
+ canvasWidth = requisition.width;
+ canvasAscent = requisition.ascent;
+ canvasDescent = requisition.descent;
+
+ emitter.emitCanvasSizeChanged (canvasWidth, canvasAscent, canvasDescent);
+
+ // Tell the view about the new world size.
+ view->setCanvasSize (canvasWidth, canvasAscent, canvasDescent);
+ // view->queueDrawTotal (false);
+
+ if (usesViewport) {
+ int currHThickness = currHScrollbarThickness();
+ int currVThickness = currVScrollbarThickness();
+
+ if (!canvasHeightGreater &&
+ canvasAscent + canvasDescent > viewportHeight - currHThickness) {
+ canvasHeightGreater = true;
+ DBG_OBJ_SET_SYM ("canvasHeightGreater",
+ canvasHeightGreater ? "true" : "false");
+ containerSizeChanged ();
+ }
+
+ // Set viewport sizes.
+ view->setViewportSize (viewportWidth, viewportHeight,
+ currHThickness, currVThickness);
+ }
+
+ // views are redrawn via Widget::resizeDrawImpl ()
+ }
+
+ updateAnchor ();
+
+ DBG_OBJ_MSGF ("resize", 1,
+ "after resizeIdle: resizeIdleId = %d", resizeIdleId);
+ DBG_OBJ_LEAVE ();
+
+ leaveResizeIdle ();
+}
+
+void Layout::queueDraw (int x, int y, int width, int height)
+{
+ DBG_OBJ_ENTER ("draw", 0, "queueDrawArea", "%d, %d, %d, %d",
+ x, y, width, height);
+
+ Rectangle area;
+ area.x = x;
+ area.y = y;
+ area.width = width;
+ area.height = height;
+
+ if (!area.isEmpty ())
+ view->queueDraw (&area);
+
+ DBG_OBJ_LEAVE ();
+}
+
+void Layout::queueDrawExcept (int x, int y, int width, int height,
+ int ex, int ey, int ewidth, int eheight) {
+
+ if (x == ex && y == ey && width == ewidth && height == eheight)
+ return;
+
+ // queueDraw() the four rectangles within rectangle (x, y, width, height)
+ // around rectangle (ex, ey, ewidth, eheight).
+ // Some or all of these may be empty.
+
+ // upper left corner of the intersection rectangle
+ int ix1 = misc::max (x, ex);
+ int iy1 = misc::max (y, ey);
+ // lower right corner of the intersection rectangle
+ int ix2 = misc::min (x + width, ex + ewidth);
+ int iy2 = misc::min (y + height, ey + eheight);
+
+ queueDraw (x, y, width, iy1 - y);
+ queueDraw (x, iy2, width, y + height - iy2);
+ queueDraw (x, iy1, ix1 - x, iy2 - iy1);
+ queueDraw (ix2, iy1, x + width - ix2, iy2 - iy1);
+}
+
+void Layout::queueResize (bool extremesChanged)
+{
+ DBG_OBJ_ENTER ("resize", 0, "queueResize", "%s",
+ extremesChanged ? "true" : "false");
+
+ if (resizeIdleId == -1) {
+ view->cancelQueueDraw ();
+
+ resizeIdleId = platform->addIdle (&Layout::resizeIdle);
+ DBG_OBJ_MSGF ("resize", 1, "setting resizeIdleId = %d", resizeIdleId);
+ }
+
+ emitter.emitResizeQueued (extremesChanged);
+
+ DBG_OBJ_LEAVE ();
+}
+
+
+// Views
+
+bool Layout::buttonEvent (ButtonEventType type, View *view, int numPressed,
+ int x, int y, ButtonState state, int button)
+
+{
+ EventButton event;
+
+ moveToWidgetAtPoint (x, y, state);
+
+ event.xCanvas = x;
+ event.yCanvas = y;
+ event.state = state;
+ event.button = button;
+ event.numPressed = numPressed;
+
+ return processMouseEvent (&event, type);
+}
+
+/**
+ * \brief This function is called by a view, to delegate a motion notify
+ * event.
+ *
+ * Arguments are similar to dw::core::Layout::buttonPress.
+ */
+bool Layout::motionNotify (View *view, int x, int y, ButtonState state)
+{
+ EventButton event;
+
+ moveToWidgetAtPoint (x, y, state);
+
+ event.xCanvas = x;
+ event.yCanvas = y;
+ event.state = state;
+
+ return processMouseEvent (&event, MOTION_NOTIFY);
+}
+
+/**
+ * \brief This function is called by a view, to delegate a enter notify event.
+ *
+ * Arguments are similar to dw::core::Layout::buttonPress.
+ */
+void Layout::enterNotify (View *view, int x, int y, ButtonState state)
+{
+ Widget *lastWidget;
+ EventCrossing event;
+
+ lastWidget = widgetAtPoint;
+ moveToWidgetAtPoint (x, y, state);
+
+ if (widgetAtPoint) {
+ event.state = state;
+ event.lastWidget = lastWidget;
+ event.currentWidget = widgetAtPoint;
+ widgetAtPoint->enterNotify (&event);
+ }
+}
+
+/**
+ * \brief This function is called by a view, to delegate a leave notify event.
+ *
+ * Arguments are similar to dw::core::Layout::buttonPress.
+ */
+void Layout::leaveNotify (View *view, ButtonState state)
+{
+#if 0
+ Widget *lastWidget;
+ EventCrossing event;
+
+ lastWidget = widgetAtPoint;
+ moveOutOfView (state);
+
+ if (lastWidget) {
+ event.state = state;
+ event.lastWidget = lastWidget;
+ event.currentWidget = widgetAtPoint;
+ lastWidget->leaveNotify (&event);
+ }
+#else
+ moveOutOfView (state);
+#endif
+}
+
+/*
+ * Return the widget at position (x, y). Return NULL, if there is no widget.
+ */
+Widget *Layout::getWidgetAtPoint (int x, int y)
+{
+ _MSG ("------------------------------------------------------------\n");
+ _MSG ("widget at (%d, %d)\n", x, y);
+ if (topLevel && topLevel->wasAllocated ())
+ return topLevel->getWidgetAtPoint (x, y, 0);
+ else
+ return NULL;
+}
+
+
+/*
+ * Emit the necessary crossing events, when the mouse pointer has moved to
+ * the given widget (by mouse or scrolling).
+ */
+void Layout::moveToWidget (Widget *newWidgetAtPoint, ButtonState state)
+{
+ Widget *ancestor, *w;
+ Widget **track;
+ int trackLen, i, i_a;
+ EventCrossing crossingEvent;
+
+ _MSG("moveToWidget: wap=%p nwap=%p\n",widgetAtPoint,newWidgetAtPoint);
+ if (newWidgetAtPoint != widgetAtPoint) {
+ // The mouse pointer has been moved into another widget.
+ if (newWidgetAtPoint && widgetAtPoint)
+ ancestor =
+ newWidgetAtPoint->getNearestCommonAncestor (widgetAtPoint);
+ else if (newWidgetAtPoint)
+ ancestor = newWidgetAtPoint->getTopLevel ();
+ else
+ ancestor = widgetAtPoint->getTopLevel ();
+
+ // Construct the track.
+ trackLen = 0;
+ if (widgetAtPoint)
+ // first part
+ for (w = widgetAtPoint; w != ancestor; w = w->getParent ())
+ trackLen++;
+ trackLen++; // for the ancestor
+ if (newWidgetAtPoint)
+ // second part
+ for (w = newWidgetAtPoint; w != ancestor; w = w->getParent ())
+ trackLen++;
+
+ track = new Widget* [trackLen];
+ i = 0;
+ if (widgetAtPoint)
+ /* first part */
+ for (w = widgetAtPoint; w != ancestor; w = w->getParent ())
+ track[i++] = w;
+ i_a = i;
+ track[i++] = ancestor;
+ if (newWidgetAtPoint) {
+ /* second part */
+ i = trackLen - 1;
+ for (w = newWidgetAtPoint; w != ancestor; w = w->getParent ())
+ track[i--] = w;
+ }
+#if 0
+ MSG("Track: %s[ ", widgetAtPoint ? "" : "nil ");
+ for (i = 0; i < trackLen; i++)
+ MSG("%s%p ", i == i_a ? ">" : "", track[i]);
+ MSG("] %s\n", newWidgetAtPoint ? "" : "nil");
+#endif
+
+ /* Send events to the widgets on the track */
+ for (i = 0; i < trackLen; i++) {
+ crossingEvent.state = state;
+ crossingEvent.currentWidget = widgetAtPoint; // ???
+ crossingEvent.lastWidget = widgetAtPoint; // ???
+ if (i < i_a) {
+ track[i]->leaveNotify (&crossingEvent);
+ } else if (i == i_a) { /* ancestor */
+ /* Don't touch ancestor unless:
+ * - moving into/from NULL,
+ * - ancestor becomes the newWidgetAtPoint */
+ if (i_a == trackLen-1 && !newWidgetAtPoint)
+ track[i]->leaveNotify (&crossingEvent);
+ else if ((i_a == 0 && !widgetAtPoint) ||
+ (i_a == trackLen-1 && newWidgetAtPoint))
+ track[i]->enterNotify (&crossingEvent);
+ } else {
+ track[i]->enterNotify (&crossingEvent);
+ }
+ }
+
+ delete[] track;
+
+ widgetAtPoint = newWidgetAtPoint;
+ updateCursor ();
+ }
+}
+
+/**
+ * \brief Common processing of press, release and motion events.
+ *
+ * This function depends on that move_to_widget_at_point()
+ * has been called before.
+ */
+bool Layout::processMouseEvent (MousePositionEvent *event,
+ ButtonEventType type)
+{
+ Widget *widget;
+
+ /*
+ * If the event is outside of the visible region of the canvas, treat it
+ * as occurring at the region's edge. Notably, this helps when selecting
+ * text.
+ */
+ if (event->xCanvas < scrollX)
+ event->xCanvas = scrollX;
+ else {
+ int maxX = scrollX + viewportWidth - currVScrollbarThickness() - 1;
+
+ if (event->xCanvas > maxX)
+ event->xCanvas = maxX;
+ }
+ if (event->yCanvas < scrollY)
+ event->yCanvas = scrollY;
+ else {
+ int maxY = misc::min(scrollY + viewportHeight -currHScrollbarThickness(),
+ canvasAscent + canvasDescent) - 1;
+
+ if (event->yCanvas > maxY)
+ event->yCanvas = maxY;
+ }
+
+ widget = getWidgetAtPoint(event->xCanvas, event->yCanvas);
+
+ for (; widget; widget = widget->getParent ()) {
+ if (widget->isButtonSensitive ()) {
+ event->xWidget = event->xCanvas - widget->getAllocation()->x;
+ event->yWidget = event->yCanvas - widget->getAllocation()->y;
+
+ switch (type) {
+ case BUTTON_PRESS:
+ return widget->buttonPress ((EventButton*)event);
+
+ case BUTTON_RELEASE:
+ return widget->buttonRelease ((EventButton*)event);
+
+ case MOTION_NOTIFY:
+ return widget->motionNotify ((EventMotion*)event);
+
+ default:
+ misc::assertNotReached ();
+ }
+ }
+ }
+ if (type == BUTTON_PRESS)
+ return emitLinkPress (NULL, -1, -1, -1, -1, (EventButton*)event);
+ else if (type == BUTTON_RELEASE)
+ return emitLinkRelease(NULL, -1, -1, -1, -1, (EventButton*)event);
+
+ return false;
+}
+
+/*
+ * This function must be called by a view, when the user has manually changed
+ * the viewport position. It is *not* called, when the layout has requested the
+ * position change.
+ */
+void Layout::scrollPosChanged (View *view, int x, int y)
+{
+ if (x != scrollX || y != scrollY) {
+ scrollX = x;
+ scrollY = y;
+
+ setAnchor (NULL);
+ updateAnchor ();
+ }
+}
+
+/*
+ * This function must be called by a viewport view, when its viewport size has
+ * changed. It is *not* called, when the layout has requested the size change.
+ */
+void Layout::viewportSizeChanged (View *view, int width, int height)
+{
+ DBG_OBJ_ENTER ("resize", 0, "viewportSizeChanged", "%p, %d, %d",
+ view, width, height);
+
+ /* If the width has become higher, we test again, whether the vertical
+ * scrollbar (so to speak) can be hidden again. */
+ if (usesViewport && width > viewportWidth) {
+ canvasHeightGreater = false;
+ DBG_OBJ_SET_SYM ("canvasHeightGreater",
+ canvasHeightGreater ? "true" : "false");
+ }
+
+ /* if size changes, redraw this view.
+ * TODO: this is a resize call (redraw/resize code needs a review). */
+ if (viewportWidth != width || viewportHeight != height) {
+ if (topLevel)
+ // similar to addWidget()
+ topLevel->queueResize (-1, false);
+ else
+ queueResize (false);
+ }
+
+ viewportWidth = width;
+ viewportHeight = height;
+
+ DBG_OBJ_SET_NUM ("viewportWidth", viewportWidth);
+ DBG_OBJ_SET_NUM ("viewportHeight", viewportHeight);
+
+ containerSizeChanged ();
+
+ DBG_OBJ_LEAVE ();
+}
+
+void Layout::containerSizeChanged ()
+{
+ DBG_OBJ_ENTER0 ("resize", 0, "containerSizeChanged");
+
+ if (topLevel) {
+ topLevel->containerSizeChanged ();
+ queueResize (true);
+ }
+
+ DBG_OBJ_LEAVE ();
+}
+
+} // namespace core
+} // namespace dw
diff --git a/dw/layout.hh b/dw/layout.hh
new file mode 100644
index 0000000..dbcff99
--- /dev/null
+++ b/dw/layout.hh
@@ -0,0 +1,532 @@
+#ifndef __DW_LAYOUT_HH__
+#define __DW_LAYOUT_HH__
+
+#ifndef __INCLUDED_FROM_DW_CORE_HH__
+# error Do not include this file directly, use "core.hh" instead.
+#endif
+
+namespace dw {
+namespace core {
+
+/**
+ * \brief The central class for managing and drawing a widget tree.
+ *
+ * \sa\ref dw-overview, \ref dw-layout-widgets, \ref dw-layout-views
+ */
+class Layout: public lout::object::Object
+{
+ friend class Widget;
+
+private:
+ class LayoutImgRenderer: public style::StyleImage::ExternalImgRenderer
+ {
+ Layout *layout;
+
+ public:
+ LayoutImgRenderer (Layout *layout) { this->layout = layout; }
+
+ bool readyToDraw ();
+ void getBgArea (int *x, int *y, int *width, int *height);
+ void getRefArea (int *xRef, int *yRef, int *widthRef, int *heightRef);
+ style::StyleImage *getBackgroundImage ();
+ style::BackgroundRepeat getBackgroundRepeat ();
+ style::BackgroundAttachment getBackgroundAttachment ();
+ style::Length getBackgroundPositionX ();
+ style::Length getBackgroundPositionY ();
+ void draw (int x, int y, int width, int height);
+ };
+
+ LayoutImgRenderer *layoutImgRenderer;
+
+public:
+ /**
+ * \brief Receiver interface different signals.
+ *
+ * May be extended.
+ */
+ class Receiver: public lout::signal::Receiver
+ {
+ public:
+ virtual void resizeQueued (bool extremesChanged);
+ virtual void canvasSizeChanged (int width, int ascent, int descent);
+ };
+
+ class LinkReceiver: public lout::signal::Receiver
+ {
+ public:
+ /**
+ * \brief Called, when a link is entered, left, or the position has
+ * changed.
+ *
+ * When a link is entered, this method is called with the respective
+ * arguments. When a link is left, this method is called with all
+ * three arguments (\em link, \em x, \em y) set to -1.
+ *
+ * When coordinates are supported, a change of the coordinates also
+ * causes emitting this signal.
+ */
+ virtual bool enter (Widget *widget, int link, int img, int x, int y);
+
+ /**
+ * \brief Called, when the user has pressed the mouse button on a
+ * link (but not yet released).
+ *
+ * The causing event is passed as \em event.
+ */
+ virtual bool press (Widget *widget, int link, int img, int x, int y,
+ EventButton *event);
+
+ /**
+ * \brief Called, when the user has released the mouse button on a
+ * link.
+ *
+ * The causing event is passed as \em event.
+ */
+ virtual bool release (Widget *widget, int link, int img, int x, int y,
+ EventButton *event);
+
+ /**
+ * \brief Called, when the user has clicked on a link.
+ *
+ * For mouse interaction, this is equivalent to "press" and "release"
+ * on the same link. In this case, \em event contains the "release"
+ * event.
+ *
+ *
+ * When activating links via keyboard is supported, only a "clicked"
+ * signal will be emitted, and \em event will be NULL.
+ */
+ virtual bool click (Widget *widget, int link, int img, int x, int y,
+ EventButton *event);
+ };
+
+ class LinkEmitter: public lout::signal::Emitter
+ {
+ private:
+ enum { ENTER, PRESS, RELEASE, CLICK };
+
+ protected:
+ bool emitToReceiver (lout::signal::Receiver *receiver, int signalNo,
+ int argc, lout::object::Object **argv);
+
+ public:
+ inline void connectLink (LinkReceiver *receiver) { connect (receiver); }
+
+ bool emitEnter (Widget *widget, int link, int img, int x, int y);
+ bool emitPress (Widget *widget, int link, int img, int x, int y,
+ EventButton *event);
+ bool emitRelease (Widget *widget, int link, int img, int x, int y,
+ EventButton *event);
+ bool emitClick (Widget *widget, int link, int img, int x, int y,
+ EventButton *event);
+ };
+
+ LinkEmitter linkEmitter;
+
+private:
+ class Emitter: public lout::signal::Emitter
+ {
+ private:
+ enum { RESIZE_QUEUED, CANVAS_SIZE_CHANGED };
+
+ protected:
+ bool emitToReceiver (lout::signal::Receiver *receiver, int signalNo,
+ int argc, lout::object::Object **argv);
+
+ public:
+ inline void connectLayout (Receiver *receiver) { connect (receiver); }
+
+ void emitResizeQueued (bool extremesChanged);
+ void emitCanvasSizeChanged (int width, int ascent, int descent);
+ };
+
+ Emitter emitter;
+
+ class Anchor: public lout::object::Object
+ {
+ public:
+ char *name;
+ Widget *widget;
+ int y;
+
+ ~Anchor ();
+ };
+
+ class QueueResizeItem: public lout::object::Object
+ {
+ public:
+ Widget *widget;
+ int ref;
+ bool extremesChanged, fast;
+
+ inline QueueResizeItem (Widget *widget, int ref, bool extremesChanged,
+ bool fast)
+ {
+ this->widget = widget;
+ this->ref = ref;
+ this->extremesChanged = extremesChanged;
+ this->fast = fast;
+ }
+ };
+
+ /**
+ * \brief An abstract scrolling target. The values are first
+ * calculated when they are needed in scrollIdle().
+ *
+ * (Note: perhaps a subclass should be uses for anchors.)
+ */
+ class ScrollTarget
+ {
+ public:
+ virtual ~ScrollTarget ();
+
+ virtual HPosition getHPos () = 0;
+ virtual VPosition getVPos () = 0;
+ virtual int getX () = 0;
+ virtual int getY () = 0;
+ virtual int getWidth () = 0;
+ virtual int getHeight () = 0;
+ };
+
+ class ScrollTargetBase: public ScrollTarget
+ {
+ HPosition hPos;
+ VPosition vPos;
+
+ public:
+ ScrollTargetBase (HPosition hPos, VPosition vPos);
+
+ HPosition getHPos ();
+ VPosition getVPos ();
+ };
+
+ /**
+ * \brief Scrolling target with concrete values.
+ */
+ class ScrollTargetFixed: public ScrollTargetBase
+ {
+ int x, y, width, height;
+
+ public:
+ ScrollTargetFixed (HPosition hPos, VPosition vPos,
+ int x, int y, int width, int height);
+
+ int getX ();
+ int getY ();
+ int getWidth ();
+ int getHeight ();
+ };
+
+ /**
+ * \brief Scrolling target for a widget allocation.
+ *
+ * If the widget is allocated between scrollToWidget() and
+ * scrollIdle(), this is taken into account.
+ */
+ class ScrollTargetWidget: public ScrollTargetBase
+ {
+ Widget *widget;
+
+ public:
+ ScrollTargetWidget (HPosition hPos, VPosition vPos, Widget *widget);
+
+ int getX ();
+ int getY ();
+ int getWidth ();
+ int getHeight ();
+ };
+
+ Platform *platform;
+ View *view;
+ Widget *topLevel, *widgetAtPoint;
+ lout::container::typed::Stack<QueueResizeItem> *queueQueueResizeList;
+ lout::container::typed::Vector<Widget> *queueResizeList;
+
+ /* The state, which must be projected into the view. */
+ style::Color *bgColor;
+ style::StyleImage *bgImage;
+ style::BackgroundRepeat bgRepeat;
+ style::BackgroundAttachment bgAttachment;
+ style::Length bgPositionX, bgPositionY;
+
+ style::Cursor cursor;
+ int canvasWidth, canvasAscent, canvasDescent;
+
+ bool usesViewport, drawAfterScrollReq;
+ int scrollX, scrollY, viewportWidth, viewportHeight;
+ bool canvasHeightGreater;
+ int hScrollbarThickness, vScrollbarThickness;
+
+ ScrollTarget *scrollTarget;
+
+ char *requestedAnchor;
+ int scrollIdleId, resizeIdleId;
+ bool scrollIdleNotInterrupted;
+
+ /* Anchors of the widget tree */
+ lout::container::typed::HashTable <lout::object::String, Anchor>
+ *anchorsTable;
+
+ SelectionState selectionState;
+ FindtextState findtextState;
+
+ enum ButtonEventType { BUTTON_PRESS, BUTTON_RELEASE, MOTION_NOTIFY };
+
+ void detachWidget (Widget *widget);
+
+ Widget *getWidgetAtPoint (int x, int y);
+ void moveToWidget (Widget *newWidgetAtPoint, ButtonState state);
+
+ /**
+ * \brief Emit the necessary crossing events, when the mouse pointer has
+ * moved to position (\em x, \em );
+ */
+ void moveToWidgetAtPoint (int x, int y, ButtonState state)
+ { moveToWidget (getWidgetAtPoint (x, y), state); }
+
+ /**
+ * \brief Emit the necessary crossing events, when the mouse pointer
+ * has moved out of the view.
+ */
+ void moveOutOfView (ButtonState state) { moveToWidget (NULL, state); }
+
+ bool processMouseEvent (MousePositionEvent *event, ButtonEventType type);
+ bool buttonEvent (ButtonEventType type, View *view,
+ int numPressed, int x, int y, ButtonState state,
+ int button);
+ void resizeIdle ();
+ void setSizeHints ();
+ void draw (View *view, Rectangle *area);
+
+ void scrollTo0(ScrollTarget *scrollTarget, bool scrollingInterrupted);
+ void scrollIdle ();
+ void adjustScrollPos ();
+ static bool calcScrollInto (int targetValue, int requestedSize,
+ int *value, int viewportSize);
+ int currHScrollbarThickness();
+ int currVScrollbarThickness();
+
+ void updateAnchor ();
+
+ /* Widget */
+
+ char *addAnchor (Widget *widget, const char* name);
+ char *addAnchor (Widget *widget, const char* name, int y);
+ void changeAnchor (Widget *widget, char* name, int y);
+ void removeAnchor (Widget *widget, char* name);
+ void setCursor (style::Cursor cursor);
+ void updateCursor ();
+ void queueDraw (int x, int y, int width, int height);
+ void queueDrawExcept (int x, int y, int width, int height,
+ int ex, int ey, int ewidth, int eheight);
+ void queueResize (bool extremesChanged);
+ void removeWidget ();
+
+ /* For tests regarding the respective Layout and (mostly) Widget
+ methods. Accessed by respective methods (enter..., leave...,
+ ...Entered) defined here and in Widget. */
+
+ int resizeIdleCounter, queueResizeCounter, sizeAllocateCounter,
+ sizeRequestCounter, getExtremesCounter;
+
+ void enterResizeIdle () { resizeIdleCounter++; }
+ void leaveResizeIdle () { resizeIdleCounter--; }
+
+public:
+ Layout (Platform *platform);
+ ~Layout ();
+
+ inline void connectLink (LinkReceiver *receiver)
+ { linkEmitter.connectLink (receiver); }
+
+ inline bool emitLinkEnter (Widget *w, int link, int img, int x, int y)
+ { return linkEmitter.emitEnter (w, link, img, x, y); }
+
+ inline bool emitLinkPress (Widget *w, int link, int img,
+ int x, int y, EventButton *event)
+ { return linkEmitter.emitPress (w, link, img, x, y, event); }
+
+ inline bool emitLinkRelease (Widget *w, int link, int img,
+ int x, int y, EventButton *event)
+ { return linkEmitter.emitRelease (w, link, img, x, y, event); }
+
+ inline bool emitLinkClick (Widget *w, int link, int img,
+ int x, int y, EventButton *event)
+ { return linkEmitter.emitClick (w, link, img, x, y, event); }
+
+ lout::misc::ZoneAllocator *textZone;
+
+ void addWidget (Widget *widget);
+ void setWidget (Widget *widget);
+
+ void attachView (View *view);
+ void detachView (View *view);
+
+ inline bool getUsesViewport () { return usesViewport; }
+ inline int getWidthViewport () { return viewportWidth; }
+ inline int getHeightViewport () { return viewportHeight; }
+ inline int getScrollPosX () { return scrollX; }
+ inline int getScrollPosY () { return scrollY; }
+
+ /* public */
+
+ void scrollTo (HPosition hpos, VPosition vpos,
+ int x, int y, int width, int height);
+ void scrollToWidget (HPosition hpos, VPosition vpos, Widget *widget);
+ void scroll (ScrollCommand cmd);
+ void setAnchor (const char *anchor);
+
+ /* View */
+
+ inline void expose (View *view, Rectangle *area) {
+ DBG_OBJ_ENTER ("draw", 0, "expose", "%d, %d, %d * %d",
+ area->x, area->y, area->width, area->height);
+ draw (view, area);
+ DBG_OBJ_LEAVE ();
+ }
+
+ /**
+ * \brief This function is called by a view, to delegate a button press
+ * event.
+ *
+ * \em numPressed is 1 for simple presses, 2 for double presses etc. (more
+ * that 2 is never needed), \em x and \em y the world coordinates, and
+ * \em button the number of the button pressed.
+ */
+ inline bool buttonPress (View *view, int numPressed, int x, int y,
+ ButtonState state, int button)
+ {
+ return buttonEvent (BUTTON_PRESS, view, numPressed, x, y, state, button);
+ }
+
+ void containerSizeChanged ();
+
+ /**
+ * \brief This function is called by a view, to delegate a button press
+ * event.
+ *
+ * Arguments are similar to dw::core::Layout::buttonPress.
+ */
+ inline bool buttonRelease (View *view, int numPressed, int x, int y,
+ ButtonState state, int button)
+ {
+ return buttonEvent (BUTTON_RELEASE, view, numPressed, x, y, state,
+ button);
+ }
+
+ bool motionNotify (View *view, int x, int y, ButtonState state);
+ void enterNotify (View *view, int x, int y, ButtonState state);
+ void leaveNotify (View *view, ButtonState state);
+
+ void scrollPosChanged (View *view, int x, int y);
+ void viewportSizeChanged (View *view, int width, int height);
+
+ inline Platform *getPlatform ()
+ {
+ return platform;
+ }
+
+ /* delegated */
+
+ inline int textWidth (style::Font *font, const char *text, int len)
+ {
+ return platform->textWidth (font, text, len);
+ }
+
+ inline char *textToUpper (const char *text, int len)
+ {
+ return platform->textToUpper (text, len);
+ }
+
+ inline char *textToLower (const char *text, int len)
+ {
+ return platform->textToLower (text, len);
+ }
+
+ inline int nextGlyph (const char *text, int idx)
+ {
+ return platform->nextGlyph (text, idx);
+ }
+
+ inline int prevGlyph (const char *text, int idx)
+ {
+ return platform->prevGlyph (text, idx);
+ }
+
+ inline float dpiX ()
+ {
+ return platform->dpiX ();
+ }
+
+ inline float dpiY ()
+ {
+ return platform->dpiY ();
+ }
+
+ inline style::Font *createFont (style::FontAttrs *attrs, bool tryEverything)
+ {
+ return platform->createFont (attrs, tryEverything);
+ }
+
+ inline bool fontExists (const char *name)
+ {
+ return platform->fontExists (name);
+ }
+
+ inline style::Color *createColor (int color)
+ {
+ return platform->createColor (color);
+ }
+
+ inline style::Tooltip *createTooltip (const char *text)
+ {
+ return platform->createTooltip (text);
+ }
+
+ inline void cancelTooltip ()
+ {
+ return platform->cancelTooltip ();
+ }
+
+ inline Imgbuf *createImgbuf (Imgbuf::Type type, int width, int height,
+ double gamma)
+ {
+ return platform->createImgbuf (type, width, height, gamma);
+ }
+
+ inline void copySelection(const char *text)
+ {
+ platform->copySelection(text);
+ }
+
+ inline ui::ResourceFactory *getResourceFactory ()
+ {
+ return platform->getResourceFactory ();
+ }
+
+ inline void connect (Receiver *receiver) {
+ emitter.connectLayout (receiver); }
+
+ /** \brief See dw::core::FindtextState::search. */
+ inline FindtextState::Result search (const char *str, bool caseSens,
+ int backwards)
+ { return findtextState.search (str, caseSens, backwards); }
+
+ /** \brief See dw::core::FindtextState::resetSearch. */
+ inline void resetSearch () { findtextState.resetSearch (); }
+
+ void setBgColor (style::Color *color);
+ void setBgImage (style::StyleImage *bgImage,
+ style::BackgroundRepeat bgRepeat,
+ style::BackgroundAttachment bgAttachment,
+ style::Length bgPositionX, style::Length bgPositionY);
+
+ inline style::Color* getBgColor () { return bgColor; }
+ inline style::StyleImage* getBgImage () { return bgImage; }
+};
+
+} // namespace core
+} // namespace dw
+
+#endif // __DW_LAYOUT_HH__
+
diff --git a/dw/platform.hh b/dw/platform.hh
new file mode 100644
index 0000000..227cda3
--- /dev/null
+++ b/dw/platform.hh
@@ -0,0 +1,171 @@
+#ifndef __DW_PLATFORM_HH__
+#define __DW_PLATFORM_HH__
+
+#ifndef __INCLUDED_FROM_DW_CORE_HH__
+# error Do not include this file directly, use "core.hh" instead.
+#endif
+
+namespace dw {
+namespace core {
+
+/**
+ * \brief An interface to encapsulate some platform dependencies.
+ *
+ * \sa\ref dw-overview
+ */
+class Platform: public lout::object::Object
+{
+public:
+ /*
+ * -----------------------------------
+ * General
+ * -----------------------------------
+ */
+
+ /**
+ * \brief This methods notifies the platform, that it has been attached to
+ * a layout.
+ */
+ virtual void setLayout (Layout *layout) = 0;
+
+ /*
+ * -------------------------
+ * Operations on views
+ * -------------------------
+ */
+
+ /**
+ * \brief This methods notifies the platform, that a view has been attached
+ * to the related layout.
+ */
+ virtual void attachView (View *view) = 0;
+
+ /**
+ * \brief This methods notifies the platform, that a view has been detached
+ * from the related layout.
+ */
+ virtual void detachView (View *view) = 0;
+
+ /*
+ * -----------------------------------
+ * Platform dependent properties
+ * -----------------------------------
+ */
+
+ /**
+ * \brief Return the width of a text, with a given length and font.
+ */
+ virtual int textWidth (style::Font *font, const char *text, int len) = 0;
+
+ /**
+ * \brief Return the string resulting from transforming text to uppercase.
+ */
+ virtual char *textToUpper (const char *text, int len) = 0;
+
+ /**
+ * \brief Return the string resulting from transforming text to lowercase.
+ */
+ virtual char *textToLower (const char *text, int len) = 0;
+
+ /**
+ * \brief Return the index of the next glyph in string text.
+ */
+ virtual int nextGlyph (const char *text, int idx) = 0;
+
+ /**
+ * \brief Return the index of the previous glyph in string text.
+ */
+ virtual int prevGlyph (const char *text, int idx) = 0;
+
+ /**
+ * \brief Return screen resolution in x-direction.
+ */
+ virtual float dpiX () = 0;
+
+ /**
+ * \brief Return screen resolution in y-direction.
+ */
+ virtual float dpiY () = 0;
+
+ /*
+ * ---------------------------------------------------------
+ * These are to encapsulate some platform dependencies
+ * ---------------------------------------------------------
+ */
+
+ /**
+ * \brief Add an idle function.
+ *
+ * An idle function is called once, when no other
+ * tasks are to be done (e.g. there are no events to process), and then
+ * removed from the queue. The return value is a number, which can be
+ * used in removeIdle below.
+ */
+ virtual int addIdle (void (Layout::*func) ()) = 0;
+
+ /**
+ * \brief Remove an idle function, which has not been processed yet.
+ */
+ virtual void removeIdle (int idleId) = 0;
+
+ /*
+ * ---------------------
+ * Style Resources
+ * ---------------------
+ */
+
+ /**
+ * \brief Create a (platform dependent) font.
+ *
+ * Typically, within a platform, a sub class of dw::core::style::Font
+ * is defined, which holds more platform dependent data.
+ *
+ * Also, this method must fill the attributes "font" (when needed),
+ * "ascent", "descent", "spaceSidth" and "xHeight". If "tryEverything"
+ * is true, several methods should be used to use another font, when
+ * the requested font is not available. Passing false is typically done,
+ * if the caller wants to test different variations.
+ */
+ virtual style::Font *createFont (style::FontAttrs *attrs,
+ bool tryEverything) = 0;
+
+ virtual bool fontExists (const char *name) = 0;
+
+ /**
+ * \brief Create a color resource for a given 0xrrggbb value.
+ */
+ virtual style::Color *createColor (int color) = 0;
+
+ /**
+ * \brief Create a tooltip
+ */
+ virtual style::Tooltip *createTooltip (const char *text) = 0;
+
+ /**
+ * \brief Cancel a tooltip (either shown or requested)
+ */
+ virtual void cancelTooltip () = 0;
+
+ /**
+ * \brief Create a (platform speficic) image buffer.
+ *
+ * "gamma" is the value by which the image data is gamma-encoded.
+ */
+ virtual Imgbuf *createImgbuf (Imgbuf::Type type, int width, int height,
+ double gamma) = 0;
+
+ /**
+ * \brief Copy selected text (0-terminated).
+ */
+ virtual void copySelection(const char *text) = 0;
+
+ /**
+ * ...
+ */
+ virtual ui::ResourceFactory *getResourceFactory () = 0;
+};
+
+} // namespace core
+} // namespace dw
+
+#endif // __DW_PLATFORM_HH__
diff --git a/dw/preview.xbm b/dw/preview.xbm
new file mode 100644
index 0000000..85ea829
--- /dev/null
+++ b/dw/preview.xbm
@@ -0,0 +1,5 @@
+#define preview_width 11
+#define preview_height 11
+static unsigned char preview_bits[] = {
+ 0x20, 0x00, 0x70, 0x00, 0x20, 0x00, 0x20, 0x00, 0x22, 0x02, 0xff, 0x07,
+ 0x22, 0x02, 0x20, 0x00, 0x20, 0x00, 0x70, 0x00, 0x20, 0x00};
diff --git a/dw/selection.cc b/dw/selection.cc
new file mode 100644
index 0000000..f5c7bda
--- /dev/null
+++ b/dw/selection.cc
@@ -0,0 +1,494 @@
+/*
+ * RTFL (originally part of dillo)
+ *
+ * Copyright 2005-2007 Sebastian Geerken <sgeerken@dillo.org>
+ *
+ * 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; with the following exception:
+ *
+ * The copyright holders of RTFL give you permission to link this file
+ * statically or dynamically against all versions of the graphviz
+ * library, which are published by AT&T Corp. under one of the following
+ * licenses:
+ *
+ * - Common Public License version 1.0 as published by International
+ * Business Machines Corporation (IBM), or
+ * - Eclipse Public License version 1.0 as published by the Eclipse
+ * Foundation.
+ *
+ * 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/>.
+ */
+
+
+
+#include "core.hh"
+#include "../lout/debug.hh"
+
+#include <string.h>
+
+using namespace lout;
+
+/*
+ * strndup() is a GNU extension.
+ */
+extern "C" char *strndup(const char *s, size_t size)
+{
+ char *r = (char *) malloc (size + 1);
+
+ if (r) {
+ strncpy (r, s, size);
+ r[size] = 0;
+ }
+
+ return r;
+}
+
+namespace dw {
+namespace core {
+
+SelectionState::SelectionState ()
+{
+ DBG_OBJ_CREATE ("dw::core::SelectionState");
+
+ layout = NULL;
+
+ selectionState = NONE;
+ from = NULL;
+ to = NULL;
+
+ linkState = LINK_NONE;
+ link = NULL;
+}
+
+SelectionState::~SelectionState ()
+{
+ reset ();
+ DBG_OBJ_DELETE ();
+}
+
+void SelectionState::reset ()
+{
+ resetSelection ();
+ resetLink ();
+}
+
+void SelectionState::resetSelection ()
+{
+ if (from)
+ delete from;
+ from = NULL;
+ if (to)
+ delete to;
+ to = NULL;
+ selectionState = NONE;
+}
+
+
+void SelectionState::resetLink ()
+{
+ if (link)
+ delete link;
+ link = NULL;
+ linkState = LINK_NONE;
+}
+
+bool SelectionState::buttonPress (Iterator *it, int charPos, int linkNo,
+ EventButton *event)
+{
+ Widget *itWidget = it->getWidget ();
+ bool ret = false;
+
+ if (!event) return ret;
+
+ if (event->button == 3) {
+ // menu popup
+ layout->emitLinkPress (itWidget, linkNo, -1, -1, -1, event);
+ ret = true;
+ } else if (linkNo != -1) {
+ // link handling
+ (void) layout->emitLinkPress (itWidget, linkNo, -1, -1, -1, event);
+ resetLink ();
+ linkState = LINK_PRESSED;
+ linkButton = event->button;
+ DeepIterator *newLink = new DeepIterator (it);
+ if (newLink->isEmpty ()) {
+ delete newLink;
+ resetLink ();
+ } else {
+ link = newLink;
+ // It may be that the user has pressed on something activatable
+ // (linkNo != -1), but there is no contents, e.g. with images
+ // without ALTernative text.
+ if (link) {
+ linkChar = correctCharPos (link, charPos);
+ linkNumber = linkNo;
+ }
+ }
+ // We do not return the value of the signal method,
+ // but we do actually process this event.
+ ret = true;
+ } else if (event->button == 1) {
+ // normal selection handling
+ highlight (false, 0);
+ resetSelection ();
+
+ selectionState = SELECTING;
+ DeepIterator *newFrom = new DeepIterator (it);
+ if (newFrom->isEmpty ()) {
+ delete newFrom;
+ resetSelection ();
+ } else {
+ from = newFrom;
+ fromChar = correctCharPos (from, charPos);
+ to = from->cloneDeepIterator ();
+ toChar = correctCharPos (to, charPos);
+ }
+ ret = true;
+ }
+
+ return ret;
+}
+
+bool SelectionState::buttonRelease (Iterator *it, int charPos, int linkNo,
+ EventButton *event)
+{
+ Widget *itWidget = it->getWidget ();
+ bool ret = false;
+
+ if (linkState == LINK_PRESSED && event && event->button == linkButton) {
+ // link handling
+ ret = true;
+ if (linkNo != -1)
+ (void) layout->emitLinkRelease (itWidget, linkNo, -1, -1, -1, event);
+
+ // The link where the user clicked the mouse button?
+ if (linkNo == linkNumber) {
+ resetLink ();
+ (void) layout->emitLinkClick (itWidget, linkNo, -1, -1, -1, event);
+ } else {
+ if (event->button == 1)
+ // Reset links and switch to selection mode. The selection
+ // state will be set to SELECTING, which is handled some lines
+ // below.
+ switchLinkToSelection (it, charPos);
+ }
+ }
+
+ if (selectionState == SELECTING && event && event->button == 1) {
+ // normal selection
+ ret = true;
+ adjustSelection (it, charPos);
+
+ if (from->compareTo (to) == 0 && fromChar == toChar)
+ // nothing selected
+ resetSelection ();
+ else {
+ copy ();
+ selectionState = SELECTED;
+ }
+ }
+
+ return ret;
+}
+
+bool SelectionState::buttonMotion (Iterator *it, int charPos, int linkNo,
+ EventMotion *event)
+{
+ if (linkState == LINK_PRESSED) {
+ //link handling
+ if (linkNo != linkNumber)
+ // No longer the link where the user clicked the mouse button.
+ // Reset links and switch to selection mode.
+ switchLinkToSelection (it, charPos);
+ // Still in link: do nothing.
+ } else if (selectionState == SELECTING) {
+ // selection
+ adjustSelection (it, charPos);
+ }
+
+ return true;
+}
+
+/**
+ * \brief General form of dw::core::SelectionState::buttonPress,
+ * dw::core::SelectionState::buttonRelease and
+ * dw::core::SelectionState::buttonMotion.
+ */
+bool SelectionState::handleEvent (EventType eventType, Iterator *it,
+ int charPos, int linkNo,
+ MousePositionEvent *event)
+{
+ switch (eventType) {
+ case BUTTON_PRESS:
+ return buttonPress (it, charPos, linkNo, (EventButton*)event);
+
+ case BUTTON_RELEASE:
+ return buttonRelease (it, charPos, linkNo, (EventButton*)event);
+
+ case BUTTON_MOTION:
+ return buttonMotion (it, charPos, linkNo, (EventMotion*)event);
+
+
+ default:
+ misc::assertNotReached ();
+ }
+
+ return false;
+}
+
+
+/**
+ * \brief This method is called when the user decides not to activate a link,
+ * but instead select text.
+ */
+void SelectionState::switchLinkToSelection (Iterator *it, int charPos)
+{
+ // It may be that selection->link is NULL, see a_Selection_button_press.
+ if (link) {
+ // Reset old selection.
+ highlight (false, 0);
+ resetSelection ();
+
+ // Transfer link state into selection state.
+ from = link->cloneDeepIterator ();
+ fromChar = linkChar;
+ to = from->createVariant (it);
+ toChar = correctCharPos (to, charPos);
+ selectionState = SELECTING;
+
+ // Reset link status.
+ resetLink ();
+
+ highlight (true, 0);
+
+ } else {
+ // A link was pressed on, but there is nothing to select. Reset
+ // everything.
+ resetSelection ();
+ resetLink ();
+ }
+}
+
+/**
+ * \brief This method is used by core::dw::SelectionState::buttonMotion and
+ * core::dw::SelectionState::buttonRelease, and changes the second limit of
+ * the already existing selection region.
+ */
+void SelectionState::adjustSelection (Iterator *it, int charPos)
+{
+ DeepIterator *newTo;
+ int newToChar, cmpOld, cmpNew, cmpDiff, len;
+ bool bruteHighlighting = false;
+
+ newTo = to->createVariant (it);
+ newToChar = correctCharPos (newTo, charPos);
+
+ cmpOld = to->compareTo (from);
+ cmpNew = newTo->compareTo (from);
+
+ if (cmpOld == 0 || cmpNew == 0) {
+ // Either before, or now, the limits differ only by the character
+ // position.
+ bruteHighlighting = true;
+ } else if (cmpOld * cmpNew < 0) {
+ // The selection order has changed, i.e. the user moved the selection
+ // end again beyond the position he started.
+ bruteHighlighting = true;
+ } else {
+ // Here, cmpOld and cmpNew are equivalent and != 0.
+ cmpDiff = newTo->compareTo (to);
+
+ if (cmpOld * cmpDiff > 0) {
+ // The user has enlarged the selection. Highlight the difference.
+ if (cmpDiff < 0) {
+ len = correctCharPos (to, END_OF_WORD);
+ highlight0 (true, newTo, newToChar, to, len + 1, 1);
+ } else {
+ highlight0 (true, to, 0, newTo, newToChar, -1);
+ }
+ } else {
+ if (cmpOld * cmpDiff < 0) {
+ // The user has reduced the selection. Unhighlight the difference.
+ highlight0 (false, to, 0, newTo, 0, cmpDiff);
+ }
+
+ // Otherwise, the user has changed the position only slightly.
+ // In both cases, re-highlight the new position.
+ if (cmpOld < 0) {
+ len = correctCharPos (newTo, END_OF_WORD);
+ newTo->highlight (newToChar, len + 1, HIGHLIGHT_SELECTION);
+ } else
+ newTo->highlight (0, newToChar, HIGHLIGHT_SELECTION);
+ }
+ }
+
+ if (bruteHighlighting)
+ highlight (false, 0);
+
+ delete to;
+ to = newTo;
+ toChar = newToChar;
+
+ if (bruteHighlighting)
+ highlight (true, 0);
+}
+
+/**
+ * \brief This method deals especially with the case that a widget passes
+ * dw::core::SelectionState::END_OF_WORD.
+ */
+int SelectionState::correctCharPos (DeepIterator *it, int charPos)
+{
+ Iterator *top = it->getTopIterator ();
+ int len;
+
+ if (top->getContent()->type == Content::TEXT)
+ len = strlen(top->getContent()->text);
+ else
+ len = 1;
+
+ return misc::min(charPos, len);
+}
+
+void SelectionState::highlight0 (bool fl, DeepIterator *from, int fromChar,
+ DeepIterator *to, int toChar, int dir)
+{
+ DeepIterator *a, *b, *i;
+ int cmp, aChar, bChar;
+ bool start;
+
+ if (from && to) {
+ cmp = from->compareTo (to);
+ if (cmp == 0) {
+ if (fl) {
+ if (fromChar < toChar)
+ from->highlight (fromChar, toChar, HIGHLIGHT_SELECTION);
+ else
+ from->highlight (toChar, fromChar, HIGHLIGHT_SELECTION);
+ } else
+ from->unhighlight (0, HIGHLIGHT_SELECTION);
+ return;
+ }
+
+ if (cmp < 0) {
+ a = from;
+ aChar = fromChar;
+ b = to;
+ bChar = toChar;
+ } else {
+ a = to;
+ aChar = toChar;
+ b = from;
+ bChar = fromChar;
+ }
+
+ for (i = a->cloneDeepIterator (), start = true;
+ (cmp = i->compareTo (b)) <= 0;
+ i->next (), start = false) {
+ if (i->getContent()->type == Content::TEXT) {
+ if (fl) {
+ if (start) {
+ i->highlight (aChar, strlen (i->getContent()->text) + 1,
+ HIGHLIGHT_SELECTION);
+ } else if (cmp == 0) {
+ // the end
+ i->highlight (0, bChar, HIGHLIGHT_SELECTION);
+ } else {
+ i->highlight (0, strlen (i->getContent()->text) + 1,
+ HIGHLIGHT_SELECTION);
+ }
+ } else {
+ i->unhighlight (dir, HIGHLIGHT_SELECTION);
+ }
+ }
+ }
+ delete i;
+ }
+}
+
+void SelectionState::copy()
+{
+ if (from && to) {
+ Iterator *si;
+ DeepIterator *a, *b, *i;
+ int cmp, aChar, bChar;
+ bool start;
+ char *tmp;
+ misc::StringBuffer strbuf;
+
+ cmp = from->compareTo (to);
+ if (cmp == 0) {
+ if (from->getContent()->type == Content::TEXT) {
+ si = from->getTopIterator ();
+ if (fromChar < toChar)
+ tmp = strndup (si->getContent()->text + fromChar,
+ toChar - fromChar);
+ else
+ tmp = strndup (si->getContent()->text + toChar,
+ fromChar - toChar);
+ strbuf.appendNoCopy (tmp);
+ }
+ } else {
+ if (cmp < 0) {
+ a = from;
+ aChar = fromChar;
+ b = to;
+ bChar = toChar;
+ } else {
+ a = to;
+ aChar = toChar;
+ b = from;
+ bChar = fromChar;
+ }
+
+ for (i = a->cloneDeepIterator (), start = true;
+ (cmp = i->compareTo (b)) <= 0;
+ i->next (), start = false) {
+ si = i->getTopIterator ();
+ switch (si->getContent()->type) {
+ case Content::TEXT:
+ if (start) {
+ tmp = strndup (si->getContent()->text + aChar,
+ strlen (i->getContent()->text) - aChar);
+ strbuf.appendNoCopy (tmp);
+ } else if (cmp == 0) {
+ // the end
+ tmp = strndup (si->getContent()->text, bChar);
+ strbuf.appendNoCopy (tmp);
+ } else
+ strbuf.append (si->getContent()->text);
+
+ if (si->getContent()->space && cmp != 0)
+ strbuf.append (" ");
+
+ break;
+
+ case Content::BREAK:
+ if (si->getContent()->breakSpace > 0)
+ strbuf.append ("\n\n");
+ else
+ strbuf.append ("\n");
+ break;
+ default:
+ // Make pedantic compilers happy. Especially
+ // DW_CONTENT_WIDGET is never returned by a DwDeepIterator.
+ break;
+ }
+ }
+ delete i;
+ }
+
+ layout->copySelection(strbuf.getChars());
+ }
+}
+
+} // namespace core
+} // namespace dw
diff --git a/dw/selection.hh b/dw/selection.hh
new file mode 100644
index 0000000..ef9df0e
--- /dev/null
+++ b/dw/selection.hh
@@ -0,0 +1,241 @@
+#ifndef __DW_SELECTION_H__
+#define __DW_SELECTION_H__
+
+#ifndef __INCLUDED_FROM_DW_CORE_HH__
+# error Do not include this file directly, use "core.hh" instead.
+#endif
+
+namespace dw {
+namespace core {
+
+/**
+ * \brief This class handles selections, as well as activation of links,
+ * which is closely related.
+ *
+ * <h3>General Overview</h3>
+ *
+ * dw::core::SelectionState is associated with dw::core::Layout. The selection
+ * state is controlled by "abstract events", which are sent by single
+ * widgets by calling one of the following methods:
+ *
+ * <ul>
+ * <li> dw::core::SelectionState::buttonPress for button press events,
+ * <li> dw::core::SelectionState::buttonRelease for button release events, and
+ * <li> dw::core::SelectionState::buttonMotion for motion events (with pressed
+ * mouse button).
+ * </ul>
+ *
+ * The widget must construct simple iterators (dw::core::Iterator), which will
+ * be transferred to deep iterators (dw::core::DeepIterator), see below for
+ * more details. All event handling methods have the same signature, the
+ * arguments in detail are:
+ *
+ * <table>
+ * <tr><td>dw::core::Iterator *it <td>the iterator pointing on the item
+ * under the mouse pointer; this
+ * iterator \em must be created with
+ * dw::core::Content::SELECTION_CONTENT
+ * as mask
+ * <tr><td>int charPos <td>the exact (character) position
+ * within the iterator,
+ * <tr><td>int linkNo <td>if this item is associated with a
+ * link, its number (see
+ * dw::core::Layout::LinkReceiver),
+ * otherwise -1
+ * <tr><td>dw::core::EventButton *event <td>the event itself; only the button
+ * is used
+ * </table>
+ *
+ * Look also at dw::core::SelectionState::handleEvent, which may be useful
+ * in some circumstances.
+ *
+ * In some cases, \em charPos would be difficult to determine. E.g., when
+ * the dw::Textblock widget decides that the user is pointing on a position
+ * <i>at the end</i> of an image (DwImage), it constructs a simple iterator
+ * pointing on this image widget. In a simple iterator, that fact that
+ * the pointer is at the end, would be represented by \em charPos == 1. But
+ * when transferring this simple iterator into an deep iterator, this
+ * simple iterator is discarded and instead the stack has an iterator
+ * pointing to text at the top. As a result, only the first letter of the
+ * ALT text would be copied.
+ *
+ * To avoid this problem, widgets should in this case pass
+ * dw::core::SelectionState::END_OF_WORD as \em charPos, which is then
+ * automatically reduced to the actual length of the deep(!) iterator.
+ *
+ * The return value is the same as in DwWidget event handling methods.
+ * I.e., in most cases, they should simply return it. The events
+ * dw::core::Layout::LinkReceiver::press,
+ * dw::core::Layout::LinkReceiver::release and
+ * dw::core::Layout::LinkReceiver::click (but not
+ * dw::core::Layout::LinkReceiver::enter) are emitted by these methods, so
+ * that widgets which let dw::core::SelectionState handle links, should only
+ * emit dw::core::Layout::LinkReceiver::enter for themselves.
+ *
+ * <h3>Selection State</h3>
+ *
+ * Selection interferes with handling the activation of links, so the
+ * latter is also handled by the dw::core::SelectionState. Details are based on
+ * following guidelines:
+ *
+ * <ol>
+ * <li> It should be simple to select links and to start selection in
+ * links. The rule to distinguish between link activation and
+ * selection is that the selection starts as soon as the user leaves
+ * the link. (This is, IMO, a useful feature. Even after drag and
+ * drop has been implemented in dillo, this should be somehow
+ * preserved.)
+ *
+ * <li> The selection should stay as long as possible, i.e., the old
+ * selection is only cleared when a new selection is started.
+ * </ol>
+ *
+ * The latter leads to a model with two states: the selection state and
+ * the link handling state.
+ *
+ * The general selection works, for events not pointing on links, like
+ * this (numbers in parantheses after the event denote the button, "n"
+ * means arbitrary button):
+ *
+ * \dot
+ * digraph G {
+ * node [shape=ellipse, fontname=Helvetica, fontsize=10];
+ * edge [arrowhead="open", labelfontname=Helvetica, labelfontsize=10,
+ * color="#404040", labelfontcolor="#000080",
+ * fontname=Helvetica, fontsize=10, fontcolor="#000080"];
+ * fontname=Helvetica; fontsize=10;
+ *
+ * NONE;
+ * SELECTING;
+ * q [label="Anything selected?", shape=plaintext];
+ * SELECTED;
+ *
+ * NONE -> SELECTING [label="press(1)\non non-link"];
+ * SELECTING -> SELECTING [label="motion(1)"];
+ * SELECTING -> q [label="release(1)"];
+ * q -> SELECTED [label="yes"];
+ * q -> NONE [label="no"];
+ * SELECTED -> SELECTING [label="press(1)"];
+ *
+ * }
+ * \enddot
+ *
+ * The selected region is represented by two instances of
+ * dw::core::DeepIterator.
+ *
+ * Links are handled by a different state machine:
+ *
+ * \dot
+ * digraph G {
+ * node [shape=ellipse, fontname=Helvetica, fontsize=10];
+ * edge [arrowhead="open", labelfontname=Helvetica, labelfontsize=10,
+ * color="#404040", labelfontcolor="#000080",
+ * fontname=Helvetica, fontsize=10, fontcolor="#000080"];
+ * fontname=Helvetica; fontsize=10;
+ *
+ * LINK_NONE;
+ * LINK_PRESSED;
+ * click [label="Emit \"click\" signal.", shape=record];
+ * q11 [label="Still the same link?", shape=plaintext];
+ * q21 [label="Still the same link?", shape=plaintext];
+ * q22 [label="n == 1?", shape=plaintext];
+ * SELECTED [label="Switch selection\nto SELECTED", shape=record];
+ * q12 [label="n == 1?", shape=plaintext];
+ * SELECTING [label="Switch selection\nto SELECTING", shape=record];
+ *
+ * LINK_NONE -> LINK_PRESSED [label="press(n)\non link"];
+ * LINK_PRESSED -> q11 [label="motion(n)"];
+ * q11 -> LINK_PRESSED [label="yes"];
+ * q11 -> q12 [label="no"];
+ * q12 -> SELECTING [label="yes"];
+ * SELECTING -> LINK_NONE;
+ * q12 -> LINK_NONE [label="no"];
+ * LINK_PRESSED -> q21 [label="release(n)"];
+ * q21 -> click [label="yes"];
+ * click -> LINK_NONE;
+ * q21 -> q22 [label="no"];
+ * q22 -> SELECTED [label="yes"];
+ * SELECTED -> LINK_NONE;
+ * q22 -> LINK_NONE [label="no"];
+ * }
+ * \enddot
+ *
+ * Switching selection simply means that the selection state will
+ * eventually be SELECTED/SELECTING, with the original and the current
+ * position making up the selection region. This happens for button 1,
+ * events with buttons other than 1 do not affect selection at all.
+ *
+ *
+ * \todo dw::core::SelectionState::buttonMotion currently always assumes
+ * that button 1 has been pressed (since otherwise it would not do
+ * anything). This should be made a bit cleaner.
+ *
+ * \todo The selection should be cleared, when the user selects something
+ * somewhere else (perhaps switched into "non-active" mode, as e.g. Gtk+
+ * does).
+ *
+ */
+class SelectionState
+{
+public:
+ enum { END_OF_WORD = 1 << 30 };
+
+private:
+ Layout *layout;
+
+ // selection
+ enum {
+ NONE,
+ SELECTING,
+ SELECTED
+ } selectionState;
+
+ DeepIterator *from, *to;
+ int fromChar, toChar;
+
+ // link handling
+ enum {
+ LINK_NONE,
+ LINK_PRESSED
+ } linkState;
+
+ int linkButton;
+ DeepIterator *link;
+ int linkChar, linkNumber;
+
+ void resetSelection ();
+ void resetLink ();
+ void switchLinkToSelection (Iterator *it, int charPos);
+ void adjustSelection (Iterator *it, int charPos);
+ static int correctCharPos (DeepIterator *it, int charPos);
+
+ void highlight (bool fl, int dir)
+ { highlight0 (fl, from, fromChar, to, toChar, dir); }
+
+ void highlight0 (bool fl, DeepIterator *from, int fromChar,
+ DeepIterator *to, int toChar, int dir);
+ void copy ();
+
+public:
+ enum EventType { BUTTON_PRESS, BUTTON_RELEASE, BUTTON_MOTION };
+
+ SelectionState ();
+ ~SelectionState ();
+
+ inline void setLayout (Layout *layout) { this->layout = layout; }
+ void reset ();
+ bool buttonPress (Iterator *it, int charPos, int linkNo,
+ EventButton *event);
+ bool buttonRelease (Iterator *it, int charPos, int linkNo,
+ EventButton *event);
+ bool buttonMotion (Iterator *it, int charPos, int linkNo,
+ EventMotion *event);
+
+ bool handleEvent (EventType eventType, Iterator *it, int charPos,
+ int linkNo, MousePositionEvent *event);
+};
+
+} // namespace core
+} // namespace dw
+
+#endif // __DW_SELECTION_H__
diff --git a/dw/style.cc b/dw/style.cc
new file mode 100644
index 0000000..aaeb959
--- /dev/null
+++ b/dw/style.cc
@@ -0,0 +1,1468 @@
+/*
+ * RTFL (originally part of dillo)
+ *
+ * Copyright 2005-2007 Sebastian Geerken <sgeerken@dillo.org>
+ *
+ * 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; with the following exception:
+ *
+ * The copyright holders of RTFL give you permission to link this file
+ * statically or dynamically against all versions of the graphviz
+ * library, which are published by AT&T Corp. under one of the following
+ * licenses:
+ *
+ * - Common Public License version 1.0 as published by International
+ * Business Machines Corporation (IBM), or
+ * - Eclipse Public License version 1.0 as published by the Eclipse
+ * Foundation.
+ *
+ * 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/>.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <math.h>
+
+#include "core.hh"
+#include "../lout/msg.h"
+
+using namespace lout;
+
+namespace dw {
+namespace core {
+namespace style {
+
+const bool drawBackgroundLineByLine = false;
+
+const int MIN_BG_IMG_W = 10;
+const int MIN_BG_IMG_H = 10;
+const int OPT_BG_IMG_W = 50;
+const int OPT_BG_IMG_H = 50;
+
+static void calcBackgroundRelatedValues (StyleImage *backgroundImage,
+ BackgroundRepeat backgroundRepeat,
+ BackgroundAttachment
+ backgroundAttachment,
+ Length backgroundPositionX,
+ Length backgroundPositionY,
+ int xDraw, int yDraw, int widthDraw,
+ int heightDraw, int xRef, int yRef,
+ int widthRef, int heightRef,
+ bool *repeatX, bool *repeatY,
+ int *origX, int *origY,
+ int *tileX1, int *tileX2, int *tileY1,
+ int *tileY2, bool *doDraw);
+
+void StyleAttrs::initValues ()
+{
+ x_link = -1;
+ x_lang[0] = x_lang[1] = 0;
+ x_img = -1;
+ x_tooltip = NULL;
+ textDecoration = TEXT_DECORATION_NONE;
+ textAlign = TEXT_ALIGN_LEFT;
+ textAlignChar = '.';
+ textTransform = TEXT_TRANSFORM_NONE;
+ listStylePosition = LIST_STYLE_POSITION_OUTSIDE;
+ listStyleType = LIST_STYLE_TYPE_DISC;
+ valign = VALIGN_BASELINE;
+ backgroundColor = NULL;
+ backgroundImage = NULL;
+ backgroundRepeat = BACKGROUND_REPEAT;
+ backgroundAttachment = BACKGROUND_ATTACHMENT_SCROLL;
+ backgroundPositionX = createPerLength (0);
+ backgroundPositionY = createPerLength (0);
+ width = height = lineHeight = LENGTH_AUTO;
+ minWidth = maxWidth = minHeight = maxHeight = LENGTH_AUTO;
+ vloat = FLOAT_NONE;
+ clear = CLEAR_NONE;
+ overflow = OVERFLOW_VISIBLE;
+ position = POSITION_STATIC;
+ top = bottom = left = right = LENGTH_AUTO;
+ textIndent = 0;
+ margin.setVal (0);
+ borderWidth.setVal (0);
+ padding.setVal (0);
+ borderCollapse = BORDER_MODEL_SEPARATE;
+ setBorderColor (NULL);
+ setBorderStyle (BORDER_NONE);
+ hBorderSpacing = 0;
+ vBorderSpacing = 0;
+ wordSpacing = 0;
+
+ display = DISPLAY_INLINE;
+ whiteSpace = WHITE_SPACE_NORMAL;
+ cursor = CURSOR_DEFAULT;
+}
+
+/**
+ * \brief Reset those style attributes to their standard values, which are
+ * not inherited, according to CSS.
+ */
+void StyleAttrs::resetValues ()
+{
+ x_img = -1;
+
+ valign = VALIGN_BASELINE;
+ textAlignChar = '.';
+ vloat = FLOAT_NONE; /** \todo Correct? Check specification. */
+ clear = CLEAR_NONE; /** \todo Correct? Check specification. */
+ overflow = OVERFLOW_VISIBLE;
+ position = POSITION_STATIC; /** \todo Correct? Check specification. */
+ top = bottom = left = right = LENGTH_AUTO; /** \todo Correct? Check
+ specification. */
+ backgroundColor = NULL;
+ backgroundImage = NULL;
+ backgroundRepeat = BACKGROUND_REPEAT;
+ backgroundAttachment = BACKGROUND_ATTACHMENT_SCROLL;
+ backgroundPositionX = createPerLength (0);
+ backgroundPositionY = createPerLength (0);
+ width = LENGTH_AUTO;
+ height = LENGTH_AUTO;
+ minWidth = maxWidth = minHeight = maxHeight = LENGTH_AUTO;
+
+ margin.setVal (0);
+ borderWidth.setVal (0);
+ padding.setVal (0);
+ setBorderColor (NULL);
+ setBorderStyle (BORDER_NONE);
+ hBorderSpacing = 0;
+ vBorderSpacing = 0;
+
+ display = DISPLAY_INLINE;
+}
+
+/**
+ * \brief This method returns whether something may change its size, when
+ * its style changes from this style to \em otherStyle.
+ *
+ * It is mainly for optimizing style changes where only colors etc change
+ * (where false would be returned), in some cases it may return true, although
+ * a size change does not actually happen (e.g. when in a certain
+ * context a particular attribute is ignored).
+ *
+ * \todo Should for CSS implemented properly. Currently, size changes are
+ * not needed, so always false is returned. See also
+ * dw::core::Widget::setStyle.
+ */
+bool StyleAttrs::sizeDiffs (StyleAttrs *otherStyle)
+{
+ return false;
+}
+
+bool StyleAttrs::equals (object::Object *other) {
+ StyleAttrs *otherAttrs = (StyleAttrs *) other;
+
+ return this == otherAttrs ||
+ (font == otherAttrs->font &&
+ textDecoration == otherAttrs->textDecoration &&
+ color == otherAttrs->color &&
+ backgroundColor == otherAttrs->backgroundColor &&
+ backgroundImage == otherAttrs->backgroundImage &&
+ backgroundRepeat == otherAttrs->backgroundRepeat &&
+ backgroundAttachment == otherAttrs->backgroundAttachment &&
+ backgroundPositionX == otherAttrs->backgroundPositionX &&
+ backgroundPositionY == otherAttrs->backgroundPositionY &&
+ textAlign == otherAttrs->textAlign &&
+ valign == otherAttrs->valign &&
+ textAlignChar == otherAttrs->textAlignChar &&
+ textTransform == otherAttrs->textTransform &&
+ vloat == otherAttrs->vloat &&
+ clear == otherAttrs->clear &&
+ overflow == otherAttrs->overflow &&
+ position == otherAttrs->position &&
+ top == otherAttrs->top &&
+ bottom == otherAttrs->bottom &&
+ left == otherAttrs->left &&
+ right == otherAttrs->right &&
+ hBorderSpacing == otherAttrs->hBorderSpacing &&
+ vBorderSpacing == otherAttrs->vBorderSpacing &&
+ wordSpacing == otherAttrs->wordSpacing &&
+ width == otherAttrs->width &&
+ height == otherAttrs->height &&
+ minWidth == otherAttrs->minWidth &&
+ maxWidth == otherAttrs->maxWidth &&
+ minHeight == otherAttrs->minHeight &&
+ maxHeight == otherAttrs->maxHeight &&
+ lineHeight == otherAttrs->lineHeight &&
+ textIndent == otherAttrs->textIndent &&
+ margin.equals (&otherAttrs->margin) &&
+ borderWidth.equals (&otherAttrs->borderWidth) &&
+ padding.equals (&otherAttrs->padding) &&
+ borderCollapse == otherAttrs->borderCollapse &&
+ borderColor.top == otherAttrs->borderColor.top &&
+ borderColor.right == otherAttrs->borderColor.right &&
+ borderColor.bottom == otherAttrs->borderColor.bottom &&
+ borderColor.left == otherAttrs->borderColor.left &&
+ borderStyle.top == otherAttrs->borderStyle.top &&
+ borderStyle.right == otherAttrs->borderStyle.right &&
+ borderStyle.bottom == otherAttrs->borderStyle.bottom &&
+ borderStyle.left == otherAttrs->borderStyle.left &&
+ display == otherAttrs->display &&
+ whiteSpace == otherAttrs->whiteSpace &&
+ listStylePosition == otherAttrs->listStylePosition &&
+ listStyleType == otherAttrs->listStyleType &&
+ cursor == otherAttrs->cursor &&
+ x_link == otherAttrs->x_link &&
+ x_lang[0] == otherAttrs->x_lang[0] &&
+ x_lang[1] == otherAttrs->x_lang[1] &&
+ x_img == otherAttrs->x_img &&
+ x_tooltip == otherAttrs->x_tooltip);
+}
+
+int StyleAttrs::hashValue () {
+ return (intptr_t) font +
+ textDecoration +
+ (intptr_t) color +
+ (intptr_t) backgroundColor +
+ (intptr_t) backgroundImage +
+ backgroundRepeat +
+ backgroundAttachment +
+ backgroundPositionX +
+ backgroundPositionY +
+ textAlign +
+ valign +
+ textAlignChar +
+ textTransform +
+ vloat +
+ clear +
+ overflow +
+ position +
+ top +
+ bottom +
+ left +
+ right +
+ hBorderSpacing +
+ vBorderSpacing +
+ wordSpacing +
+ width +
+ height +
+ minWidth +
+ maxWidth +
+ minHeight +
+ maxHeight +
+ lineHeight +
+ textIndent +
+ margin.hashValue () +
+ borderWidth.hashValue () +
+ padding.hashValue () +
+ borderCollapse +
+ (intptr_t) borderColor.top +
+ (intptr_t) borderColor.right +
+ (intptr_t) borderColor.bottom +
+ (intptr_t) borderColor.left +
+ borderStyle.top +
+ borderStyle.right +
+ borderStyle.bottom +
+ borderStyle.left +
+ display +
+ whiteSpace +
+ listStylePosition +
+ listStyleType +
+ cursor +
+ x_link +
+ x_lang[0] + x_lang[1] +
+ x_img +
+ (intptr_t) x_tooltip;
+}
+
+int Style::totalRef = 0;
+container::typed::HashTable <StyleAttrs, Style> * Style::styleTable =
+ new container::typed::HashTable <StyleAttrs, Style> (false, false, 1024);
+
+Style::Style (StyleAttrs *attrs)
+{
+ DBG_OBJ_CREATE ("dw::core::style::Style");
+
+ copyAttrs (attrs);
+
+ DBG_OBJ_ASSOC_CHILD (font);
+ DBG_OBJ_ASSOC_CHILD (color);
+ DBG_OBJ_ASSOC_CHILD (backgroundColor);
+ DBG_OBJ_ASSOC_CHILD (backgroundImage);
+ DBG_OBJ_ASSOC_CHILD (borderColor.top);
+ DBG_OBJ_ASSOC_CHILD (borderColor.bottom);
+ DBG_OBJ_ASSOC_CHILD (borderColor.left);
+ DBG_OBJ_ASSOC_CHILD (borderColor.right);
+ //DBG_OBJ_ASSOC_CHILD (x_tooltip);
+
+ refCount = 1;
+
+ font->ref ();
+ if (color)
+ color->ref ();
+ if (backgroundColor)
+ backgroundColor->ref ();
+ if (backgroundImage)
+ backgroundImage->ref ();
+ if (borderColor.top)
+ borderColor.top->ref();
+ if (borderColor.bottom)
+ borderColor.bottom->ref();
+ if (borderColor.left)
+ borderColor.left->ref();
+ if (borderColor.right)
+ borderColor.right->ref();
+ if (x_tooltip)
+ x_tooltip->ref();
+
+ totalRef++;
+}
+
+Style::~Style ()
+{
+ font->unref ();
+
+ if (color)
+ color->unref ();
+ if (backgroundColor)
+ backgroundColor->unref ();
+ if (backgroundImage)
+ backgroundImage->unref ();
+ if (borderColor.top)
+ borderColor.top->unref();
+ if (borderColor.bottom)
+ borderColor.bottom->unref();
+ if (borderColor.left)
+ borderColor.left->unref();
+ if (borderColor.right)
+ borderColor.right->unref();
+ if (x_tooltip)
+ x_tooltip->unref();
+
+ styleTable->remove (this);
+ totalRef--;
+
+ DBG_OBJ_DELETE ();
+}
+
+void Style::copyAttrs (StyleAttrs *attrs)
+{
+ font = attrs->font;
+ textDecoration = attrs->textDecoration;
+ color = attrs->color;
+ backgroundColor = attrs->backgroundColor;
+ backgroundImage = attrs->backgroundImage;
+ backgroundRepeat = attrs->backgroundRepeat;
+ backgroundAttachment = attrs->backgroundAttachment;
+ backgroundPositionX = attrs->backgroundPositionX;
+ backgroundPositionY = attrs->backgroundPositionY;
+ textAlign = attrs->textAlign;
+ valign = attrs->valign;
+ textAlignChar = attrs->textAlignChar;
+ textTransform = attrs->textTransform;
+ vloat = attrs->vloat;
+ clear = attrs->clear;
+ overflow = attrs->overflow;
+ position = attrs->position;
+ top = attrs->top;
+ bottom = attrs->bottom;
+ left = attrs->left;
+ right = attrs->right;
+ hBorderSpacing = attrs->hBorderSpacing;
+ vBorderSpacing = attrs->vBorderSpacing;
+ wordSpacing = attrs->wordSpacing;
+ width = attrs->width;
+ height = attrs->height;
+ lineHeight = attrs->lineHeight;
+ textIndent = attrs->textIndent;
+ minWidth = attrs->minWidth;
+ maxWidth = attrs->maxWidth;
+ minHeight = attrs->minHeight;
+ maxHeight = attrs->maxHeight;
+ margin = attrs->margin;
+ borderWidth = attrs->borderWidth;
+ padding = attrs->padding;
+ borderCollapse = attrs->borderCollapse;
+ borderColor = attrs->borderColor;
+ borderStyle = attrs->borderStyle;
+ display = attrs->display;
+ whiteSpace = attrs->whiteSpace;
+ listStylePosition = attrs->listStylePosition;
+ listStyleType = attrs->listStyleType;
+ cursor = attrs->cursor;
+ x_link = attrs->x_link;
+ x_lang[0] = attrs->x_lang[0];
+ x_lang[1] = attrs->x_lang[1];
+ x_img = attrs->x_img;
+ x_tooltip = attrs->x_tooltip;
+}
+
+// ----------------------------------------------------------------------
+
+bool FontAttrs::equals(object::Object *other)
+{
+ FontAttrs *otherAttrs = (FontAttrs*)other;
+ return
+ this == otherAttrs ||
+ (size == otherAttrs->size &&
+ weight == otherAttrs->weight &&
+ style == otherAttrs->style &&
+ letterSpacing == otherAttrs->letterSpacing &&
+ fontVariant == otherAttrs->fontVariant &&
+ strcmp (name, otherAttrs->name) == 0);
+}
+
+int FontAttrs::hashValue()
+{
+ int h = object::String::hashValue (name);
+ h = (h << 5) - h + size;
+ h = (h << 5) - h + weight;
+ h = (h << 5) - h + style;
+ h = (h << 5) - h + letterSpacing;
+ h = (h << 5) - h + fontVariant;
+ return h;
+}
+
+Font::~Font ()
+{
+ free ((char*)name);
+ DBG_OBJ_DELETE ();
+}
+
+void Font::copyAttrs (FontAttrs *attrs)
+{
+ name = strdup (attrs->name);
+ size = attrs->size;
+ weight = attrs->weight;
+ style = attrs->style;
+ letterSpacing = attrs->letterSpacing;
+ fontVariant = attrs->fontVariant;
+}
+
+Font *Font::create0 (Layout *layout, FontAttrs *attrs,
+ bool tryEverything)
+{
+ return layout->createFont (attrs, tryEverything);
+}
+
+Font *Font::create (Layout *layout, FontAttrs *attrs)
+{
+ return create0 (layout, attrs, false);
+}
+
+bool Font::exists (Layout *layout, const char *name)
+{
+ return layout->fontExists (name);
+}
+
+// ----------------------------------------------------------------------
+
+bool ColorAttrs::equals(object::Object *other)
+{
+ ColorAttrs *oc = (ColorAttrs*)other;
+ return this == oc || (color == oc->color);
+}
+
+int ColorAttrs::hashValue()
+{
+ return color;
+}
+
+Color::~Color ()
+{
+ DBG_OBJ_DELETE ();
+}
+
+int Color::shadeColor (int color, int d)
+{
+ int red = (color >> 16) & 255;
+ int green = (color >> 8) & 255;
+ int blue = color & 255;
+
+ double oldLightness = ((double) misc::max (red, green, blue)) / 255;
+ double newLightness;
+
+ if (oldLightness > 0.8) {
+ if (d > 0)
+ newLightness = oldLightness - 0.2;
+ else
+ newLightness = oldLightness - 0.4;
+ } else if (oldLightness < 0.2) {
+ if (d > 0)
+ newLightness = oldLightness + 0.4;
+ else
+ newLightness = oldLightness + 0.2;
+ } else
+ newLightness = oldLightness + d * 0.2;
+
+ if (oldLightness) {
+ double f = (newLightness / oldLightness);
+ red = (int)(red * f);
+ green = (int)(green * f);
+ blue = (int)(blue * f);
+ } else {
+ red = green = blue = (int)(newLightness * 255);
+ }
+
+ return (red << 16) | (green << 8) | blue;
+}
+
+int Color::shadeColor (int color, Shading shading)
+{
+ switch (shading) {
+ case SHADING_NORMAL:
+ return color;
+
+ case SHADING_LIGHT:
+ return shadeColor(color, +1);
+
+ case SHADING_INVERSE:
+ return color ^ 0xffffff;
+
+ case SHADING_DARK:
+ return shadeColor(color, -1);
+
+ default:
+ // compiler happiness
+ misc::assertNotReached ();
+ return -1;
+ }
+}
+
+
+Color *Color::create (Layout *layout, int col)
+{
+ ColorAttrs attrs(col);
+
+ return layout->createColor (col);
+}
+
+Tooltip *Tooltip::create (Layout *layout, const char *text)
+{
+ return layout->createTooltip (text);
+}
+
+// ----------------------------------------------------------------------
+
+void StyleImage::StyleImgRenderer::setBuffer (core::Imgbuf *buffer, bool resize)
+{
+ if (image->imgbufSrc)
+ image->imgbufSrc->unref ();
+ if (image->imgbufTiled)
+ image->imgbufTiled->unref ();
+
+ image->imgbufTiled = NULL;
+
+ image->imgbufSrc = buffer;
+ DBG_OBJ_ASSOC (image, image->imgbufSrc);
+
+ if (image->imgbufSrc) {
+ image->imgbufSrc->ref ();
+
+ // If the image is too small, drawing a background will cause
+ // many calls of View::drawImgbuf. For this reason, we create
+ // another image buffer, the "tiled" image buffer, which is
+ // larger (the "optimal" size is defined as OPT_BG_IMG_W *
+ // OPT_BG_IMG_H) and contains the "source" buffer several times.
+ //
+ // This "tiled" buffer is not used when 'background-repeat' has
+ // another value than 'repeat', for obvious reasons. Image
+ // buffers only "tiled" in one dimension (to optimize 'repeat-x'
+ // and 'repeat-y') are not supported.
+
+ if (image->imgbufSrc->getRootWidth() * image->imgbufSrc->getRootHeight()
+ < MIN_BG_IMG_W * MIN_BG_IMG_H) {
+ image->tilesX =
+ misc::max (OPT_BG_IMG_W / image->imgbufSrc->getRootWidth(), 1);
+ image->tilesY =
+ misc::max (OPT_BG_IMG_H / image->imgbufSrc->getRootHeight(), 1);
+ image->imgbufTiled =
+ image->imgbufSrc->createSimilarBuf
+ (image->tilesX * image->imgbufSrc->getRootWidth(),
+ image->tilesY * image->imgbufSrc->getRootHeight());
+
+ DBG_OBJ_ASSOC (image, image->imgbufTiled);
+ }
+ }
+}
+
+void StyleImage::StyleImgRenderer::drawRow (int row)
+{
+ if (image->imgbufTiled) {
+ // A row of data has been copied to the source buffer, here it
+ // is copied into the tiled buffer.
+
+ // Unfortunately, this code may be called *after* some other
+ // implementations of ImgRenderer::drawRow, which actually
+ // *draw* the tiled buffer, which is so not up to date
+ // (ImgRendererDist does not define an order). OTOH, these
+ // drawing implementations calle Widget::queueResize, so the
+ // actual drawing (and so access to the tiled buffer) is done
+ // later.
+
+ int w = image->imgbufSrc->getRootWidth ();
+ int h = image->imgbufSrc->getRootHeight ();
+
+ for (int x = 0; x < image->tilesX; x++)
+ for (int y = 0; y < image->tilesX; y++)
+ image->imgbufSrc->copyTo (image->imgbufTiled, x * w, y * h,
+ 0, row, w, 1);
+ }
+}
+
+void StyleImage::StyleImgRenderer::finish ()
+{
+ // Nothing to do.
+}
+
+void StyleImage::StyleImgRenderer::fatal ()
+{
+ // Nothing to do.
+}
+
+StyleImage::StyleImage ()
+{
+ DBG_OBJ_CREATE ("dw::core::style::StyleImage");
+
+ refCount = 0;
+ imgbufSrc = NULL;
+ imgbufTiled = NULL;
+
+ imgRendererDist = new ImgRendererDist ();
+ styleImgRenderer = new StyleImgRenderer (this);
+ imgRendererDist->put (styleImgRenderer);
+}
+
+StyleImage::~StyleImage ()
+{
+ if (imgbufSrc)
+ imgbufSrc->unref ();
+ if (imgbufTiled)
+ imgbufTiled->unref ();
+
+ delete imgRendererDist;
+ delete styleImgRenderer;
+
+ DBG_OBJ_DELETE ();
+}
+
+void StyleImage::ExternalImgRenderer::setBuffer (core::Imgbuf *buffer,
+ bool resize)
+{
+ // Nothing to do?
+}
+
+void StyleImage::ExternalImgRenderer::drawRow (int row)
+{
+ if (drawBackgroundLineByLine) {
+ StyleImage *backgroundImage;
+ if (readyToDraw () && (backgroundImage = getBackgroundImage ())) {
+ // All single rows are drawn.
+
+ Imgbuf *imgbuf = backgroundImage->getImgbufSrc();
+ int imgWidth = imgbuf->getRootWidth ();
+ int imgHeight = imgbuf->getRootHeight ();
+
+ int x, y, width, height;
+ getBgArea (&x, &y, &width, &height);
+
+ int xRef, yRef, widthRef, heightRef;
+ getRefArea (&xRef, &yRef, &widthRef, &heightRef);
+
+ bool repeatX, repeatY, doDraw;
+ int origX, origY, tileX1, tileX2, tileY1, tileY2;
+
+ calcBackgroundRelatedValues (backgroundImage,
+ getBackgroundRepeat (),
+ getBackgroundAttachment (),
+ getBackgroundPositionX (),
+ getBackgroundPositionY (),
+ x, y, width, height, xRef, yRef, widthRef,
+ heightRef, &repeatX, &repeatY, &origX,
+ &origY, &tileX1, &tileX2, &tileY1,
+ &tileY2, &doDraw);
+
+ //printf ("tileX1 = %d, tileX2 = %d, tileY1 = %d, tileY2 = %d\n",
+ // tileX1, tileX2, tileY1, tileY2);
+
+ if (doDraw)
+ // Only iterate over y, because the rows can be combined
+ // horizontally.
+ for (int tileY = tileY1; tileY <= tileY2; tileY++) {
+ int x1 = misc::max (origX + tileX1 * imgWidth, x);
+ int x2 = misc::min (origX + (tileX2 + 1) * imgWidth, x + width);
+
+ int yt = origY + tileY * imgHeight + row;
+ if (yt >= y && yt < y + height)
+ draw (x1, yt, x2 - x1, 1);
+ }
+ }
+ }
+}
+
+void StyleImage::ExternalImgRenderer::finish ()
+{
+ if (!drawBackgroundLineByLine) {
+ if (readyToDraw ()) {
+ // Draw total area, as a whole.
+ int x, y, width, height;
+ getBgArea (&x, &y, &width, &height);
+ draw (x, y, width, height);
+ }
+ }
+}
+
+void StyleImage::ExternalImgRenderer::fatal ()
+{
+ // Nothing to do.
+}
+
+// ----------------------------------------------------------------------
+
+StyleImage *StyleImage::ExternalWidgetImgRenderer::getBackgroundImage ()
+{
+ Style *style = getStyle ();
+ return style ? style->backgroundImage : NULL;
+}
+
+BackgroundRepeat StyleImage::ExternalWidgetImgRenderer::getBackgroundRepeat ()
+{
+ Style *style = getStyle ();
+ return style ? style->backgroundRepeat : BACKGROUND_REPEAT;
+}
+
+BackgroundAttachment
+ StyleImage::ExternalWidgetImgRenderer::getBackgroundAttachment ()
+{
+ Style *style = getStyle ();
+ return style ? style->backgroundAttachment : BACKGROUND_ATTACHMENT_SCROLL;
+}
+
+Length StyleImage::ExternalWidgetImgRenderer::getBackgroundPositionX ()
+{
+ Style *style = getStyle ();
+ return style ? style->backgroundPositionX : createPerLength (0);
+}
+
+Length StyleImage::ExternalWidgetImgRenderer::getBackgroundPositionY ()
+{
+ Style *style = getStyle ();
+ return style ? style->backgroundPositionY : createPerLength (0);
+}
+
+// ----------------------------------------------------------------------
+
+/*
+ * The drawBorder{Top,Bottom,Left,Right} functions are similar. They
+ * use a trapezium as draw polygon, or drawTypedLine() for dots and dashes.
+ * Although the concept is simple, achieving pixel accuracy is laborious [1].
+ *
+ * [1] http://www.dillo.org/css_compat/tests/border-style.html
+ */
+static void drawBorderTop(View *view, Style *style,
+ int x1, int y1, int x2, int y2)
+
+{
+ int d, w;
+ Point points[4];
+ const bool filled = true, convex = true;
+ bool ridge = false, inset = false, dotted = false;
+ Color::Shading shading = Color::SHADING_NORMAL;
+
+ if (!style->borderColor.top || style->borderWidth.top == 0)
+ return;
+
+ switch (style->borderStyle.top) {
+ case BORDER_NONE:
+ case BORDER_HIDDEN:
+ break;
+ case BORDER_DOTTED:
+ dotted = true;
+ case BORDER_DASHED:
+ w = style->borderWidth.top;
+ view->drawTypedLine(style->borderColor.top, shading,
+ dotted ? LINE_DOTTED : LINE_DASHED,
+ w, x1+w/2, y1+w/2, x2-w/2, y2+w/2);
+ break;
+ case BORDER_SOLID:
+ case BORDER_INSET:
+ inset = true;
+ case BORDER_OUTSET:
+ if (style->borderStyle.top != BORDER_SOLID)
+ shading = (inset) ? Color::SHADING_DARK : Color::SHADING_LIGHT;
+
+ if (style->borderWidth.top == 1) {
+ view->drawLine(style->borderColor.top, shading, x1, y1, x2, y2);
+ } else {
+ points[0].x = x1;
+ points[1].x = x2 + 1;
+ points[0].y = points[1].y = y1;
+ points[2].x = points[1].x - style->borderWidth.right;
+ points[3].x = x1 + style->borderWidth.left;
+ points[2].y = points[3].y = points[0].y + style->borderWidth.top;
+ view->drawPolygon (style->borderColor.top, shading, filled, convex,
+ points, 4);
+ }
+ break;
+ case BORDER_RIDGE:
+ ridge = true;
+ case BORDER_GROOVE:
+ d = style->borderWidth.top & 1;
+ points[0].x = x1;
+ points[1].x = x2 + 1;
+ points[0].y = points[1].y = y1;
+ points[2].x = x2 - style->borderWidth.right / 2;
+ points[3].x = x1 + style->borderWidth.left / 2;
+ points[2].y = points[3].y = y1 + style->borderWidth.top / 2 + d;
+ shading = (ridge) ? Color::SHADING_LIGHT : Color::SHADING_DARK;
+ view->drawPolygon (style->borderColor.top, shading, filled, convex,
+ points, 4);
+ points[0].x = x1 + style->borderWidth.left / 2 + d;
+ points[1].x = x2 - style->borderWidth.right / 2 + 1 - d;
+ points[0].y = points[1].y = y1 + style->borderWidth.top / 2 + d;
+ points[2].x = x2 - style->borderWidth.right + 1 - d;
+ points[3].x = x1 + style->borderWidth.left;
+ points[2].y = points[3].y = y1 + style->borderWidth.top;
+ shading = (ridge) ? Color::SHADING_DARK : Color::SHADING_LIGHT;
+ view->drawPolygon (style->borderColor.top, shading, filled, convex,
+ points, 4);
+ break;
+ case BORDER_DOUBLE:
+ w = (int) rint(style->borderWidth.top / 3.0);
+ d = w ? style->borderWidth.top - 2 * w : 0;
+ int w_l = (int) rint(style->borderWidth.left / 3.0);
+ int w_r = (int) rint(style->borderWidth.right / 3.0);
+ if (style->borderWidth.top == 1) {
+ view->drawLine(style->borderColor.top, shading, x1, y1, x2, y2);
+ break;
+ }
+ points[0].x = x1;
+ points[1].x = x2 + 1;
+ points[0].y = points[1].y = y1;
+ points[2].x = points[1].x - w_r;
+ points[3].x = points[0].x + w_l;
+ points[2].y = points[3].y = points[0].y + w;
+ view->drawPolygon (style->borderColor.top, shading, filled, convex,
+ points, 4);
+ points[0].x = x1 + style->borderWidth.left - w_l;
+ points[1].x = x2 + 1 - style->borderWidth.right + w_r;
+ points[0].y = points[1].y = y1 + w + d;
+ points[2].x = x2 + 1 - style->borderWidth.right;
+ points[3].x = x1 + style->borderWidth.left;
+ points[2].y = points[3].y = y1 + style->borderWidth.top;
+ view->drawPolygon (style->borderColor.top, shading, filled, convex,
+ points, 4);
+ break;
+ }
+}
+
+static void drawBorderBottom(View *view, Style *style,
+ int x1, int y1, int x2, int y2)
+
+{
+ int d, w;
+ Point points[4];
+ const bool filled = true, convex = true;
+ bool ridge = false, inset = false, dotted = false;
+ Color::Shading shading = Color::SHADING_NORMAL;
+
+ if (!style->borderColor.bottom || style->borderWidth.bottom == 0)
+ return;
+
+ switch (style->borderStyle.bottom) {
+ case BORDER_NONE:
+ case BORDER_HIDDEN:
+ break;
+ case BORDER_DOTTED:
+ dotted = true;
+ case BORDER_DASHED:
+ w = style->borderWidth.bottom;
+ view->drawTypedLine(style->borderColor.bottom, shading,
+ dotted ? LINE_DOTTED : LINE_DASHED,
+ w, x1+w/2, y1-w/2, x2-w/2, y2-w/2);
+ break;
+ case BORDER_SOLID:
+ case BORDER_INSET:
+ inset = true;
+ case BORDER_OUTSET:
+ if (style->borderStyle.bottom != BORDER_SOLID)
+ shading = (inset) ? Color::SHADING_LIGHT : Color::SHADING_DARK;
+
+ if (style->borderWidth.bottom == 1) { /* 1 pixel line */
+ view->drawLine(style->borderColor.bottom, shading, x1, y1, x2, y2);
+ } else {
+ points[0].x = x1 - 1;
+ points[1].x = x2 + 2;
+ points[0].y = points[1].y = y1 + 1;
+ points[2].x = points[1].x - style->borderWidth.right;
+ points[3].x = points[0].x + style->borderWidth.left;
+ points[2].y = points[3].y = points[0].y-style->borderWidth.bottom;
+ view->drawPolygon (style->borderColor.bottom, shading, filled, convex,
+ points, 4);
+ }
+ break;
+ case BORDER_RIDGE:
+ ridge = true;
+ case BORDER_GROOVE:
+ w = style->borderWidth.bottom;
+ d = w & 1;
+ points[0].x = x1 - 1;
+ points[1].x = x2 + 2 - d;
+ points[0].y = points[1].y = y1 + 1;
+ points[2].x = points[1].x - style->borderWidth.right / 2;
+ points[3].x = points[0].x + style->borderWidth.left / 2 + d;
+ points[2].y = points[3].y = points[0].y - w/2 - d;
+ shading = (ridge) ? Color::SHADING_DARK : Color::SHADING_LIGHT;
+ view->drawPolygon (style->borderColor.bottom, shading, filled, convex,
+ points, 4);
+ // clockwise
+ points[0].x = x1 + style->borderWidth.left - 1;
+ points[1].x = x2 + 1 - style->borderWidth.right + 1;
+ points[0].y = points[1].y = y1 - w + 1;
+ points[2].x = points[1].x + style->borderWidth.right / 2;
+ points[3].x = points[0].x - style->borderWidth.left / 2;
+ points[2].y = points[3].y = points[0].y + w/2;
+ shading = (ridge) ? Color::SHADING_LIGHT : Color::SHADING_DARK;
+ view->drawPolygon (style->borderColor.bottom, shading, filled, convex,
+ points, 4);
+ break;
+ case BORDER_DOUBLE:
+ w = (int) rint(style->borderWidth.bottom / 3.0);
+ d = w ? style->borderWidth.bottom - 2 * w : 0;
+ int w_l = (int) rint(style->borderWidth.left / 3.0);
+ int w_r = (int) rint(style->borderWidth.right / 3.0);
+ if (style->borderWidth.bottom == 1) {
+ view->drawLine(style->borderColor.bottom, shading, x1, y1, x2, y2);
+ break;
+ }
+ points[0].x = x2 + 2;
+ points[1].x = x1 - 1;
+ points[0].y = points[1].y = y1 + 1;
+ points[2].x = points[1].x + w_l;
+ points[3].x = points[0].x - w_r;
+ points[2].y = points[3].y = points[0].y - w;
+ view->drawPolygon (style->borderColor.bottom, shading, filled, convex,
+ points, 4);
+ points[0].x = x2 + 2 - style->borderWidth.right + w_r;
+ points[1].x = x1 - 1 + style->borderWidth.left - w_l;
+ points[0].y = points[1].y = y1 + 1 - w - d;
+ points[2].x = x1 - 1 + style->borderWidth.left;
+ points[3].x = x2 + 2 - style->borderWidth.right;
+ points[2].y = points[3].y = y1 + 1 - style->borderWidth.bottom;
+ view->drawPolygon (style->borderColor.bottom, shading, filled, convex,
+ points, 4);
+ break;
+ }
+}
+
+static void drawBorderLeft(View *view, Style *style,
+ int x1, int y1, int x2, int y2)
+
+{
+ int d, w;
+ Point points[4];
+ bool filled = true, convex = true;
+ bool ridge = false, inset = false, dotted = false;
+ Color::Shading shading = Color::SHADING_NORMAL;
+
+ if (!style->borderColor.left || style->borderWidth.left == 0)
+ return;
+
+ switch (style->borderStyle.left) {
+ case BORDER_NONE:
+ case BORDER_HIDDEN:
+ break;
+ case BORDER_DOTTED:
+ dotted = true;
+ case BORDER_DASHED:
+ w = style->borderWidth.left;
+ view->drawTypedLine(style->borderColor.left, shading,
+ dotted ? LINE_DOTTED : LINE_DASHED,
+ w, x1+w/2, y1+w/2, x1+w/2, y2-w/2);
+ break;
+ case BORDER_SOLID:
+ case BORDER_INSET:
+ inset = true;
+ case BORDER_OUTSET:
+ if (style->borderStyle.left != BORDER_SOLID)
+ shading = (inset) ? Color::SHADING_DARK : Color::SHADING_LIGHT;
+ if (style->borderWidth.left == 1) { /* 1 pixel line */
+ view->drawLine(style->borderColor.left, shading, x1, y1, x2, y2);
+ } else {
+ points[0].x = points[1].x = x1;
+ points[0].y = y1 - 1;
+ points[1].y = y2 + 1;
+ points[2].x = points[3].x = points[0].x + style->borderWidth.left;
+ points[2].y = points[1].y - style->borderWidth.bottom;
+ points[3].y = points[0].y + style->borderWidth.top;
+ view->drawPolygon (style->borderColor.left, shading, filled, convex,
+ points, 4);
+ }
+ break;
+ case BORDER_RIDGE:
+ ridge = true;
+ case BORDER_GROOVE:
+ w = style->borderWidth.left;
+ d = w & 1;
+ points[0].x = points[1].x = x1;
+ points[0].y = y1;
+ points[1].y = y2;
+ points[2].x = points[3].x = x1 + w / 2 + d;
+ points[2].y = y2 - style->borderWidth.bottom / 2;
+ points[3].y = y1 + style->borderWidth.top / 2;
+ shading = (ridge) ? Color::SHADING_LIGHT : Color::SHADING_DARK;
+ view->drawPolygon (style->borderColor.left, shading, filled, convex,
+ points, 4);
+ points[0].x = points[1].x = x1 + w / 2 + d;
+ points[0].y = y1 + style->borderWidth.top / 2;
+ points[1].y = y2 - style->borderWidth.bottom / 2;
+ points[2].x = points[3].x = x1 + w;
+ points[2].y = y2 - style->borderWidth.bottom;
+ points[3].y = y1 + style->borderWidth.top;
+ shading = (ridge) ? Color::SHADING_DARK : Color::SHADING_LIGHT;
+ view->drawPolygon (style->borderColor.left, shading, filled, convex,
+ points, 4);
+ break;
+ case BORDER_DOUBLE:
+ w = (int) rint(style->borderWidth.left / 3.0);
+ d = w ? style->borderWidth.left - 2 * w : 0;
+ int w_b = (int) rint(style->borderWidth.bottom / 3.0);
+ int w_t = (int) rint(style->borderWidth.top / 3.0);
+ if (style->borderWidth.left == 1) {
+ view->drawLine(style->borderColor.left, shading, x1, y1, x2, y2-1);
+ break;
+ }
+ points[0].x = points[1].x = x1;
+ points[0].y = y1 - 1;
+ points[1].y = y2 + 1;
+ points[2].x = points[3].x = points[0].x + w;
+ points[2].y = points[1].y - w_b;
+ points[3].y = points[0].y + w_t;
+ view->drawPolygon (style->borderColor.left, shading, filled, convex,
+ points, 4);
+ points[0].x = points[1].x = x1 + w + d;
+ points[0].y = y1 - 1 + style->borderWidth.top - w_t;
+ points[1].y = y2 + 1 - style->borderWidth.bottom + w_b;
+ points[2].x = points[3].x = points[0].x + w;
+ points[2].y = y2 + 1 - style->borderWidth.bottom;
+ points[3].y = y1 - 1 + style->borderWidth.top;
+ view->drawPolygon (style->borderColor.left, shading, filled, convex,
+ points, 4);
+ break;
+ }
+}
+
+static void drawBorderRight(View *view, Style *style,
+ int x1, int y1, int x2, int y2)
+
+{
+ int d, w;
+ Point points[4];
+ const bool filled = true, convex = true;
+ bool ridge = false, inset = false, dotted = false;
+ Color::Shading shading = Color::SHADING_NORMAL;
+
+ if (!style->borderColor.right || style->borderWidth.right == 0)
+ return;
+
+ switch (style->borderStyle.right) {
+ case BORDER_NONE:
+ case BORDER_HIDDEN:
+ break;
+ case BORDER_DOTTED:
+ dotted = true;
+ case BORDER_DASHED:
+ w = style->borderWidth.right;
+ view->drawTypedLine(style->borderColor.right, shading,
+ dotted ? LINE_DOTTED : LINE_DASHED,
+ w, x1 - w/2, y1 + w/2, x1 - w/2, y2 - w/2);
+ break;
+ case BORDER_SOLID:
+ case BORDER_INSET:
+ inset = true;
+ case BORDER_OUTSET:
+ if (style->borderStyle.right != BORDER_SOLID)
+ shading = (inset) ? Color::SHADING_LIGHT : Color::SHADING_DARK;
+ if (style->borderWidth.right == 1) { /* 1 pixel line */
+ view->drawLine(style->borderColor.right, shading, x1, y1, x2, y2);
+ } else {
+ points[0].x = points[1].x = x1 + 1;
+ points[0].y = y1 - 1;
+ points[1].y = y2 + 1;
+ points[2].x = points[3].x = points[0].x-style->borderWidth.right;
+ points[2].y = points[1].y - style->borderWidth.bottom;
+ points[3].y = points[0].y + style->borderWidth.top;
+ view->drawPolygon (style->borderColor.right, shading, filled, convex,
+ points,4);
+ }
+ break;
+ case BORDER_RIDGE:
+ ridge = true;
+ case BORDER_GROOVE:
+ w = style->borderWidth.right;
+ d = w & 1;
+ points[0].x = points[1].x = x1 + 1;
+ points[0].y = y1;
+ points[1].y = y2;
+ points[2].x = points[3].x = points[0].x - w / 2 - d;
+ points[2].y = y2 - style->borderWidth.bottom / 2;
+ points[3].y = points[0].y + style->borderWidth.top / 2;
+ shading = (ridge) ? Color::SHADING_DARK : Color::SHADING_LIGHT;
+ view->drawPolygon (style->borderColor.right, shading, filled, convex,
+ points, 4);
+ points[0].x = points[1].x = x1 + 1 - w / 2 - d;
+ points[0].y = y1 + style->borderWidth.top / 2;
+ points[1].y = y2 - style->borderWidth.bottom / 2;
+ points[2].x = points[3].x = x1 + 1 - w;
+ points[2].y = y2 - style->borderWidth.bottom;
+ points[3].y = y1 + style->borderWidth.top;
+ shading = (ridge) ? Color::SHADING_LIGHT: Color::SHADING_DARK;
+ view->drawPolygon (style->borderColor.right, shading, filled, convex,
+ points, 4);
+ break;
+ case BORDER_DOUBLE:
+ w = (int) rint(style->borderWidth.right / 3.0);
+ d = w ? style->borderWidth.right - 2 * w : 0;
+ int w_b = (int) rint(style->borderWidth.bottom / 3.0);
+ int w_t = (int) rint(style->borderWidth.top / 3.0);
+ if (style->borderWidth.right == 1) {
+ view->drawLine(style->borderColor.right, shading, x1, y1, x2, y2);
+ break;
+ }
+ points[0].x = points[1].x = x1 + 1;
+ points[0].y = y1 - 1;
+ points[1].y = y2 + 1;
+ points[2].x = points[3].x = points[0].x - w;
+ points[2].y = points[1].y - w_b;
+ points[3].y = points[0].y + w_t;
+ view->drawPolygon (style->borderColor.right, shading, filled, convex,
+ points, 4);
+ points[0].x = points[1].x = x1 + 1 - w - d;
+ points[0].y = y1 - 1 + style->borderWidth.top - w_t;
+ points[1].y = y2 + 1 - style->borderWidth.bottom + w_b;
+ points[2].x = points[3].x = points[0].x - w;
+ points[2].y = y2 + 1 - style->borderWidth.bottom;
+ points[3].y = y1 - 1 + style->borderWidth.top;
+ view->drawPolygon (style->borderColor.right, shading, filled, convex,
+ points, 4);
+ break;
+ }
+}
+
+/**
+ * \brief Draw the border of a region in window, according to style.
+ *
+ * Used by dw::core::Widget::drawBox and dw::core::Widget::drawWidgetBox.
+ *
+ * "area" is the area to be drawn, "x", "y", "width" and "height"
+ * define the box itself. All are given in canvas coordinates.
+ */
+void drawBorder (View *view, Layout *layout, Rectangle *area,
+ int x, int y, int width, int height,
+ Style *style, bool inverse)
+{
+ /** \todo a lot! */
+ int xb1, yb1, xb2, yb2;
+
+ // top left and bottom right point of outer border boundary
+ xb1 = x + style->margin.left;
+ yb1 = y + style->margin.top;
+ xb2 = x + (width > 0 ? width - 1 : 0) - style->margin.right;
+ yb2 = y + (height > 0 ? height - 1 : 0) - style->margin.bottom;
+
+ /*
+ // top left and bottom right point of inner border boundary
+ xp1 = xb1 + style->borderWidth.left;
+ yp1 = yb1 + style->borderWidth.top;
+ xp2 = xb2 - style->borderWidth.right;
+ yp2 = yb2 - style->borderWidth.bottom;
+
+ light = inverse ? Color::SHADING_DARK : Color::SHADING_LIGHT;
+ dark = inverse ? Color::SHADING_LIGHT : Color::SHADING_DARK;
+ normal = inverse ? Color::SHADING_INVERSE : Color::SHADING_NORMAL;
+ */
+
+ drawBorderRight(view, style, xb2, yb1, xb2, yb2);
+ drawBorderLeft(view, style, xb1, yb1, xb1, yb2);
+ drawBorderTop(view, style, xb1, yb1, xb2, yb1);
+ drawBorderBottom(view, style, xb1, yb2, xb2, yb2);
+}
+
+
+/**
+ * \brief Draw the background (content plus padding) of a region in window,
+ * according to style.
+ *
+ * Used by dw::core::Widget::drawBox and dw::core::Widget::drawWidgetBox.
+ *
+ * "area" is the area to be drawn, "x", "y", "width" and "height"
+ * define the box itself (padding box). "xRef", "yRef", "widthRef" and
+ * "heightRef" define the reference area, which is important for the
+ * tiling of background images (for position 0%/0%, a tile is set at
+ * xRef/yRef; for position 100%/100%, a tile is set at xRef +
+ * widthRef/yRef + widthRef). See calls for more informations; in most
+ * cases, these boxes are identical (padding box). All these
+ * coordinates are given in canvas coordinates.
+ *
+ * "atTop" should be true, only if the area is drawn directly on the
+ * canvas, not on top of other areas; this is only true for the
+ * toplevel widget itself (not parts of its contents). Toplevel widget
+ * background colors are already set as viewport background color, so
+ * that drawing again is is not neccessary, but some time can be
+ * saved.
+ *
+ * Otherwise, the caller should not try to increase the performance by
+ * doing some tests before; this is all done in this method.
+ *
+ * "bgColor" is passes implicitly. For non-inversed drawing,
+ * style->backgroundColor may simply used. However, when drawing is
+ * inversed, and style->backgroundColor is undefined (NULL), a
+ * background color defined higher in the hierarchy (which is not
+ * accessable here) must be used.
+ *
+ * (Background *images* are never drawn inverse.)
+ */
+void drawBackground (View *view, Layout *layout, Rectangle *area,
+ int x, int y, int width, int height,
+ int xRef, int yRef, int widthRef, int heightRef,
+ Style *style, Color *bgColor, bool inverse, bool atTop)
+{
+ bool hasBgColor = bgColor != NULL &&
+ // The test for background colors is rather simple, since only the color
+ // has to be compared, ...
+ (!atTop || layout->getBgColor () != bgColor);
+ bool hasBgImage = (style->backgroundImage != NULL &&
+ style->backgroundImage->getImgbufSrc() != NULL) &&
+ // ... but for backgrounds, it would be rather complicated. To handle the
+ // two cases (normal HTML in a viewport, where the layout background
+ // image is set, and contents of <button> within a flat view, where the
+ // background image of the toplevel widget is set), only the background
+ // images are compared. A full test, which also deals with all other
+ // attributes related to background images (repeat, position etc.) would
+ // be complicated and useless, so not worth the work.
+ (!atTop || layout->getBgImage () != style->backgroundImage);
+
+ // Since widgets are always drawn from top to bottom, it is *not*
+ // necessary to draw the background if background color and image
+ // are not set (NULL), i. e. shining through.
+
+ if (hasBgColor || hasBgImage) {
+ Rectangle bgArea, intersection;
+ bgArea.x = x;
+ bgArea.y = y;
+ bgArea.width = width;
+ bgArea.height = height;
+
+ if (area->intersectsWith (&bgArea, &intersection)) {
+ if (hasBgColor)
+ view->drawRectangle (bgColor,
+ inverse ?
+ Color::SHADING_INVERSE : Color::SHADING_NORMAL,
+ true, intersection.x, intersection.y,
+ intersection.width, intersection.height);
+
+ if (hasBgImage)
+ drawBackgroundImage (view, style->backgroundImage,
+ style->backgroundRepeat,
+ style->backgroundAttachment,
+ style->backgroundPositionX,
+ style->backgroundPositionY,
+ intersection.x, intersection.y,
+ intersection.width, intersection.height,
+ xRef, yRef, widthRef, heightRef);
+
+ }
+ }
+}
+
+void drawBackgroundImage (View *view, StyleImage *backgroundImage,
+ BackgroundRepeat backgroundRepeat,
+ BackgroundAttachment backgroundAttachment,
+ Length backgroundPositionX,
+ Length backgroundPositionY,
+ int x, int y, int width, int height,
+ int xRef, int yRef, int widthRef, int heightRef)
+{
+ //printf ("drawBackgroundImage (..., [img: %d, %d], ..., (%d, %d), %d x %d, "
+ // "(%d, %d), %d x %d)\n", imgWidth, imgHeight, x, y, width, height,
+ // xRef, yRef, widthRef, heightRef);
+
+ bool repeatX, repeatY, doDraw;
+ int origX, origY, tileX1, tileX2, tileY1, tileY2;
+
+ calcBackgroundRelatedValues (backgroundImage, backgroundRepeat,
+ backgroundAttachment, backgroundPositionX,
+ backgroundPositionY, x, y, width, height,
+ xRef, yRef, widthRef, heightRef,
+ &repeatX, &repeatY, &origX, &origY,
+ &tileX1, &tileX2, &tileY1, &tileY2, &doDraw);
+
+ //printf ("tileX1 = %d, tileX2 = %d, tileY1 = %d, tileY2 = %d\n",
+ // tileX1, tileX2, tileY1, tileY2);
+
+ if (doDraw) {
+ // Drawing is done with the "tiled" buffer, but all calculations
+ // before have been done with the "source" buffer.
+
+ Imgbuf *imgbufS = backgroundImage->getImgbufSrc();
+ int imgWidthS = imgbufS->getRootWidth ();
+ int imgHeightS = imgbufS->getRootHeight ();
+
+ Imgbuf *imgbufT = backgroundImage->getImgbufTiled(repeatX, repeatY);
+ int imgWidthT = imgbufT->getRootWidth ();
+ int imgHeightT = imgbufT->getRootHeight ();
+ int tilesX = backgroundImage->getTilesX (repeatX, repeatY);
+ int tilesY = backgroundImage->getTilesY (repeatX, repeatY);
+
+ for (int tileX = tileX1; tileX <= tileX2; tileX += tilesX)
+ for (int tileY = tileY1; tileY <= tileY2; tileY += tilesY) {
+ int xt = origX + tileX * imgWidthS;
+ int x1 = misc::max (xt, x);
+ int x2 = misc::min (xt + imgWidthT, x + width);
+ int yt = origY + tileY * imgHeightS;
+ int y1 = misc::max (yt, y);
+ int y2 = misc::min (yt + imgHeightT, y + height);
+
+ view->drawImage (imgbufT, xt, yt, x1 - xt, y1 - yt,
+ x2 - x1, y2 - y1);
+ }
+ }
+}
+
+void calcBackgroundRelatedValues (StyleImage *backgroundImage,
+ BackgroundRepeat backgroundRepeat,
+ BackgroundAttachment backgroundAttachment,
+ Length backgroundPositionX,
+ Length backgroundPositionY,
+ int xDraw, int yDraw, int widthDraw,
+ int heightDraw, int xRef, int yRef,
+ int widthRef, int heightRef, bool *repeatX,
+ bool *repeatY, int *origX, int *origY,
+ int *tileX1, int *tileX2, int *tileY1,
+ int *tileY2, bool *doDraw)
+{
+ Imgbuf *imgbuf = backgroundImage->getImgbufSrc();
+ int imgWidth = imgbuf->getRootWidth ();
+ int imgHeight = imgbuf->getRootHeight ();
+
+ *repeatX = backgroundRepeat == BACKGROUND_REPEAT ||
+ backgroundRepeat == BACKGROUND_REPEAT_X;
+ *repeatY = backgroundRepeat == BACKGROUND_REPEAT ||
+ backgroundRepeat == BACKGROUND_REPEAT_Y;
+
+ *origX = xRef +
+ (isPerLength (backgroundPositionX) ?
+ multiplyWithPerLength (widthRef - imgWidth, backgroundPositionX) :
+ absLengthVal (backgroundPositionX));
+ *origY = yRef +
+ (isPerLength (backgroundPositionY) ?
+ multiplyWithPerLength (heightRef - imgHeight, backgroundPositionY) :
+ absLengthVal (backgroundPositionY));
+
+ *tileX1 = xDraw < *origX ?
+ - (*origX - xDraw + imgWidth - 1) / imgWidth :
+ (xDraw - *origX) / imgWidth;
+ *tileX2 = *origX < xDraw + widthDraw ?
+ (xDraw + widthDraw - *origX - 1) / imgWidth :
+ - (*origX - (xDraw + widthDraw) + imgWidth - 1) / imgWidth;
+ *tileY1 = yDraw < *origY ?
+ - (*origY - yDraw + imgHeight - 1) / imgHeight :
+ (yDraw - *origY) / imgHeight;
+ *tileY2 = *origY < yDraw + heightDraw ?
+ (yDraw + heightDraw - *origY - 1) / imgHeight :
+ - (*origY - (yDraw + heightDraw) + imgHeight - 1) / imgHeight;
+
+ *doDraw = true;
+ if (!*repeatX) {
+ // Only center tile (tileX = 0) is drawn, ...
+ if (*tileX1 <= 0 && *tileX2 >= 0)
+ // ... and is visible.
+ *tileX1 = *tileX2 = 0;
+ else
+ // ... but is not visible.
+ *doDraw = false;
+ }
+
+ if (!*repeatY) {
+ // Analogue.
+ if (*tileY1 <= 0 && *tileY2 >= 0)
+ *tileY1 = *tileY2 = 0;
+ else
+ *doDraw = false;
+ }
+}
+
+// ----------------------------------------------------------------------
+
+static const char
+ *const roman_I0[] = { "","I","II","III","IV","V","VI","VII","VIII","IX" },
+ *const roman_I1[] = { "","X","XX","XXX","XL","L","LX","LXX","LXXX","XC" },
+ *const roman_I2[] = { "","C","CC","CCC","CD","D","DC","DCC","DCCC","CM" },
+ *const roman_I3[] = { "","M","MM","MMM","MMMM" };
+
+static void strAsciiTolower (char *s)
+{
+ for ( ; *s; s++)
+ *s = misc::AsciiTolower (*s);
+}
+
+/**
+ * \brief Convert a number into a string, in a given list style.
+ *
+ * Used for ordered lists.
+ */
+void numtostr (int num, char *buf, int buflen, ListStyleType listStyleType)
+{
+ int i3, i2, i1, i0;
+ bool low = false;
+ int start_ch = 'A';
+
+ if (buflen <= 0)
+ return;
+
+ switch(listStyleType){
+ case LIST_STYLE_TYPE_LOWER_ALPHA:
+ case LIST_STYLE_TYPE_LOWER_LATIN:
+ start_ch = 'a';
+ case LIST_STYLE_TYPE_UPPER_ALPHA:
+ case LIST_STYLE_TYPE_UPPER_LATIN:
+ i0 = num - 1;
+ i1 = i0/26 - 1; i2 = i1/26 - 1;
+ if (i2 > 25) /* more than 26+26^2+26^3=18278 elements ? */
+ snprintf(buf, buflen, "****.");
+ else
+ snprintf(buf, buflen, "%c%c%c.",
+ i2<0 ? ' ' : start_ch + i2%26,
+ i1<0 ? ' ' : start_ch + i1%26,
+ i0<0 ? ' ' : start_ch + i0%26);
+ break;
+ case LIST_STYLE_TYPE_LOWER_ROMAN:
+ low = true;
+ case LIST_STYLE_TYPE_UPPER_ROMAN:
+ i0 = num;
+ i1 = i0/10; i2 = i1/10; i3 = i2/10;
+ i0 %= 10; i1 %= 10; i2 %= 10;
+ if (num < 0 || i3 > 4) /* more than 4999 elements ? */
+ snprintf(buf, buflen, "****.");
+ else
+ snprintf(buf, buflen, "%s%s%s%s.", roman_I3[i3], roman_I2[i2],
+ roman_I1[i1], roman_I0[i0]);
+ break;
+ case LIST_STYLE_TYPE_DECIMAL:
+ default:
+ snprintf(buf, buflen, "%d.", num);
+ break;
+ }
+
+ // ensure termination
+ buf[buflen - 1] = '\0';
+
+ if (low)
+ strAsciiTolower(buf);
+
+}
+
+} // namespace style
+} // namespace core
+} // namespace dw
diff --git a/dw/style.hh b/dw/style.hh
new file mode 100644
index 0000000..230baa2
--- /dev/null
+++ b/dw/style.hh
@@ -0,0 +1,907 @@
+#ifndef __DW_STYLE_HH__
+#define __DW_STYLE_HH__
+
+#include <stdint.h>
+
+#ifndef __INCLUDED_FROM_DW_CORE_HH__
+# error Do not include this file directly, use "core.hh" instead.
+#endif
+
+#include "../lout/signal.hh"
+#include "../lout/debug.hh"
+
+namespace dw {
+namespace core {
+
+/**
+ * \brief Anything related to Dillo %Widget styles is defined here.
+ *
+ * <h3>Overview</h3>
+ *
+ * dw::core::style::Style provides some resources and attributes for
+ * drawing widgets, as well as for parts of a widget (e.g., dw::Textblock
+ * uses styles for its words). Creating a style is done by filling a
+ * dw::core::style::StyleAttrs with the attributes and calling
+ * dw::core::style::Style::create:
+ *
+ * \code
+ * dw::core::style::Style styleAttrs;
+ * dw::core::style::Style *style;
+ * dw::core::Layout *layout;
+ *
+ * // ...
+ *
+ * styleAttrs.foo = bar;
+ * // etc.
+ * style = dw::core::style::Style::create (&styleAttrs, layout);
+ * // do something with style
+ * \endcode
+ *
+ * After this, the attributes of a dw::core::style::Style should not be
+ * changed anymore, since styles are often shared between different
+ * widgets etc. (see below). Most times, you simply copy the attributes
+ * of another style (possible, since dw::core::style::Style is a sub
+ * class of dw::core::style::StyleAttrs), modify them and create a new
+ * style:
+ *
+ * \code
+ * styleAttrs = *anotherStyle;
+ * styleAttrs.foo = baz;
+ * style = dw::core::style::Style::create (&styleAttrs, layout);
+ * \endcode
+ *
+ * The dw::core::style::Font structure can be created by
+ * dw::core::style::Font::create, in a similar, with
+ * dw::core::style::FontAttrs, and colors by
+ * dw::core::style::Color::create, passing 0xrrggbb as an
+ * argument. Furthermore, there is dw::core::style::Tooltip, created by
+ * dw::core::style::Tooltip::create.
+ *
+ * Notice that fonts, colors and tooltips are only intended to be used in
+ * conjunction with dw::core::style::Style.
+ *
+ *
+ * <h3>Naming</h3>
+ *
+ * dw::core::style::Style will become important for CSS, each CSS
+ * attribute, which is supported by dillo, will refer to an attribute in
+ * dw::core::style::Style. For this reason, the attributes in
+ * dw::core::style::Style get the names from the CSS attributes, with
+ * "camelCase" instead of hyphens (e.g. "background-color" becomes
+ * "backgroundColor").
+ *
+ * However, dw::core::style::Style will be extended by some more
+ * attributes, which are not defined by CSS. To distinguish them, they
+ * get the prefix "x_", e.g. dw::core::style::Style::x_link.
+ *
+ *
+ * <h3>Lengths and Percentages</h3>
+ *
+ * dw::core::style::Length is a simple data type for lengths and
+ * percentages:
+ *
+ * <ul>
+ * <li> A length refers to an absolute measurement. It is used to
+ * represent the HTML type %Pixels; and the CSS type \<length\>.
+ *
+ * For CSS lengths, there are two units: (i) pixels and absolute
+ * units, which have to be converted to pixels (a pixel is, unlike
+ * in the CSS specification, treated as absolute unit), and (ii) the
+ * relative units "em" and "ex" (see below).
+ *
+ * <li> A percentage refers to a value relative to another value. It is
+ * used for the HTML type %Length; (except %Pixels;), and the CSS
+ * type \<percentage\>.
+ *
+ * <li> A relative length can be used in lists of HTML MultiLengths.
+ * </ul>
+ *
+ * Since many values in CSS may be either lengths or percentages, a
+ * single type is very useful.
+ *
+ * <h4>Useful Functions</h4>
+ *
+ * Creating lengths:
+ *
+ * <ul>
+ * <li> dw::core::style::createAbsLength
+ * <li> dw::core::style::createPerLength
+ * <li> dw::core::style::createRelLength
+ * </ul>
+ *
+ * Examine lengths:
+ *
+ * <ul>
+ * <li> dw::core::style::isAbsLength
+ * <li> dw::core::style::isPerLength
+ * <li> dw::core::style::isRelLength
+ * <li> dw::core::style::absLengthVal
+ * <li> dw::core::style::perLengthVal
+ * <li> dw::core::style::relLengthVal
+ * </ul>
+ *
+ *
+ * <h3>Boxes</h3>
+ *
+ * <h4>The CSS %Box Model</h4>
+ *
+ * For borders, margins etc., the box model defined by CSS2 is
+ * used. dw::core::style::Style contains some members defining these
+ * attributes. A dw::core::Widget must use these values for any
+ * calculation of sizes. There are some helper functions (see
+ * dw/style.hh). A dw::core::style::Style box looks quite similar to a
+ * CSS box:
+ *
+ * \image html dw-style-box-model.png
+ *
+ * <h4>Background colors</h4>
+ *
+ * The background color is stored in
+ * dw::core::style::Style::backgroundColor, which may be NULL (the
+ * background color of the parent widget is shining through).
+ *
+ * For toplevel widgets, this color is set as the background color of the
+ * views (dw::core::View::setBgColor), for other widgets, a filled
+ * rectangle is drawn, covering the content and padding. (This is
+ * compliant with CSS2, the background color of the toplevel element
+ * covers the whole canvas.)
+ *
+ * <h4>Drawing</h4>
+ *
+ * The following methods may be useful:
+ *
+ * <ul>
+ * <li> dw::core::Widget::drawWidgetBox for drawing the box of a widget
+ * (typically at the beginning of the implementation of
+ * dw::core::Widget::draw), and
+ *
+ * <li> dw::core::Widget::drawBox, for drawing parts of a widget (e.g.
+ * dw::Textblock::Word, which has its own dw::Textblock::Word::style).
+ * </ul>
+ *
+ *
+ * <h3>Notes on Memory Management</h3>
+ *
+ * Memory management is done by reference counting,
+ * dw::core::style::Style::create returns a pointer to
+ * dw::core::style::Style with an increased reference counter, so you
+ * should care about calling dw::core::style::Style::unref if it is not
+ * used anymore. You do \em not need to care about the reference counters
+ * of fonts and styles.
+ *
+ * In detail:
+ *
+ * <ul>
+ * <li> dw::core::style::Style::ref is called in
+ *
+ * <ul>
+ * <li> dw::core::Widget::setStyle to assign a style to a widget,
+ * <li> dw::Textblock::addText, dw::Textblock::addWidget,
+ * dw::Textblock::addAnchor, dw::Textblock::addSpace,
+ * dw::Textblock::addParbreak and dw::Textblock::addLinebreak,
+ * to assign a style to a dw::Textblock::Word, and
+ * <li> by the HTML parser, when pushing an element on the stack.
+ * </ul>
+ *
+ * <li> dw::core::style::Style::unref is called in
+ *
+ * <ul>
+ * <li> dw::core::Widget::~Widget, dw::Textblock::~Textblock, by the
+ * HTML parser, when popping an element fom the stack, and
+ * <li> dw::core::Widget::setStyle, dw::Textblock::addText etc.,
+ * these methods overwrite an existing style.
+ * </ul>
+ * </ul>
+ */
+namespace style {
+
+enum Cursor {
+ CURSOR_CROSSHAIR,
+ CURSOR_DEFAULT,
+ CURSOR_POINTER,
+ CURSOR_MOVE,
+ CURSOR_E_RESIZE,
+ CURSOR_NE_RESIZE,
+ CURSOR_NW_RESIZE,
+ CURSOR_N_RESIZE,
+ CURSOR_SE_RESIZE,
+ CURSOR_SW_RESIZE,
+ CURSOR_S_RESIZE,
+ CURSOR_W_RESIZE,
+ CURSOR_TEXT,
+ CURSOR_WAIT,
+ CURSOR_HELP
+};
+
+enum BorderCollapse {
+ BORDER_MODEL_SEPARATE,
+ BORDER_MODEL_COLLAPSE
+};
+
+enum BorderStyle {
+ BORDER_NONE,
+ BORDER_HIDDEN,
+ BORDER_DOTTED,
+ BORDER_DASHED,
+ BORDER_SOLID,
+ BORDER_DOUBLE,
+ BORDER_GROOVE,
+ BORDER_RIDGE,
+ BORDER_INSET,
+ BORDER_OUTSET
+};
+
+enum BackgroundRepeat {
+ BACKGROUND_REPEAT,
+ BACKGROUND_REPEAT_X,
+ BACKGROUND_REPEAT_Y,
+ BACKGROUND_NO_REPEAT
+};
+
+enum BackgroundAttachment {
+ BACKGROUND_ATTACHMENT_SCROLL,
+ BACKGROUND_ATTACHMENT_FIXED
+};
+
+enum TextAlignType {
+ TEXT_ALIGN_LEFT,
+ TEXT_ALIGN_RIGHT,
+ TEXT_ALIGN_CENTER,
+ TEXT_ALIGN_JUSTIFY,
+ TEXT_ALIGN_STRING
+};
+
+enum VAlignType {
+ VALIGN_TOP,
+ VALIGN_BOTTOM,
+ VALIGN_MIDDLE,
+ VALIGN_BASELINE,
+ VALIGN_SUB,
+ VALIGN_SUPER,
+ VALIGN_TEXT_TOP,
+ VALIGN_TEXT_BOTTOM,
+};
+
+enum TextTransform {
+ TEXT_TRANSFORM_NONE,
+ TEXT_TRANSFORM_CAPITALIZE,
+ TEXT_TRANSFORM_UPPERCASE,
+ TEXT_TRANSFORM_LOWERCASE,
+};
+
+/**
+ * \todo Incomplete. Has to be completed for a CSS implementation.
+ */
+enum DisplayType {
+ DISPLAY_BLOCK,
+ DISPLAY_INLINE,
+ DISPLAY_INLINE_BLOCK,
+ DISPLAY_LIST_ITEM,
+ DISPLAY_NONE,
+ DISPLAY_TABLE,
+ DISPLAY_TABLE_ROW_GROUP,
+ DISPLAY_TABLE_HEADER_GROUP,
+ DISPLAY_TABLE_FOOTER_GROUP,
+ DISPLAY_TABLE_ROW,
+ DISPLAY_TABLE_CELL
+};
+
+enum LineType {
+ LINE_NORMAL,
+ LINE_DOTTED,
+ LINE_DASHED
+};
+
+enum ListStylePosition {
+ LIST_STYLE_POSITION_INSIDE,
+ LIST_STYLE_POSITION_OUTSIDE
+};
+enum ListStyleType {
+ LIST_STYLE_TYPE_DISC,
+ LIST_STYLE_TYPE_CIRCLE,
+ LIST_STYLE_TYPE_SQUARE,
+ LIST_STYLE_TYPE_DECIMAL,
+ LIST_STYLE_TYPE_DECIMAL_LEADING_ZERO,
+ LIST_STYLE_TYPE_LOWER_ROMAN,
+ LIST_STYLE_TYPE_UPPER_ROMAN,
+ LIST_STYLE_TYPE_LOWER_GREEK,
+ LIST_STYLE_TYPE_LOWER_ALPHA,
+ LIST_STYLE_TYPE_LOWER_LATIN,
+ LIST_STYLE_TYPE_UPPER_ALPHA,
+ LIST_STYLE_TYPE_UPPER_LATIN,
+ LIST_STYLE_TYPE_HEBREW,
+ LIST_STYLE_TYPE_ARMENIAN,
+ LIST_STYLE_TYPE_GEORGIAN,
+ LIST_STYLE_TYPE_CJK_IDEOGRAPHIC,
+ LIST_STYLE_TYPE_HIRAGANA,
+ LIST_STYLE_TYPE_KATAKANA,
+ LIST_STYLE_TYPE_HIRAGANA_IROHA,
+ LIST_STYLE_TYPE_KATAKANA_IROHA,
+ LIST_STYLE_TYPE_NONE
+};
+
+enum FontStyle {
+ FONT_STYLE_NORMAL,
+ FONT_STYLE_ITALIC,
+ FONT_STYLE_OBLIQUE
+};
+
+enum FontVariant {
+ FONT_VARIANT_NORMAL,
+ FONT_VARIANT_SMALL_CAPS
+};
+
+enum Overflow {
+ OVERFLOW_VISIBLE,
+ OVERFLOW_HIDDEN,
+ OVERFLOW_SCROLL,
+ OVERFLOW_AUTO
+};
+
+enum Position {
+ POSITION_STATIC,
+ POSITION_RELATIVE,
+ POSITION_ABSOLUTE,
+ POSITION_FIXED,
+};
+
+enum TextDecoration {
+ TEXT_DECORATION_NONE = 0,
+ TEXT_DECORATION_UNDERLINE = 1 << 0,
+ TEXT_DECORATION_OVERLINE = 1 << 1,
+ TEXT_DECORATION_LINE_THROUGH = 1 << 2,
+ TEXT_DECORATION_BLINK = 1 << 3
+};
+
+enum WhiteSpace {
+ WHITE_SPACE_NORMAL,
+ WHITE_SPACE_PRE,
+ WHITE_SPACE_NOWRAP,
+ WHITE_SPACE_PRE_WRAP,
+ WHITE_SPACE_PRE_LINE,
+};
+
+enum FloatType {
+ FLOAT_NONE,
+ FLOAT_LEFT,
+ FLOAT_RIGHT
+};
+
+enum ClearType {
+ CLEAR_LEFT,
+ CLEAR_RIGHT,
+ CLEAR_BOTH,
+ CLEAR_NONE
+};
+
+/**
+ * \brief Type for representing all lengths within dw::core::style.
+ *
+ * Lengths are int's. Absolute lengths are represented in the following way:
+ *
+ * \image html dw-style-length-absolute.png
+ *
+ * Percentages:
+ *
+ * \image html dw-style-length-percentage.png
+ *
+ * Relative lengths (only used in HTML):
+ *
+ * \image html dw-style-length-relative.png
+ *
+ * This is an implementation detail, use one of the following functions:
+ *
+ * Creating lengths:
+ *
+ * <ul>
+ * <li> dw::core::style::createAbsLength
+ * <li> dw::core::style::createPerLength
+ * <li> dw::core::style::createRelLength
+ * </ul>
+ *
+ * Examine lengths:
+ *
+ * <ul>
+ * <li> dw::core::style::isAbsLength
+ * <li> dw::core::style::isPerLength
+ * <li> dw::core::style::isRelLength
+ * <li> dw::core::style::absLengthVal
+ * <li> dw::core::style::perLengthVal
+ * <li> dw::core::style::relLengthVal
+ * </ul>
+ *
+ * "auto" lengths are represented as dw::core::style::LENGTH_AUTO.
+ */
+typedef int Length;
+
+/** \brief Returns a length of \em n pixels. */
+inline Length createAbsLength(int n) { return (n << 2) | 1; }
+
+/** \brief Returns a percentage, \em v is relative to 1, not to 100. */
+inline Length createPerLength(double v) {
+ return ((int)(v * (1 << 18)) & ~3) | 2; }
+
+/** \brief Returns a relative length. */
+inline Length createRelLength(double v) {
+ return ((int)(v * (1 << 18)) & ~3) | 3; }
+
+/** \brief Returns true if \em l is an absolute length. */
+inline bool isAbsLength(Length l) { return (l & 3) == 1; }
+
+/** \brief Returns true if \em l is a percentage. */
+inline bool isPerLength(Length l) { return (l & 3) == 2; }
+
+/** \brief Returns true if \em l is a relative length. */
+inline bool isRelLength(Length l) { return (l & 3) == 3; }
+
+/** \brief Returns the value of a length in pixels, as an integer. */
+inline int absLengthVal(Length l) { return l >> 2; }
+
+/** \brief Returns the value of a percentage, relative to 1, as a double.
+ *
+ * When possible, do not use this function directly; it may be removed
+ * soon. Instead, use multiplyWithPerLength or multiplyWithPerLengthRounded.
+ */
+inline double perLengthVal_useThisOnlyForDebugging(Length l)
+{ return (double)(l & ~3) / (1 << 18); }
+
+/** \brief Returns the value of a relative length, as a float.
+ *
+ * When possible, do not use this function directly; it may be removed
+ * soon.
+ */
+inline double relLengthVal(Length l) { return (double)(l & ~3) / (1 << 18); }
+
+/**
+ * \brief Multiply an int with a percentage length, returning int.
+ *
+ * Use this instead of perLengthVal, when possible.
+ */
+inline int multiplyWithPerLength(int x, Length l) {
+ return x * perLengthVal_useThisOnlyForDebugging (l);
+}
+
+/**
+ * \brief Like multiplyWithPerLength, but rounds to nearest integer
+ * instead of down.
+ *
+ * (This function exists for backward compatibility.)
+ */
+inline int multiplyWithPerLengthRounded(int x, Length l) {
+ return lout::misc::roundInt (x * perLengthVal_useThisOnlyForDebugging (l));
+}
+
+inline int multiplyWithRelLength(int x, Length l) {
+ return x * relLengthVal(l);
+}
+
+
+enum {
+ /** \brief Represents "auto" lengths. */
+ LENGTH_AUTO = 0
+};
+
+/**
+ * \brief Represents a dimension box according to the CSS box model.
+ *
+ * Used for dw::core::style::Style::margin,
+ * dw::core::style::Style::borderWidth, and dw::core::style::Style::padding.
+ */
+class Box
+{
+public:
+ /* in future also percentages */
+ int top, right, bottom, left;
+
+ inline void setVal(int val) { top = right = bottom = left = val; }
+ inline bool equals (Box *other) {
+ return top == other->top &&
+ right == other->right &&
+ bottom == other->bottom &&
+ left == other->left;
+ }
+ inline int hashValue () {
+ return top + right + bottom + left;
+ }
+};
+
+class Tooltip;
+class Font;
+class Color;
+class StyleImage;
+
+/**
+ * \sa dw::core::style
+ */
+class StyleAttrs : public lout::object::Object
+{
+public:
+ Font *font;
+ int textDecoration; /* No TextDecoration because of problems converting
+ * TextDecoration <-> int */
+ Color *color, *backgroundColor;
+ StyleImage *backgroundImage;
+ BackgroundRepeat backgroundRepeat;
+ BackgroundAttachment backgroundAttachment;
+ Length backgroundPositionX; // "left" defined by "0%" etc. (see CSS spec)
+ Length backgroundPositionY; // "top" defined by "0%" etc. (see CSS spec)
+
+ TextAlignType textAlign;
+ VAlignType valign;
+ char textAlignChar; /* In future, strings will be supported. */
+ TextTransform textTransform;
+
+ FloatType vloat; /* "float" is a keyword. */
+ ClearType clear;
+
+ Overflow overflow;
+
+ Position position;
+ Length top, bottom, left, right;
+
+ int hBorderSpacing, vBorderSpacing, wordSpacing;
+ Length width, height, lineHeight, textIndent;
+ Length minWidth, maxWidth, minHeight, maxHeight;
+
+ Box margin, borderWidth, padding;
+ BorderCollapse borderCollapse;
+ struct { Color *top, *right, *bottom, *left; } borderColor;
+ struct { BorderStyle top, right, bottom, left; } borderStyle;
+
+ DisplayType display;
+ WhiteSpace whiteSpace;
+ ListStylePosition listStylePosition;
+ ListStyleType listStyleType;
+ Cursor cursor;
+
+ int x_link;
+ int x_img;
+ Tooltip *x_tooltip;
+ char x_lang[2]; /* Either x_lang[0] == x_lang[1] == 0 (no language
+ set), or x_lang contains the RFC 1766 country
+ code in lower case letters. (Only two letters
+ allowed, currently.) */
+
+ void initValues ();
+ void resetValues ();
+
+ bool sizeDiffs (StyleAttrs *otherStyleAttrs);
+
+ inline void setBorderColor(Color *val) {
+ borderColor.top = borderColor.right = borderColor.bottom
+ = borderColor.left = val; }
+ inline void setBorderStyle(BorderStyle val) {
+ borderStyle.top = borderStyle.right = borderStyle.bottom
+ = borderStyle.left = val; }
+
+ inline int boxOffsetX ()
+ { return margin.left + borderWidth.left + padding.left; }
+ inline int boxRestWidth ()
+ { return margin.right + borderWidth.right + padding.right; }
+ inline int boxDiffWidth () { return boxOffsetX () + boxRestWidth (); }
+ inline int boxOffsetY ()
+ { return margin.top + borderWidth.top + padding.top; }
+ inline int boxRestHeight ()
+ { return margin.bottom + borderWidth.bottom + padding.bottom; }
+ inline int boxDiffHeight () { return boxOffsetY () + boxRestHeight (); }
+
+ inline bool hasBackground ()
+ { return backgroundColor != NULL || backgroundImage != NULL; }
+
+ bool equals (lout::object::Object *other);
+ int hashValue ();
+};
+
+
+/**
+ * \sa dw::core::style
+ */
+class Style: public StyleAttrs
+{
+private:
+ static int totalRef;
+ int refCount;
+ static lout::container::typed::HashTable <StyleAttrs, Style> *styleTable;
+
+ Style (StyleAttrs *attrs);
+
+protected:
+ ~Style();
+
+ void copyAttrs (StyleAttrs *attrs);
+
+public:
+ inline static Style *create (StyleAttrs *attrs)
+ {
+ Style *style = styleTable->get (attrs);
+ if (style) {
+ style->ref ();
+ } else {
+ style = new Style (attrs);
+ styleTable->put(style, style);
+ }
+ return style;
+ }
+
+ inline void ref () { refCount++; }
+ inline void unref () { if (--refCount == 0) delete this; }
+};
+
+
+/**
+ * \sa dw::core::style
+ */
+class TooltipAttrs: public lout::object::String
+{
+public:
+ TooltipAttrs(const char *text): lout::object::String(text) { }
+};
+
+/**
+ * \sa dw::core::style
+ */
+class Tooltip: public TooltipAttrs
+{
+private:
+ int refCount;
+
+protected:
+ Tooltip (const char *text): TooltipAttrs(text) { refCount = 0; }
+
+public:
+ static Tooltip *create (dw::core::Layout *layout, const char *text);
+ inline void ref () { refCount++; }
+ inline void unref ()
+ { if (--refCount == 0) delete this; }
+
+ inline virtual void onEnter () { }
+ inline virtual void onLeave () { }
+ inline virtual void onMotion () { }
+};
+
+
+/**
+ * \sa dw::core::style
+ */
+class FontAttrs: public lout::object::Object
+{
+public:
+ const char *name;
+ int size;
+ int weight;
+ int letterSpacing;
+ FontVariant fontVariant;
+ FontStyle style;
+
+ bool equals(lout::object::Object *other);
+ int hashValue();
+};
+
+
+/**
+ * \sa dw::core::style
+ */
+class Font: public FontAttrs
+{
+private:
+ int refCount;
+
+ static Font *create0 (Layout *layout, FontAttrs *attrs, bool tryEverything);
+
+protected:
+ inline Font () {
+ DBG_OBJ_CREATE ("dw::core::style::Font");
+ refCount = 0;
+ }
+ virtual ~Font ();
+
+ void copyAttrs (FontAttrs *attrs);
+
+public:
+ int ascent, descent;
+ int spaceWidth;
+ int xHeight;
+
+ static Font *create (Layout *layout, FontAttrs *attrs);
+ static bool exists (Layout *layout, const char *name);
+
+ inline void ref () { refCount++; }
+ inline void unref () { if (--refCount == 0) delete this; }
+};
+
+
+/**
+ * \sa dw::core::style
+ */
+class ColorAttrs: public lout::object::Object
+{
+protected:
+ int color;
+
+public:
+ inline ColorAttrs(int color)
+ {
+ this->color = color;
+ }
+
+ inline int getColor () { return color; }
+
+ bool equals(lout::object::Object *other);
+ int hashValue();
+};
+
+
+/**
+ * \sa dw::core::style
+ */
+class Color: public ColorAttrs
+{
+private:
+ int refCount;
+
+ void remove(dw::core::Layout *layout);
+ int shadeColor (int color, int d);
+
+protected:
+ inline Color (int color): ColorAttrs (color) {
+ DBG_OBJ_CREATE ("dw::core::style::Color");
+ refCount = 0;
+ }
+ virtual ~Color ();
+
+public:
+ enum Shading { SHADING_NORMAL, SHADING_INVERSE, SHADING_DARK, SHADING_LIGHT,
+ SHADING_NUM };
+
+protected:
+ int shadeColor (int color, Shading shading);
+
+public:
+ static Color *create (Layout *layout, int color);
+
+ inline void ref () { refCount++; }
+ inline void unref ()
+ { if (--refCount == 0) delete this; }
+};
+
+
+class StyleImage: public lout::signal::ObservedObject
+{
+private:
+ class StyleImgRenderer: public ImgRenderer
+ {
+ private:
+ StyleImage *image;
+
+ public:
+ inline StyleImgRenderer (StyleImage *image) { this->image = image; }
+
+ void setBuffer (core::Imgbuf *buffer, bool resize);
+ void drawRow (int row);
+ void finish ();
+ void fatal ();
+ };
+
+ int refCount, tilesX, tilesY;
+ Imgbuf *imgbufSrc, *imgbufTiled;
+ ImgRendererDist *imgRendererDist;
+ StyleImgRenderer *styleImgRenderer;
+
+ StyleImage ();
+ ~StyleImage ();
+
+public:
+ /**
+ * \brief Useful (but not mandatory) base class for updates of
+ * areas with background images.
+ */
+ class ExternalImgRenderer: public ImgRenderer
+ {
+ public:
+ void setBuffer (core::Imgbuf *buffer, bool resize);
+ void drawRow (int row);
+ void finish ();
+ void fatal ();
+
+ /**
+ * \brief If this method returns false, nothing is done at all.
+ */
+ virtual bool readyToDraw () = 0;
+
+ /**
+ * \brief Return the area covered by the background image.
+ */
+ virtual void getBgArea (int *x, int *y, int *width, int *height) = 0;
+
+ /**
+ * \brief Return the "reference area".
+ *
+ * See comment of "drawBackground".
+ */
+ virtual void getRefArea (int *xRef, int *yRef, int *widthRef,
+ int *heightRef) = 0;
+
+ virtual StyleImage *getBackgroundImage () = 0;
+ virtual BackgroundRepeat getBackgroundRepeat () = 0;
+ virtual BackgroundAttachment getBackgroundAttachment () = 0;
+ virtual Length getBackgroundPositionX () = 0;
+ virtual Length getBackgroundPositionY () = 0;
+
+ /**
+ * \brief Draw (or queue for drawing) an area, which is given in
+ * canvas coordinates.
+ */
+ virtual void draw (int x, int y, int width, int height) = 0;
+ };
+
+ /**
+ * \brief Suitable for widgets and parts of widgets.
+ */
+ class ExternalWidgetImgRenderer: public ExternalImgRenderer
+ {
+ public:
+ void getPaddingArea (int *x, int *y, int *width, int *height);
+
+ StyleImage *getBackgroundImage ();
+ BackgroundRepeat getBackgroundRepeat ();
+ BackgroundAttachment getBackgroundAttachment ();
+ Length getBackgroundPositionX ();
+ Length getBackgroundPositionY ();
+
+ /**
+ * \brief Return the style this background image is part of.
+ */
+ virtual Style *getStyle () = 0;
+ };
+
+ static StyleImage *create () { return new StyleImage (); }
+
+ inline void ref () { refCount++; }
+ inline void unref ()
+ { if (--refCount == 0) delete this; }
+
+ inline Imgbuf *getImgbufSrc () { return imgbufSrc; }
+ inline Imgbuf *getImgbufTiled (bool repeatX, bool repeatY)
+ { return (imgbufTiled && repeatX && repeatY) ? imgbufTiled : imgbufSrc; }
+ inline int getTilesX (bool repeatX, bool repeatY)
+ { return (imgbufTiled && repeatX && repeatY) ? tilesX : 1; }
+ inline int getTilesY (bool repeatX, bool repeatY)
+ { return (imgbufTiled && repeatX && repeatY) ? tilesY : 1; }
+ inline ImgRenderer *getMainImgRenderer () { return imgRendererDist; }
+
+ /**
+ * \brief Add an additional ImgRenderer, especially used for
+ * drawing.
+ */
+ inline void putExternalImgRenderer (ImgRenderer *ir)
+ { imgRendererDist->put (ir); }
+
+ /**
+ * \brief Remove a previously added additional ImgRenderer.
+ */
+ inline void removeExternalImgRenderer (ImgRenderer *ir)
+ { imgRendererDist->remove (ir); }
+};
+
+void drawBorder (View *view, Layout *layout, Rectangle *area,
+ int x, int y, int width, int height,
+ Style *style, bool inverse);
+void drawBackground (View *view, Layout *layout, Rectangle *area,
+ int x, int y, int width, int height,
+ int xRef, int yRef, int widthRef, int heightRef,
+ Style *style, Color *bgColor, bool inverse, bool atTop);
+void drawBackgroundImage (View *view, StyleImage *backgroundImage,
+ BackgroundRepeat backgroundRepeat,
+ BackgroundAttachment backgroundAttachment,
+ Length backgroundPositionX,
+ Length backgroundPositionY,
+ int x, int y, int width, int height,
+ int xRef, int yRef, int widthRef, int heightRef);
+void numtostr (int num, char *buf, int buflen, ListStyleType listStyleType);
+
+} // namespace style
+} // namespace core
+} // namespace dw
+
+#endif // __DW_STYLE_HH__
+
diff --git a/dw/types.cc b/dw/types.cc
new file mode 100644
index 0000000..3962d97
--- /dev/null
+++ b/dw/types.cc
@@ -0,0 +1,367 @@
+/*
+ * RTFL (originally part of dillo)
+ *
+ * Copyright 2005-2007 Sebastian Geerken <sgeerken@dillo.org>
+ *
+ * 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; with the following exception:
+ *
+ * The copyright holders of RTFL give you permission to link this file
+ * statically or dynamically against all versions of the graphviz
+ * library, which are published by AT&T Corp. under one of the following
+ * licenses:
+ *
+ * - Common Public License version 1.0 as published by International
+ * Business Machines Corporation (IBM), or
+ * - Eclipse Public License version 1.0 as published by the Eclipse
+ * Foundation.
+ *
+ * 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/>.
+ */
+
+
+
+#include "core.hh"
+#include "../lout/msg.h"
+
+using namespace lout;
+
+namespace dw {
+namespace core {
+
+Rectangle::Rectangle (int x, int y, int width, int height)
+{
+ this->x = x;
+ this->y = y;
+ this->width = width;
+ this->height = height;
+}
+
+/*
+ * Draw rectangle in view relative to point (x,y).
+ */
+void Rectangle::draw (core::View *view, core::style::Style *style, int x,int y)
+{
+ const bool filled = false;
+
+ view->drawRectangle(style->color, core::style::Color::SHADING_NORMAL,filled,
+ x + this->x, y + this->y, this->width, this->height);
+}
+
+/**
+ * Return whether this rectangle and otherRect intersect. If yes,
+ * return the intersection rectangle in dest.
+ */
+bool Rectangle::intersectsWith (Rectangle *otherRect, Rectangle *dest)
+{
+ bool doIntersect =
+ this->x < otherRect->x + otherRect->width &&
+ this->y < otherRect->y + otherRect->height &&
+ otherRect->x < this->x + this->width &&
+ otherRect->y < this->y + this->height;
+
+ if (doIntersect) {
+ dest->x = misc::max(this->x, otherRect->x);
+ dest->y = misc::max(this->y, otherRect->y);
+ dest->width = misc::min(this->x + this->width,
+ otherRect->x + otherRect->width) - dest->x;
+ dest->height = misc::min(this->y + this->height,
+ otherRect->y + otherRect->height) - dest->y;
+ } else {
+ dest->x = dest->y = dest->width = dest->height = 0;
+ }
+
+ return doIntersect;
+}
+
+/*
+ * Return whether this is a subset of otherRect.
+ */
+bool Rectangle::isSubsetOf (Rectangle *otherRect)
+{
+ return
+ x >= otherRect->x &&
+ y >= otherRect->y &&
+ x + width <= otherRect->x + otherRect->width &&
+ y + height <= otherRect->y + otherRect->height;
+}
+
+bool Rectangle::isPointWithin (int x, int y)
+{
+ return
+ x >= this->x && y >= this->y &&
+ x < this->x + width && y < this->y + height;
+}
+
+// ----------------------------------------------------------------------
+
+Circle::Circle (int x, int y, int radius)
+{
+ this->x = x;
+ this->y = y;
+ this->radius = radius;
+}
+
+/*
+ * Draw circle in view relative to point (x,y).
+ */
+void Circle::draw (core::View *view, core::style::Style *style, int x, int y)
+{
+ const bool filled = false;
+
+ view->drawArc(style->color, core::style::Color::SHADING_NORMAL, filled,
+ x + this->x, y + this->y, 2 * this->radius, 2 * this->radius,
+ 0, 360);
+}
+
+bool Circle::isPointWithin (int x, int y)
+{
+ return
+ (x - this->x) * (x - this->x) + (y - this->y) * (y - this->y)
+ <= radius * radius;
+}
+
+// ----------------------------------------------------------------------
+
+Polygon::Polygon ()
+{
+ points = new misc::SimpleVector<Point> (8);
+ minx = miny = 0xffffff;
+ maxx = maxy = -0xffffff;
+}
+
+Polygon::~Polygon ()
+{
+ delete points;
+}
+
+/*
+ * Draw polygon in view relative to point (x,y).
+ */
+void Polygon::draw (core::View *view, core::style::Style *style, int x, int y)
+{
+ if (points->size()) {
+ int i;
+ const bool filled = false, convex = false;
+ Point *pointArray = (Point *)malloc(points->size()*sizeof(struct Point));
+
+ for (i = 0; i < points->size(); i++) {
+ pointArray[i].x = x + points->getRef(i)->x;
+ pointArray[i].y = y + points->getRef(i)->y;
+ }
+ view->drawPolygon(style->color, core::style::Color::SHADING_NORMAL,
+ filled, convex, pointArray, i);
+ free(pointArray);
+ }
+}
+
+void Polygon::addPoint (int x, int y)
+{
+ points->increase ();
+ points->getRef(points->size () - 1)->x = x;
+ points->getRef(points->size () - 1)->y = y;
+
+ minx = misc::min(minx, x);
+ miny = misc::min(miny, y);
+ maxx = misc::max(maxx, x);
+ maxy = misc::max(maxy, y);
+}
+
+/**
+ * \brief Return, whether the line, limited by (ax1, ay1) and (ax2, ay2),
+ * crosses the unlimited line, determined by two points (bx1, by1) and
+ * (bx2, by2).
+ */
+bool Polygon::linesCross0(int ax1, int ay1, int ax2, int ay2,
+ int bx1, int by1, int bx2, int by2)
+{
+ /** TODO Some more description */
+ // If the scalar product is 0, it means that one point is on the second
+ // line, so we check for <= 0, not < 0.
+ int z1 = zOfVectorProduct (ax1 - bx1, ay1 - by1, bx2 - bx1, by2 - by1);
+ int z2 = zOfVectorProduct (ax2 - bx1, ay2 - by1, bx2 - bx1, by2 - by1);
+
+ return (z1 <= 0 && z2 >= 0) || (z1 >= 0 && z2 <= 0);
+}
+
+/**
+ * \brief Return, whether the line, limited by (ax1, ay1) and (ax2, ay2),
+ * crosses the line, limited by (bx1, by1) and (bx2, by2).
+ */
+bool Polygon::linesCross(int ax1, int ay1, int ax2, int ay2,
+ int bx1, int by1, int bx2, int by2)
+{
+ bool cross =
+ linesCross0 (ax1, ay1, ax2, ay2, bx1, by1, bx2, by2) &&
+ linesCross0 (bx1, by1, bx2, by2, ax1, ay1, ax2, ay2);
+ _MSG("(%d, %d) - (%d, %d) and (%d, %d) - (%d, %d) cross? %s.\n",
+ ax1, ay1, ax2, ay2, bx1, by1, bx2, by2, cross ? "Yes" : "No");
+ return cross;
+}
+
+bool Polygon::isPointWithin (int x, int y)
+{
+ if (points->size () < 3 ||
+ (x < minx || x > maxx || y < miny || y >= maxy))
+ return false;
+ else {
+ int numCrosses = 0;
+ for (int i = 0; i < points->size () - 1; i++) {
+ if (linesCross (minx - 1, miny - 1, x, y,
+ points->getRef(i)->x, points->getRef(i)->y,
+ points->getRef(i + 1)->x, points->getRef(i + 1)->y))
+ numCrosses++;
+ }
+ if (linesCross (minx - 1, miny - 1, x, y,
+ points->getRef(points->size () - 1)->x,
+ points->getRef(points->size () - 1)->y,
+ points->getRef(0)->x, points->getRef(0)->y))
+ numCrosses++;
+
+ return numCrosses % 2 == 1;
+ }
+}
+
+Region::Region()
+{
+ rectangleList = new container::typed::List <Rectangle> (true);
+}
+
+Region::~Region()
+{
+ delete rectangleList;
+}
+
+/**
+ * \brief Add a rectangle to the region and combine it with
+ * existing rectangles if possible.
+ * The number of rectangles is forced to be less than 16
+ * by combining excessive rectangles.
+ */
+void Region::addRectangle (Rectangle *rPointer)
+{
+ container::typed::Iterator <Rectangle> it;
+ Rectangle *r = new Rectangle (rPointer->x, rPointer->y,
+ rPointer->width, rPointer->height);
+
+ for (it = rectangleList->iterator (); it.hasNext (); ) {
+ Rectangle *ownRect = it.getNext ();
+
+ int combinedHeight =
+ misc::max(r->y + r->height, ownRect->y + ownRect->height) -
+ misc::min(r->y, ownRect->y);
+ int combinedWidth =
+ misc::max(r->x + r->width, ownRect->x + ownRect->width) -
+ misc::min(r->x, ownRect->x);
+
+ if (rectangleList->size() >= 16 ||
+ combinedWidth * combinedHeight <=
+ ownRect->width * ownRect->height + r->width * r->height) {
+
+ r->x = misc::min(r->x, ownRect->x);
+ r->y = misc::min(r->y, ownRect->y);
+ r->width = combinedWidth;
+ r->height = combinedHeight;
+
+ rectangleList->removeRef (ownRect);
+ }
+ }
+
+ rectangleList->append (r);
+}
+
+Content::Type Content::maskForSelection (bool followReferences)
+{
+ Content::Type widgetMask = (Content::Type)
+ (Content::WIDGET_IN_FLOW |
+ (followReferences ? Content::WIDGET_OOF_REF : Content::WIDGET_OOF_CONT));
+ return (Content::Type)(Content::SELECTION_CONTENT | widgetMask);
+}
+
+void Content::intoStringBuffer(Content *content, misc::StringBuffer *sb)
+{
+ switch(content->type) {
+ case START:
+ sb->append ("<start>");
+ break;
+ case END:
+ sb->append ("<end>");
+ break;
+ case TEXT:
+ sb->append ("\"");
+ sb->append (content->text);
+ sb->append ("\"");
+ break;
+ case WIDGET_IN_FLOW:
+ sb->append ("<widget in flow: ");
+ sb->appendPointer (content->widget);
+ sb->append (" (");
+ sb->append (content->widget->getClassName());
+ sb->append (")>");
+ break;
+ case WIDGET_OOF_REF:
+ sb->append ("<widget oof ref: ");
+ sb->appendPointer (content->widget);
+ sb->append (" (");
+ sb->append (content->widget->getClassName());
+ sb->append (")>");
+ break;
+ case WIDGET_OOF_CONT:
+ sb->append ("<widget oof cont: ");
+ sb->appendPointer (content->widget);
+ sb->append (" (");
+ sb->append (content->widget->getClassName());
+ sb->append (")>");
+ break;
+ case BREAK:
+ sb->append ("<break>");
+ break;
+ default:
+ sb->append ("<");
+ sb->appendInt (content->type);
+ sb->append ("?>");
+ break;
+ }
+}
+
+void Content::maskIntoStringBuffer(Type mask, misc::StringBuffer *sb)
+{
+ sb->append ((mask & START) ? "st" : "--");
+ sb->append (":");
+ sb->append ((mask & END) ? "en" : "--");
+ sb->append (":");
+ sb->append ((mask & TEXT) ? "tx" : "--");
+ sb->append (":");
+ sb->append ((mask & WIDGET_IN_FLOW) ? "wf" : "--");
+ sb->append (":");
+ sb->append ((mask & WIDGET_OOF_REF) ? "Wr" : "--");
+ sb->append (":");
+ sb->append ((mask & WIDGET_OOF_CONT) ? "Wc" : "--");
+ sb->append (":");
+ sb->append ((mask & BREAK) ? "br" : "--");
+}
+
+void Content::print (Content *content)
+{
+ misc::StringBuffer sb;
+ intoStringBuffer (content, &sb);
+ printf ("%s", sb.getChars ());
+}
+
+void Content::printMask (Type mask)
+{
+ misc::StringBuffer sb;
+ maskIntoStringBuffer (mask, &sb);
+ printf ("%s", sb.getChars ());
+}
+
+} // namespace core
+} // namespace dw
diff --git a/dw/types.hh b/dw/types.hh
new file mode 100644
index 0000000..36d6caa
--- /dev/null
+++ b/dw/types.hh
@@ -0,0 +1,238 @@
+#ifndef __DW_TYPES_HH__
+#define __DW_TYPES_HH__
+
+#ifndef __INCLUDED_FROM_DW_CORE_HH__
+# error Do not include this file directly, use "core.hh" instead.
+#endif
+
+namespace dw {
+namespace core {
+
+namespace style {
+ class Style;
+}
+
+enum HPosition
+{
+ HPOS_LEFT,
+ HPOS_CENTER,
+ HPOS_RIGHT,
+ HPOS_INTO_VIEW, /* scroll only, until the content in question comes
+ * into view */
+ HPOS_NO_CHANGE
+};
+
+enum VPosition
+{
+ VPOS_TOP,
+ VPOS_CENTER,
+ VPOS_BOTTOM,
+ VPOS_INTO_VIEW, /* scroll only, until the content in question comes
+ * into view */
+ VPOS_NO_CHANGE
+};
+
+enum ScrollCommand {SCREEN_UP_CMD, SCREEN_DOWN_CMD, SCREEN_LEFT_CMD,
+ SCREEN_RIGHT_CMD, LINE_UP_CMD, LINE_DOWN_CMD,
+ LEFT_CMD, RIGHT_CMD, TOP_CMD, BOTTOM_CMD};
+
+/*
+ * Different "layers" may be highlighted in a widget.
+ */
+enum HighlightLayer
+{
+ HIGHLIGHT_SELECTION,
+ HIGHLIGHT_FINDTEXT,
+ HIGHLIGHT_NUM_LAYERS
+};
+
+struct Point
+{
+ int x;
+ int y;
+};
+
+/**
+ * \brief Abstract interface for different shapes.
+ */
+class Shape: public lout::object::Object
+{
+public:
+ virtual bool isPointWithin (int x, int y) = 0;
+ virtual void draw (core::View *view, core::style::Style *style, int x,
+ int y) = 0;
+};
+
+/**
+ * \brief dw::core::Shape implemtation for simple rectangles.
+ */
+class Rectangle: public Shape
+{
+public:
+ int x;
+ int y;
+ int width;
+ int height;
+
+ inline Rectangle () { }
+ Rectangle (int x, int y, int width, int height);
+
+ void draw (core::View *view, core::style::Style *style, int x, int y);
+ bool intersectsWith (Rectangle *otherRect, Rectangle *dest);
+ bool isSubsetOf (Rectangle *otherRect);
+ bool isPointWithin (int x, int y);
+ bool isEmpty () { return width <= 0 || height <= 0; };
+};
+
+/**
+ * \brief dw::core::Shape implemtation for simple circles.
+ */
+class Circle: public Shape
+{
+public:
+ int x, y, radius;
+
+ Circle (int x, int y, int radius);
+
+ void draw (core::View *view, core::style::Style *style, int x, int y);
+ bool isPointWithin (int x, int y);
+};
+
+/**
+ * \brief dw::core::Shape implemtation for polygons.
+ */
+class Polygon: public Shape
+{
+private:
+ lout::misc::SimpleVector<Point> *points;
+ int minx, miny, maxx, maxy;
+
+ /**
+ * \brief Return the z-coordinate of the vector product of two
+ * vectors, whose z-coordinate is 0 (so that x and y of
+ * the vector product is 0, too).
+ */
+ inline int zOfVectorProduct(int x1, int y1, int x2, int y2) {
+ return x1 * y2 - x2 * y1;
+ }
+
+ bool linesCross0(int ax1, int ay1, int ax2, int ay2,
+ int bx1, int by1, int bx2, int by2);
+ bool linesCross(int ax1, int ay1, int ax2, int ay2,
+ int bx1, int by1, int bx2, int by2);
+
+public:
+ Polygon ();
+ ~Polygon ();
+
+ void draw (core::View *view, core::style::Style *style, int x, int y);
+ void addPoint (int x, int y);
+ bool isPointWithin (int x, int y);
+};
+
+/**
+ * Implementation for a point set.
+ * Currently represented as a set of rectangles not containing
+ * each other.
+ * It is guaranteed that the rectangles returned by rectangles ()
+ * cover all rectangles that were added with addRectangle ().
+ */
+class Region
+{
+private:
+ lout::container::typed::List <Rectangle> *rectangleList;
+
+public:
+ Region ();
+ ~Region ();
+
+ void clear () { rectangleList->clear (); };
+
+ void addRectangle (Rectangle *r);
+
+ lout::container::typed::Iterator <Rectangle> rectangles ()
+ {
+ return rectangleList->iterator ();
+ };
+};
+
+/**
+ * \brief Represents the allocation, i.e. actual position and size of a
+ * dw::core::Widget.
+ */
+struct Allocation
+{
+ int x;
+ int y;
+ int width;
+ int ascent;
+ int descent;
+};
+
+struct Requisition
+{
+ int width;
+ int ascent;
+ int descent;
+};
+
+struct Extremes
+{
+ int minWidth;
+ int maxWidth;
+ int minWidthIntrinsic;
+ int maxWidthIntrinsic;
+};
+
+struct Content
+{
+ enum Type {
+ START = 1 << 0,
+ END = 1 << 1,
+ TEXT = 1 << 2,
+
+ /** \brief widget in normal flow, so that _this_ widget
+ (containing this content) is both container (parent) and
+ generator */
+ WIDGET_IN_FLOW = 1 << 3,
+
+ /** \brief widget out of flow (OOF); _this_ widget (containing
+ this content) is only the container (parent), but _not_
+ generator */
+ WIDGET_OOF_CONT = 1 << 4,
+
+ /** \brief reference to a widget out of flow (OOF); _this_
+ widget (containing this content) is only the generator
+ (parent), but _not_ container */
+ WIDGET_OOF_REF = 1 << 5,
+ BREAK = 1 << 6,
+
+ ALL = 0xff,
+ REAL_CONTENT = 0xff ^ (START | END),
+ SELECTION_CONTENT = TEXT | BREAK, // WIDGET_* must be set additionally
+ ANY_WIDGET = WIDGET_IN_FLOW | WIDGET_OOF_CONT | WIDGET_OOF_REF,
+ };
+
+ /* Content is embedded in struct Word therefore we
+ * try to be space efficient.
+ */
+ short type;
+ bool space;
+ union {
+ const char *text;
+ Widget *widget;
+ int breakSpace;
+ };
+
+ static Content::Type maskForSelection (bool followReferences);
+
+ static void intoStringBuffer(Content *content, lout::misc::StringBuffer *sb);
+ static void maskIntoStringBuffer(Type mask, lout::misc::StringBuffer *sb);
+ static void print (Content *content);
+ static void printMask (Type mask);
+};
+
+} // namespace core
+} // namespace dw
+
+#endif // __DW_TYPES_HH__
diff --git a/dw/ui.cc b/dw/ui.cc
new file mode 100644
index 0000000..c021d49
--- /dev/null
+++ b/dw/ui.cc
@@ -0,0 +1,519 @@
+/*
+ * RTFL (originally part of dillo)
+ *
+ * Copyright 2005-2007 Sebastian Geerken <sgeerken@dillo.org>
+ *
+ * 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; with the following exception:
+ *
+ * The copyright holders of RTFL give you permission to link this file
+ * statically or dynamically against all versions of the graphviz
+ * library, which are published by AT&T Corp. under one of the following
+ * licenses:
+ *
+ * - Common Public License version 1.0 as published by International
+ * Business Machines Corporation (IBM), or
+ * - Eclipse Public License version 1.0 as published by the Eclipse
+ * Foundation.
+ *
+ * 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/>.
+ */
+
+
+
+#include "core.hh"
+#include "../lout/debug.hh"
+
+#include <stdio.h>
+
+namespace dw {
+namespace core {
+namespace ui {
+
+using namespace lout;
+using namespace lout::object;
+
+int Embed::CLASS_ID = -1;
+
+Embed::Embed(Resource *resource)
+{
+ DBG_OBJ_CREATE ("dw::core::ui::Embed");
+ registerName ("dw::core::ui::Embed", &CLASS_ID);
+ this->resource = resource;
+ resource->setEmbed (this);
+ DBG_OBJ_ASSOC_CHILD (resource);
+}
+
+Embed::~Embed()
+{
+ delete resource;
+ DBG_OBJ_DELETE ();
+}
+
+void Embed::sizeRequestImpl (Requisition *requisition)
+{
+ resource->sizeRequest (requisition);
+}
+
+void Embed::getExtremesImpl (Extremes *extremes)
+{
+ resource->getExtremes (extremes);
+ correctExtremes (extremes);
+}
+
+void Embed::sizeAllocateImpl (Allocation *allocation)
+{
+ resource->sizeAllocate (allocation);
+}
+
+int Embed::getAvailWidthOfChild (Widget *child, bool forceValue)
+{
+ return resource->getAvailWidthOfChild (child, forceValue);
+}
+
+int Embed::getAvailHeightOfChild (Widget *child, bool forceValue)
+{
+ return resource->getAvailHeightOfChild (child, forceValue);
+}
+
+void Embed::correctRequisitionOfChild (Widget *child,
+ Requisition *requisition,
+ void (*splitHeightFun) (int, int*, int*))
+{
+ resource->correctRequisitionOfChild (child, requisition, splitHeightFun);
+}
+
+void Embed::correctExtremesOfChild (Widget *child, Extremes *extremes)
+{
+ resource->correctExtremesOfChild (child, extremes);
+}
+
+void Embed::containerSizeChangedForChildren ()
+{
+ DBG_OBJ_ENTER0 ("resize", 0, "containerSizeChangedForChildren");
+ resource->containerSizeChangedForChildren ();
+ DBG_OBJ_LEAVE ();
+}
+
+void Embed::enterNotifyImpl (core::EventCrossing *event)
+{
+ resource->emitEnter();
+ Widget::enterNotifyImpl(event);
+}
+
+void Embed::leaveNotifyImpl (core::EventCrossing *event)
+{
+ resource->emitLeave();
+ Widget::leaveNotifyImpl(event);
+}
+
+bool Embed::buttonPressImpl (core::EventButton *event)
+{
+ bool handled;
+
+ if (event->button == 3) {
+ resource->emitClicked(event);
+ handled = true;
+ } else {
+ handled = false;
+ }
+ return handled;
+}
+
+void Embed::setDisplayed (bool displayed)
+{
+ resource->setDisplayed (displayed);
+}
+
+void Embed::setEnabled (bool enabled)
+{
+ resource->setEnabled (enabled);
+}
+
+void Embed::draw (View *view, Rectangle *area)
+{
+ drawWidgetBox (view, area, false);
+ resource->draw (view, area);
+}
+
+Iterator *Embed::iterator (Content::Type mask, bool atEnd)
+{
+ return resource->iterator (mask, atEnd);
+}
+
+void Embed::setStyle (style::Style *style)
+{
+ resource->setStyle (style);
+ Widget::setStyle (style);
+}
+
+// ----------------------------------------------------------------------
+
+bool Resource::ActivateEmitter::emitToReceiver (lout::signal::Receiver
+ *receiver,
+ int signalNo,
+ int argc, Object **argv)
+{
+ ActivateReceiver *ar = (ActivateReceiver*)receiver;
+ Resource *res = (Resource*)((Pointer*)argv[0])->getValue ();
+
+ switch (signalNo) {
+ case 0:
+ ar->activate (res);
+ break;
+ case 1:
+ ar->enter (res);
+ break;
+ case 2:
+ ar->leave (res);
+ break;
+ default:
+ misc::assertNotReached ();
+ }
+ return false;
+}
+
+void Resource::ActivateEmitter::emitActivate (Resource *resource)
+{
+ Pointer p (resource);
+ Object *argv[1] = { &p };
+ emitVoid (0, 1, argv);
+}
+
+void Resource::ActivateEmitter::emitEnter (Resource *resource)
+{
+ Pointer p (resource);
+ Object *argv[1] = { &p };
+ emitVoid (1, 1, argv);
+}
+
+void Resource::ActivateEmitter::emitLeave (Resource *resource)
+{
+ Pointer p (resource);
+ Object *argv[1] = { &p };
+ emitVoid (2, 1, argv);
+}
+
+// ----------------------------------------------------------------------
+
+Resource::~Resource ()
+{
+ DBG_OBJ_DELETE ();
+}
+
+void Resource::setEmbed (Embed *embed)
+{
+ this->embed = embed;
+}
+
+void Resource::getExtremes (Extremes *extremes)
+{
+ DBG_OBJ_ENTER0 ("resize", 0, "getExtremes");
+
+ /* Simply return the requisition width */
+ Requisition requisition;
+ sizeRequest (&requisition);
+ extremes->minWidth = extremes->maxWidth = requisition.width;
+ extremes->minWidthIntrinsic = extremes->minWidth;
+ extremes->maxWidthIntrinsic = extremes->maxWidth;
+
+ DBG_OBJ_MSGF ("resize", 1, "result: %d / %d",
+ extremes->minWidth, extremes->maxWidth);
+ DBG_OBJ_LEAVE ();
+}
+
+void Resource::sizeAllocate (Allocation *allocation)
+{
+}
+
+int Resource::getAvailWidthOfChild (Widget *child, bool forceValue)
+{
+ // Only used when the resource contains other dillo widgets.
+ misc::assertNotReached ();
+ return 0;
+}
+
+int Resource::getAvailHeightOfChild (Widget *child, bool forceValue)
+{
+ // Only used when the resource contains other dillo widgets.
+ misc::assertNotReached ();
+ return 0;
+}
+
+void Resource::correctRequisitionOfChild (Widget *child,
+ Requisition *requisition,
+ void (*splitHeightFun) (int, int*,
+ int*))
+{
+ // Only used when the resource contains other dillo widgets.
+ misc::assertNotReached ();
+}
+
+void Resource::correctExtremesOfChild (Widget *child, Extremes *extremes)
+{
+ // Only used when the resource contains other dillo widgets.
+ misc::assertNotReached ();
+}
+
+void Resource::containerSizeChangedForChildren ()
+{
+ // No children by default.
+}
+
+void Resource::setDisplayed (bool displayed)
+{
+}
+
+void Resource::draw (View *view, Rectangle *area)
+{
+}
+
+void Resource::setStyle (style::Style *style)
+{
+}
+
+void Resource::emitEnter ()
+{
+ activateEmitter.emitEnter(this);
+}
+
+void Resource::emitLeave ()
+{
+ activateEmitter.emitLeave(this);
+}
+
+bool Resource::ClickedEmitter::emitToReceiver(lout::signal::Receiver *receiver,
+ int signalNo, int argc,
+ Object **argv)
+{
+ ((ClickedReceiver*)receiver)
+ ->clicked ((Resource*)((Pointer*)argv[0])->getValue (),
+ (EventButton*)((Pointer*)argv[1])->getValue());
+ return false;
+}
+
+void Resource::ClickedEmitter::emitClicked (Resource *resource,
+ EventButton *event)
+{
+ Pointer p1 (resource);
+ Pointer p2 (event);
+ Object *argv[2] = { &p1, &p2 };
+ emitVoid (0, 2, argv);
+}
+
+// ----------------------------------------------------------------------
+
+Iterator *LabelButtonResource::iterator (Content::Type mask, bool atEnd)
+{
+ /** \todo Perhaps in brackets? */
+ // return new TextIterator (getEmbed (), mask, atEnd, getLabel ());
+ /** \bug Not implemented. */
+ return new EmptyIterator (getEmbed (), mask, atEnd);
+}
+
+// ----------------------------------------------------------------------
+
+void ComplexButtonResource::LayoutReceiver::resizeQueued (bool extremesChanged)
+{
+ DBG_OBJ_ENTER ("resize", 0, "LayoutReceiver/resizeQueued", "%s",
+ extremesChanged ? "true" : "false");
+ resource->queueResize (extremesChanged);
+ DBG_OBJ_LEAVE ();
+}
+
+ComplexButtonResource::ComplexButtonResource ()
+{
+ DBG_OBJ_CREATE ("dw::core::ui::ComplexButtonResource");
+ layout = NULL;
+ layoutReceiver.resource = this;
+ click_x = click_y = -1;
+}
+
+void ComplexButtonResource::init (Widget *widget)
+{
+ childWidget = widget;
+
+ layout = new Layout (createPlatform ());
+ setLayout (layout);
+ DBG_OBJ_ASSOC_CHILD (layout);
+ layout->setWidget (widget);
+ layout->connect (&layoutReceiver);
+
+ if (getEmbed ())
+ childWidget->setQuasiParent (getEmbed ());
+}
+
+void ComplexButtonResource::setEmbed (Embed *embed)
+{
+ ButtonResource::setEmbed (embed);
+
+ if (childWidget)
+ childWidget->setQuasiParent (getEmbed ());
+}
+
+ComplexButtonResource::~ComplexButtonResource ()
+{
+ delete layout;
+ DBG_OBJ_DELETE ();
+}
+
+void ComplexButtonResource::sizeRequest (Requisition *requisition)
+{
+ DBG_OBJ_ENTER0 ("resize", 0, "sizeRequest");
+
+ Requisition widgetRequisition;
+ childWidget->sizeRequest (&widgetRequisition);
+ requisition->width = widgetRequisition.width + 2 * reliefXThickness ();
+ requisition->ascent = widgetRequisition.ascent + reliefYThickness ();
+ requisition->descent = widgetRequisition.descent + reliefYThickness ();
+
+ DBG_OBJ_MSGF ("resize", 1, "result: %d * (%d + %d)",
+ requisition->width, requisition->ascent, requisition->descent);
+ DBG_OBJ_LEAVE ();
+}
+
+void ComplexButtonResource::getExtremes (Extremes *extremes)
+{
+ DBG_OBJ_ENTER0 ("resize", 0, "getExtremes");
+
+ Extremes widgetExtremes;
+ childWidget->getExtremes (&widgetExtremes);
+ extremes->minWidth = widgetExtremes.minWidth + 2 * reliefXThickness ();
+ extremes->maxWidth = widgetExtremes.maxWidth + 2 * reliefXThickness ();
+ extremes->minWidthIntrinsic = extremes->minWidth;
+ extremes->maxWidthIntrinsic = extremes->maxWidth;
+
+ DBG_OBJ_MSGF ("resize", 1, "result: %d / %d",
+ extremes->minWidth, extremes->maxWidth);
+ DBG_OBJ_LEAVE ();
+}
+
+void ComplexButtonResource::sizeAllocate (Allocation *allocation)
+{
+}
+
+int ComplexButtonResource::getAvailWidthOfChild (Widget *child, bool forceValue)
+{
+ int embedWidth = getEmbed()->getAvailWidth (forceValue);
+ if (embedWidth == -1)
+ return -1;
+ else
+ return misc::max (embedWidth - 2 * reliefXThickness (), 0);
+}
+
+int ComplexButtonResource::getAvailHeightOfChild (Widget *child,
+ bool forceValue)
+{
+ int embedHeight = getEmbed()->getAvailHeight (forceValue);
+ if (embedHeight == -1)
+ return -1;
+ else
+ return misc::max (embedHeight - 2 * reliefYThickness (), 0);
+}
+
+void ComplexButtonResource::correctRequisitionOfChild (Widget *child,
+ Requisition *requisition,
+ void (*splitHeightFun)
+ (int, int*, int*))
+{
+ // Similar to Widget::correctRequisitionOfChild, but for percentage
+ // the relief has to be considered.
+
+ if (style::isPerLength (child->getStyle()->width)) {
+ int availWidth = getEmbed()->getAvailHeight (false);
+ if (availWidth != -1) {
+ int baseWidth = misc::max (availWidth
+ - getEmbed()->boxDiffWidth ()
+ - 2 * reliefXThickness (),
+ 0);
+ requisition->width =
+ child->applyPerWidth (baseWidth, child->getStyle()->width);
+ }
+ } else
+ getEmbed()->correctReqWidthOfChildNoRec (child, requisition);
+
+ // TODO Percentage heights are ignored again.
+ getEmbed()->correctReqHeightOfChildNoRec (child, requisition,
+ splitHeightFun);
+
+}
+
+void ComplexButtonResource::correctExtremesOfChild (Widget *child,
+ Extremes *extremes)
+{
+ // Similar to Widget::correctExtremesOfChild, but for percentage
+ // the relief has to be considered.
+
+ if (style::isPerLength (child->getStyle()->width)) {
+ int availWidth = getEmbed()->getAvailHeight (false);
+ if (availWidth != -1) {
+ int baseWidth = misc::max (availWidth
+ - getEmbed()->boxDiffWidth ()
+ - 2 * reliefXThickness (),
+ 0);
+ extremes->minWidth = extremes->maxWidth =
+ child->applyPerWidth (baseWidth, child->getStyle()->width);
+ }
+ } else
+ getEmbed()->correctExtremesOfChildNoRec (child, extremes);
+}
+
+void ComplexButtonResource::containerSizeChangedForChildren ()
+{
+ layout->containerSizeChanged ();
+}
+
+Iterator *ComplexButtonResource::iterator (Content::Type mask, bool atEnd)
+{
+ /**
+ * \bug Implementation.
+ * This is a bit more complicated: We have two layouts here.
+ */
+ return new EmptyIterator (getEmbed (), mask, atEnd);
+}
+
+// ----------------------------------------------------------------------
+
+Iterator *TextResource::iterator (Content::Type mask, bool atEnd)
+{
+ // return new TextIterator (getEmbed (), mask, atEnd, getText ());
+ /** \bug Not implemented. */
+ return new EmptyIterator (getEmbed (), mask, atEnd);
+}
+
+// ----------------------------------------------------------------------
+
+Iterator *CheckButtonResource::iterator (Content::Type mask, bool atEnd)
+{
+ //return new TextIterator (getEmbed (), mask, atEnd,
+ // isActivated () ? "[X]" : "[ ]");
+ /** \bug Not implemented. */
+ return new EmptyIterator (getEmbed (), mask, atEnd);
+}
+
+// ----------------------------------------------------------------------
+
+RadioButtonResource::GroupIterator::~GroupIterator ()
+{
+}
+
+Iterator *RadioButtonResource::iterator (Content::Type mask, bool atEnd)
+{
+ //return new TextIterator (getEmbed (), mask, atEnd,
+ // isActivated () ? "(*)" : "( )");
+ /** \bug Not implemented. */
+ return new EmptyIterator (getEmbed (), mask, atEnd);
+}
+
+} // namespace ui
+} // namespace core
+} // namespace dw
+
diff --git a/dw/ui.hh b/dw/ui.hh
new file mode 100644
index 0000000..6703ccc
--- /dev/null
+++ b/dw/ui.hh
@@ -0,0 +1,592 @@
+#ifndef __DW_UI_HH__
+#define __DW_UI_HH__
+
+#ifndef __INCLUDED_FROM_DW_CORE_HH__
+# error Do not include this file directly, use "core.hh" instead.
+#endif
+
+namespace dw {
+namespace core {
+
+/**
+ * \brief Anything related to embedded UI widgets is defined here.
+ *
+ * UI resources are another abstraction for Dw widgets, which are not
+ * fully implemented in a platform-independent way. Typically, they
+ * involve creating widgets, which the underlying UI toolkit provides.
+ *
+ * As you see in this diagram:
+ *
+ * \dot
+ * digraph G {
+ * node [shape=record, fontname=Helvetica, fontsize=10];
+ * edge [arrowhead="none", arrowtail="empty", dir="both",
+ * labelfontname=Helvetica, labelfontsize=10, color="#404040",
+ * labelfontcolor="#000080"];
+ * fontname=Helvetica; fontsize=10;
+ *
+ * subgraph cluster_core {
+ * style="dashed"; color="#000080"; fontname=Helvetica; fontsize=10;
+ * label="dw::core";
+ *
+ * subgraph cluster_ui {
+ * style="dashed"; color="#000080"; fontname=Helvetica; fontsize=10;
+ * label="dw::core::ui";
+ *
+ * Embed [URL="\ref dw::core::ui::Embed"];
+ * Resource [color="#a0a0a0", URL="\ref dw::core::ui::Resource"];
+ * LabelButtonResource [color="#a0a0a0",
+ * URL="\ref dw::core::ui::LabelButtonResource"];
+ * EntryResource [color="#a0a0a0",
+ * URL="\ref dw::core::ui::EntryResource"];
+ * etc [color="#a0a0a0", label="..."];
+ * }
+ *
+ * Widget [URL="\ref dw::core::Widget", color="#a0a0a0"];
+ * }
+ *
+ * subgraph cluster_fltk {
+ * style="dashed"; color="#000080"; fontname=Helvetica; fontsize=10;
+ * label="dw::fltk::ui";
+ *
+ * FltkLabelButtonResource
+ * [URL="\ref dw::fltk::ui::FltkLabelButtonResource"];
+ * FltkEntryResource [URL="\ref dw::fltk::ui::FltkEntryResource"];
+ * }
+ *
+ * Widget -> Embed;
+ * Embed -> Resource [arrowhead="open", arrowtail="none",
+ * headlabel="1", taillabel="1"];
+ * Resource -> LabelButtonResource;
+ * Resource -> EntryResource;
+ * Resource -> etc;
+ * LabelButtonResource -> FltkLabelButtonResource;
+ * EntryResource -> FltkEntryResource;
+ * }
+ * \enddot
+ *
+ * <center>[\ref uml-legend "legend"]</center>
+ *
+ * there are several levels:
+ *
+ * <ol>
+ * <li> The Dw widget is dw::core::ui::Embed. It delegates most to
+ * dw::core::ui::Resource, which has similar methods like
+ * dw::core::Widget.
+ *
+ * <li> There are several sub interfaces of dw::core::ui::Resource, which
+ * may provide methods, as e.g. dw::core::ui::ListResource::addItem. In a
+ * platform independent context, you can cast the result of
+ * dw::core::ui::Embed::getResource to a specific sub class, if you
+ * know, which one is used. E.g., if you know, that a given instance
+ * dw::core::ui::Embed refers to a dw::core::ui::ListResource, you can
+ * write something like:
+ *
+ * \code
+ * dw::core::ui::Embed *embed;
+ * //...
+ * ((dw::core::ui::ListResource*)embed->getResource ())->addItem ("Hello!");
+ * \endcode
+ *
+ * <li> These sub classes are then fully implemented in a platform specific
+ * way. For an example, look at dw::fltk::ui.
+ * </ol>
+ *
+ * There is a factory interface, dw::core::ui::ResourceFactory, which
+ * provides methods for creating common resources. By calling
+ * dw::core::Layout::getResourceFactory, which calls
+ * dw::core::Platform::getResourceFactory, you get the factory for the used
+ * platform.
+ *
+ * It is possible to define additional sub classes of
+ * dw::core::ui::Resource, but since they are not provided by
+ * dw::core::ui::ResourceFactory, you have to define some other
+ * abstractions, if you want to remain platform independent.
+ *
+ *
+ * <h3>...</h3>
+ *
+ *
+ * <h3>Resouces needed for HTML</h3>
+ *
+ * This chapter describes, how the form controls defined by HTML are
+ * implemented in Dw. Some of them do not refer to UI resources, but to
+ * other widgets, links to the respective documentations are provided
+ * here.
+ *
+ * <h4>Resouces created with \<INPUT\></h4>
+ *
+ * The HTML \<INPUT\> is always implemented by using UI
+ * resources. \<INPUT\> element has the following attributes:
+ *
+ * <table>
+ * <tr><th>Attribute <th>Implementation
+ * <tr><td>type <td>This defines the resource you have to instantiate.
+ * <tr><td>name <td>Not needed within Dw.
+ * <tr><td>value <td>The initial value is treated differently by different
+ * resources.
+ * <tr><td>checked <td>Parameter to
+ * dw::core::ui::ResourceFactory::createCheckButtonResource
+ * and dw::core::ui::ResourceFactory::createRadioButtonResource.
+ * <tr><td>disabled <td>This is provided for all resources by
+ * dw::core::ui::Resource::setEnabled.
+ * <tr><td>readonly <td>This is provided by
+ * dw::core::ui::TextResource::setEditable.
+ * <tr><td>size <td>This is handled by styles.
+ * <tr><td>maxlength <td>Parameter of
+ * dw::core::ui::ResourceFactory::createEntryResource.
+ * <tr><td>src <td>Handled by the caller (HTML parser).
+ * <tr><td>alt <td>Handled by the caller (HTML parser).
+ * <tr><td>usemap <td>Handled by the caller (HTML parser).
+ * <tr><td>ismap <td>Handled by the caller (HTML parser).
+ * <tr><td>tabindex <td>Not supported currently.
+ * <tr><td>accesskey <td>Not supported currently.
+ * <tr><td>onfocus <td>Not supported currently.
+ * <tr><td>onblur <td>Not supported currently.
+ * <tr><td>onselect <td>Not supported currently.
+ * <tr><td>onchange <td>Not supported currently.
+ * <tr><td>accept <td>Not supported currently.
+ * </table>
+ *
+ * For the different values of \em type, the following resources can be
+ * used:
+ *
+ * <table>
+ * <tr><th>Type <th>Resource
+ * <th>Factory Method
+ * <tr><td>text <td>dw::core::ui::EntryResource
+ * <td>dw::core::ui::ResourceFactory::createEntryResource
+ * <tr><td>password <td>dw::core::ui::EntryResource
+ * <td>dw::core::ui::ResourceFactory::createEntryResource
+ * <tr><td>checkbox <td>dw::core::ui::CheckButtonResource
+ * <td>dw::core::ui::ResourceFactory::createCheckButtonResource
+ * <tr><td>radio <td>dw::core::ui::RadioButtonResource
+ * <td>dw::core::ui::ResourceFactory::createRadioButtonResource
+ * <tr><td>submit <td>dw::core::ui::LabelButtonResource
+ * <td>dw::core::ui::ResourceFactory::createLabelButtonResource
+ * <tr><td>image <td>dw::core::ui::ComplexButtonResource
+ * <td>dw::core::ui::ResourceFactory::createComplexButtonResource,
+ * width a dw::Image inside and relief = false.
+ * <tr><td>reset <td>dw::core::ui::LabelButtonResource
+ * <td>dw::core::ui::ResourceFactory::createLabelButtonResource
+ * <tr><td>button <td>dw::core::ui::LabelButtonResource
+ * <td>dw::core::ui::ResourceFactory::createLabelButtonResource
+ * <tr><td>hidden <td>No rendering necessary.
+ * <td>-
+ * <tr><td>file <td>Not supported currently.
+ * <td>-
+ * </table>
+ *
+ * <h4>\<SELECT\>, \<OPTGROUP\>, and \<OPTION\></h4>
+ *
+ * \<SELECT\> is implemented either by dw::core::ui::OptionMenuResource
+ * (better suitable for \em size = 1 and single selection) or
+ * dw::core::ui::ListResource, which have a common base,
+ * dw::core::ui::SelectionResource. In the latter case, \em size must be
+ * specified via dw::core::style::Style.
+ *
+ * Factory methods are dw::core::ui::ResourceFactory::createListResource and
+ * dw::core::ui::ResourceFactory::createOptionMenuResource.
+ *
+ * \<OPTION\>'s are added via dw::core::ui::SelectionResource::addItem.
+ *
+ * \<OPTGROUP\> are created by using dw::core::ui::SelectionResource::pushGroup
+ * and dw::core::ui::SelectionResource::popGroup.
+ *
+ * For lists, the selection mode must be set in
+ * dw::core::ui::ResourceFactory::createListResource.
+ *
+ * <h4>\<TEXTAREA\></h4>
+ *
+ * \<TEXTAREA\> is implemented by dw::core::ui::MultiLineTextResource,
+ * the factory method is
+ * dw::core::ui::ResourceFactory::createMultiLineTextResource.
+ * dw::core::ui::TextResource::setEditable can be used, as for entries.
+ *
+ * <h4>\<BUTTON\></h4>
+ *
+ * For handling \<BUTTON\>, dw::core::ui::ComplexButtonResource should be used,
+ * with a dw::Textblock inside, and relief = true. The contents of \<BUTTON\>
+ * is then added to the dw::Textblock.
+ *
+ * \todo describe activation signal
+ */
+namespace ui {
+
+class Resource;
+
+/**
+ * \brief A widget for embedding UI widgets.
+ *
+ * \sa dw::core::ui
+ */
+class Embed: public Widget
+{
+ friend class Resource;
+
+private:
+ Resource *resource;
+
+protected:
+ void sizeRequestImpl (Requisition *requisition);
+ void getExtremesImpl (Extremes *extremes);
+ void sizeAllocateImpl (Allocation *allocation);
+
+ int getAvailWidthOfChild (Widget *child, bool forceValue);
+ int getAvailHeightOfChild (Widget *child, bool forceValue);
+ void correctRequisitionOfChild (Widget *child,
+ Requisition *requisition,
+ void (*splitHeightFun) (int, int*, int*));
+ void correctExtremesOfChild (Widget *child, Extremes *extremes);
+
+ void containerSizeChangedForChildren ();
+
+ void enterNotifyImpl (core::EventCrossing *event);
+ void leaveNotifyImpl (core::EventCrossing *event);
+ bool buttonPressImpl (core::EventButton *event);
+
+public:
+ static int CLASS_ID;
+
+ Embed(Resource *resource);
+ ~Embed();
+
+ void setDisplayed (bool displayed);
+ void setEnabled (bool enabled);
+ void draw (View *view, Rectangle *area);
+ Iterator *iterator (Content::Type mask, bool atEnd);
+ void setStyle (style::Style *style);
+
+ inline Resource *getResource () { return resource; }
+
+ inline void correctReqWidthOfChildNoRec (Widget *child,
+ Requisition *requisition)
+ { Widget::correctReqWidthOfChild (child, requisition); }
+
+ inline void correctReqHeightOfChildNoRec (Widget *child,
+ Requisition *requisition,
+ void (*splitHeightFun) (int, int*,
+ int*))
+ { Widget::correctReqHeightOfChild (child, requisition, splitHeightFun); }
+
+ virtual void correctExtremesOfChildNoRec (Widget *child, Extremes *extremes)
+ { Widget::correctExtremesOfChild (child, extremes); }
+};
+
+/**
+ * \brief Basic interface for all resources.
+ *
+ * \sa dw::core::ui
+ */
+class Resource
+{
+ friend class Embed;
+
+public:
+ /**
+ * \brief Receiver interface for the "activate" signal.
+ */
+ class ActivateReceiver: public lout::signal::Receiver
+ {
+ public:
+ virtual void activate (Resource *resource) = 0;
+ virtual void enter (Resource *resource) = 0;
+ virtual void leave (Resource *resource) = 0;
+ };
+ /**
+ * \brief Receiver interface for the "clicked" signal.
+ */
+ class ClickedReceiver: public lout::signal::Receiver
+ {
+ public:
+ virtual void clicked (Resource *resource, EventButton *event) = 0;
+ };
+
+private:
+ class ActivateEmitter: public lout::signal::Emitter
+ {
+ protected:
+ bool emitToReceiver (lout::signal::Receiver *receiver, int signalNo,
+ int argc, Object **argv);
+ public:
+ inline void connectActivate (ActivateReceiver *receiver) {
+ connect (receiver); }
+ void emitActivate (Resource *resource);
+ void emitEnter (Resource *resource);
+ void emitLeave (Resource *resource);
+ };
+
+ class ClickedEmitter: public lout::signal::Emitter
+ {
+ protected:
+ bool emitToReceiver (lout::signal::Receiver *receiver, int signalNo,
+ int argc, Object **argv);
+ public:
+ inline void connectClicked (ClickedReceiver *receiver) {
+ connect (receiver); }
+ void emitClicked (Resource *resource, EventButton *event);
+ };
+
+ Embed *embed;
+ ActivateEmitter activateEmitter;
+ ClickedEmitter clickedEmitter;
+
+ void emitEnter ();
+ void emitLeave ();
+protected:
+ inline void queueResize (bool extremesChanged) {
+ if (embed) embed->queueResize (0, extremesChanged);
+ }
+
+ virtual Embed *getEmbed () { return embed; }
+ virtual void setEmbed (Embed *embed);
+
+ inline void emitActivate () {
+ return activateEmitter.emitActivate (this); }
+ inline void emitClicked (EventButton *event) {
+ clickedEmitter.emitClicked (this, event); }
+
+public:
+ inline Resource ()
+ { embed = NULL; DBG_OBJ_CREATE ("dw::core::ui::Resource"); }
+
+ virtual ~Resource ();
+
+ virtual void sizeRequest (Requisition *requisition) = 0;
+ virtual void getExtremes (Extremes *extremes);
+ virtual void sizeAllocate (Allocation *allocation);
+
+ virtual int getAvailWidthOfChild (Widget *child, bool forceValue);
+ virtual int getAvailHeightOfChild (Widget *child, bool forceValue);
+ virtual void correctRequisitionOfChild (Widget *child,
+ Requisition *requisition,
+ void (*splitHeightFun) (int, int*,
+ int*));
+ virtual void correctExtremesOfChild (Widget *child, Extremes *extremes);
+ virtual void containerSizeChangedForChildren ();
+
+ virtual void setDisplayed (bool displayed);
+ virtual void draw (View *view, Rectangle *area);
+ virtual Iterator *iterator (Content::Type mask, bool atEnd) = 0;
+ virtual void setStyle (style::Style *style);
+
+ virtual bool isEnabled () = 0;
+ virtual void setEnabled (bool enabled) = 0;
+
+ inline void connectActivate (ActivateReceiver *receiver) {
+ activateEmitter.connectActivate (receiver); }
+ inline void connectClicked (ClickedReceiver *receiver) {
+ clickedEmitter.connectClicked (receiver); }
+};
+
+
+class ButtonResource: public Resource
+{};
+
+/**
+ * \brief Interface for labelled buttons resources.
+ */
+class LabelButtonResource: public ButtonResource
+{
+public:
+ Iterator *iterator (Content::Type mask, bool atEnd);
+
+ virtual const char *getLabel () = 0;
+ virtual void setLabel (const char *label) = 0;
+};
+
+class ComplexButtonResource: public ButtonResource
+{
+private:
+ class LayoutReceiver: public Layout::Receiver
+ {
+ public:
+ ComplexButtonResource *resource;
+
+ void resizeQueued (bool extremesChanged);
+ };
+
+ friend class LayoutReceiver;
+ LayoutReceiver layoutReceiver;
+
+ Widget *childWidget;
+
+protected:
+ Layout *layout;
+ int click_x, click_y;
+
+ void setEmbed (Embed *embed);
+
+ virtual Platform *createPlatform () = 0;
+ virtual void setLayout (Layout *layout) = 0;
+
+ virtual int reliefXThickness () = 0;
+ virtual int reliefYThickness () = 0;
+
+ void init (Widget *widget);
+
+public:
+ ComplexButtonResource ();
+ ~ComplexButtonResource ();
+
+ void sizeRequest (Requisition *requisition);
+ void getExtremes (Extremes *extremes);
+ void sizeAllocate (Allocation *allocation);
+
+ int getAvailWidthOfChild (Widget *child, bool forceValue);
+ int getAvailHeightOfChild (Widget *child, bool forceValue);
+ void correctRequisitionOfChild (Widget *child,
+ Requisition *requisition,
+ void (*splitHeightFun) (int, int*, int*));
+ void correctExtremesOfChild (Widget *child, Extremes *extremes);
+ void containerSizeChangedForChildren ();
+
+ Iterator *iterator (Content::Type mask, bool atEnd);
+ int getClickX () {return click_x;};
+ int getClickY () {return click_y;};
+};
+
+/**
+ * \brief Base interface for dw::core::ui::ListResource and
+ * dw::core::ui::OptionMenuResource.
+ */
+class SelectionResource: public Resource
+{
+public:
+ virtual void addItem (const char *str, bool enabled, bool selected) = 0;
+ virtual void setItem (int index, bool selected) = 0;
+ virtual void pushGroup (const char *name, bool enabled) = 0;
+ virtual void popGroup () = 0;
+
+ virtual int getNumberOfItems () = 0;
+ virtual bool isSelected (int index) = 0;
+};
+
+class ListResource: public SelectionResource
+{
+public:
+ enum SelectionMode {
+ /**
+ * \brief Exactly one item is selected.
+ *
+ * If no item is selected initially, the first one is selected.
+ */
+ SELECTION_EXACTLY_ONE,
+
+ /**
+ * \brief Exactly one item is selected, except possibly at the beginning.
+ *
+ * If no item is selected initially, no one is selected automatically.
+ * The user may not unselect the only selected item.
+ */
+ SELECTION_EXACTLY_ONE_BY_USER,
+
+ /**
+ * \brief At most one item is selected.
+ *
+ * If no item is selected initially, no one is selected automatically.
+ * The user may unselect the only selected item.
+ */
+ SELECTION_AT_MOST_ONE,
+
+ /**
+ * \brief An arbitrary number of items may be selected.
+ */
+ SELECTION_MULTIPLE
+ };
+};
+
+class OptionMenuResource: public SelectionResource
+{
+};
+
+class TextResource: public Resource
+{
+public:
+ Iterator *iterator (Content::Type mask, bool atEnd);
+
+ virtual const char *getText () = 0;
+ virtual void setText (const char *text) = 0;
+ virtual bool isEditable () = 0;
+ virtual void setEditable (bool editable) = 0;
+};
+
+class EntryResource: public TextResource
+{
+public:
+ enum { UNLIMITED_SIZE = -1 };
+ virtual void setMaxLength (int maxlen) = 0;
+};
+
+class MultiLineTextResource: public TextResource
+{
+};
+
+
+class ToggleButtonResource: public Resource
+{
+public:
+ virtual bool isActivated () = 0;
+ virtual void setActivated (bool activated) = 0;
+};
+
+class CheckButtonResource: public ToggleButtonResource
+{
+public:
+ Iterator *iterator (Content::Type mask, bool atEnd);
+};
+
+class RadioButtonResource: public ToggleButtonResource
+{
+public:
+ class GroupIterator
+ {
+ protected:
+ GroupIterator () { }
+ virtual ~GroupIterator ();
+
+ public:
+ virtual bool hasNext () = 0;
+ virtual RadioButtonResource *getNext () = 0;
+ virtual void unref () = 0;
+ };
+
+ /**
+ * \brief Return an iterator, to access all radio button resources
+ * within the group.
+ */
+ virtual GroupIterator *groupIterator () = 0;
+
+ Iterator *iterator (Content::Type mask, bool atEnd);
+};
+
+
+/**
+ * \brief A factory for the common resource.
+ */
+class ResourceFactory: public lout::object::Object
+{
+public:
+ virtual LabelButtonResource *createLabelButtonResource (const char *label)
+ = 0;
+ virtual ComplexButtonResource *createComplexButtonResource (Widget *widget,
+ bool relief)
+ = 0;
+ virtual ListResource *createListResource (ListResource::SelectionMode
+ selectionMode, int rows) = 0;
+ virtual OptionMenuResource *createOptionMenuResource () = 0;
+ virtual EntryResource *createEntryResource (int size, bool password,
+ const char *label) = 0;
+ virtual MultiLineTextResource *createMultiLineTextResource (int cols,
+ int rows) = 0;
+ virtual CheckButtonResource *createCheckButtonResource (bool activated) = 0;
+ virtual RadioButtonResource *createRadioButtonResource (RadioButtonResource
+ *groupedWith,
+ bool activated) = 0;
+};
+
+} // namespace ui
+} // namespace core
+} // namespace dw
+
+#endif // __DW_UI_HH__
diff --git a/dw/view.hh b/dw/view.hh
new file mode 100644
index 0000000..8037dc6
--- /dev/null
+++ b/dw/view.hh
@@ -0,0 +1,211 @@
+#ifndef __DW_VIEW_HH__
+#define __DW_VIEW_HH__
+
+#ifndef __INCLUDED_FROM_DW_CORE_HH__
+# error Do not include this file directly, use "core.hh" instead.
+#endif
+
+namespace dw {
+namespace core {
+
+/**
+ * \brief An interface to encapsulate platform dependent drawing.
+ *
+ * \sa\ref dw-overview, \ref dw-layout-views
+ */
+class View: public lout::object::Object
+{
+public:
+ /*
+ * ----------------------------
+ * Operations on the view
+ * ----------------------------
+ */
+
+ /**
+ * \brief This methods notifies the view, that it has been attached to a
+ * layout.
+ */
+ virtual void setLayout (Layout *layout) = 0;
+
+ /**
+ * \brief Set the canvas size.
+ */
+ virtual void setCanvasSize (int width, int ascent, int descent) = 0;
+
+ /**
+ * \brief Set the cursor appearance.
+ */
+ virtual void setCursor (style::Cursor cursor) = 0;
+
+ /**
+ * \brief Set the background of the view.
+ */
+ virtual void setBgColor (style::Color *color) = 0;
+
+ /*
+ * ---------------------------------------------------------
+ * Scrolling and Related. Only usesViewport must be
+ * implemented, if it returns false, the other methods
+ * are never called.
+ * -------------------------------------------------------
+ */
+
+ /**
+ * \brief Return, whether this view uses a viewport.
+ */
+ virtual bool usesViewport () = 0;
+
+ /**
+ * \brief Get the thickness of the horizontal scrollbar, when it is
+ * visible.
+ *
+ * Does not have to be implemented, when usesViewport returns false.
+ */
+ virtual int getHScrollbarThickness () = 0;
+
+ /**
+ * \brief Get the thickness of the vertical scrollbar, when it is
+ * visible.
+ *
+ * Does not have to be implemented, when usesViewport returns false.
+ */
+ virtual int getVScrollbarThickness () = 0;
+
+ /**
+ * \brief Scroll the vieport to the given position.
+ *
+ * Does not have to be implemented, when usesViewport returns false.
+ */
+ virtual void scrollTo (int x, int y) = 0;
+
+ /**
+ * \brief Scroll the viewport as commanded.
+ */
+ virtual void scroll (ScrollCommand) { };
+
+ /**
+ * \brief Set the viewport size.
+ *
+ * Does not have to be implemented, when usesViewport returns false.
+ *
+ * This will normally imply a resize of the UI widget. Width and height are
+ * the dimensions of the new size, \em including the scrollbar thicknesses.
+ *
+ */
+ virtual void setViewportSize (int width, int height,
+ int hScrollbarThickness,
+ int vScrollbarThickness) = 0;
+
+ /*
+ * -----------------------
+ * Drawing functions
+ * -----------------------
+ */
+
+ /**
+ * \brief Called before drawing.
+ *
+ * All actual drawing operations will be enclosed into calls of
+ * dw::core:View::startDrawing and dw::core:View::finishDrawing. They
+ * may be implemented, e.g. when a backing
+ * pixmap is used, to prevent flickering. StartDrawing() will then
+ * initialize the backing pixmap, all other drawing operations will draw
+ * into it, and finishDrawing() will merge it into the window.
+ */
+ virtual void startDrawing (Rectangle *area) = 0;
+
+ /**
+ * \brief Called after drawing.
+ *
+ * \sa dw::core:View::startDrawing
+ */
+ virtual void finishDrawing (Rectangle *area) = 0;
+
+ /**
+ * \brief Queue a region, which is given in \em canvas coordinates, for
+ * drawing.
+ *
+ * The view implementation is responsible, that this region is drawn, either
+ * immediately, or (which is more typical, since more efficient) the areas
+ * are collected, combined (as far as possible), and the drawing is later
+ * done in an idle function.
+ */
+ virtual void queueDraw (Rectangle *area) = 0;
+
+ /**
+ * \brief Queue the total viewport for drawing.
+ *
+ * \sa dw::core::View::queueDraw
+ */
+ virtual void queueDrawTotal () = 0;
+
+ /**
+ * \brief Cancel a draw queue request.
+ *
+ * If dw::core::View::queueDraw or dw::core::View::queueDrawTotal have been
+ * called before, and the actual drawing was not processed yet, the actual
+ * drawing should be cancelled. Otherwise, the cancellation should be
+ * ignored.
+ */
+ virtual void cancelQueueDraw () = 0;
+
+ /*
+ * The following methods should be self-explaining.
+ */
+
+ virtual void drawPoint (style::Color *color,
+ style::Color::Shading shading,
+ int x, int y) = 0;
+ virtual void drawLine (style::Color *color,
+ style::Color::Shading shading,
+ int x1, int y1, int x2, int y2) = 0;
+ virtual void drawTypedLine (style::Color *color,
+ style::Color::Shading shading,
+ style::LineType type, int width,
+ int x1, int y1, int x2, int y2) = 0;
+ virtual void drawRectangle (style::Color *color,
+ style::Color::Shading shading, bool filled,
+ int x, int y, int width, int height) = 0;
+ virtual void drawArc (style::Color *color,
+ style::Color::Shading shading, bool filled,
+ int centerX, int centerY, int width, int height,
+ int angle1, int angle2) = 0;
+ virtual void drawPolygon (style::Color *color,
+ style::Color::Shading shading,
+ bool filled, bool convex, Point *points,
+ int npoints) = 0;
+ virtual void drawText (style::Font *font,
+ style::Color *color,
+ style::Color::Shading shading,
+ int x, int y, const char *text, int len) = 0;
+ virtual void drawSimpleWrappedText (style::Font *font, style::Color *color,
+ style::Color::Shading shading,
+ int x, int y, int w, int h,
+ const char *text) = 0;
+ virtual void drawImage (Imgbuf *imgbuf, int xRoot, int yRoot,
+ int x, int y, int width, int height) = 0;
+
+ /*
+ * --------------
+ * Clipping
+ * --------------
+ */
+
+ /*
+ * To prevent drawing outside of a given area, a clipping view may be
+ * requested, which also implements this interface. The clipping view is
+ * related to the parent view (clipping views may be nested!), anything
+ * which is drawn into this clipping view, is later merged again into the
+ * parent view. An implementation will typically use additional pixmaps,
+ * which are later merged into the parent view pixmap/window.
+ */
+
+ virtual View *getClippingView (int x, int y, int width, int height) = 0;
+ virtual void mergeClippingView (View *clippingView) = 0;
+};
+
+} // namespace core
+} // namespace dw
+
+#endif // __DW_VIEW_HH__
diff --git a/dw/widget.cc b/dw/widget.cc
new file mode 100644
index 0000000..4ebce30
--- /dev/null
+++ b/dw/widget.cc
@@ -0,0 +1,1785 @@
+/*
+ * RTFL (originally part of dillo)
+ *
+ * Copyright 2005-2007 Sebastian Geerken <sgeerken@dillo.org>
+ *
+ * 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; with the following exception:
+ *
+ * The copyright holders of RTFL give you permission to link this file
+ * statically or dynamically against all versions of the graphviz
+ * library, which are published by AT&T Corp. under one of the following
+ * licenses:
+ *
+ * - Common Public License version 1.0 as published by International
+ * Business Machines Corporation (IBM), or
+ * - Eclipse Public License version 1.0 as published by the Eclipse
+ * Foundation.
+ *
+ * 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/>.
+ */
+
+#include "core.hh"
+
+#include "../lout/msg.h"
+#include "../lout/debug.hh"
+
+using namespace lout;
+using namespace lout::object;
+
+namespace dw {
+namespace core {
+
+// ----------------------------------------------------------------------
+
+bool Widget::WidgetImgRenderer::readyToDraw ()
+{
+ return widget->wasAllocated ();
+}
+
+void Widget::WidgetImgRenderer::getBgArea (int *x, int *y, int *width,
+ int *height)
+{
+ widget->getPaddingArea (x, y, width, height);
+}
+
+void Widget::WidgetImgRenderer::getRefArea (int *xRef, int *yRef, int *widthRef,
+ int *heightRef)
+{
+ widget->getPaddingArea (xRef, yRef, widthRef, heightRef);
+}
+
+style::Style *Widget::WidgetImgRenderer::getStyle ()
+{
+ return widget->getStyle ();
+}
+
+void Widget::WidgetImgRenderer::draw (int x, int y, int width, int height)
+{
+ widget->queueDrawArea (x - widget->allocation.x, y - widget->allocation.y,
+ width, height);
+}
+
+// ----------------------------------------------------------------------
+
+bool Widget::adjustMinWidth = false;
+int Widget::CLASS_ID = -1;
+
+Widget::Widget ()
+{
+ DBG_OBJ_CREATE ("dw::core::Widget");
+ registerName ("dw::core::Widget", &CLASS_ID);
+
+ flags = (Flags)(NEEDS_RESIZE | EXTREMES_CHANGED);
+ parent = quasiParent = generator = container = NULL;
+ DBG_OBJ_SET_PTR ("container", container);
+
+ layout = NULL;
+
+ allocation.x = -1;
+ allocation.y = -1;
+ allocation.width = 1;
+ allocation.ascent = 1;
+ allocation.descent = 0;
+
+ extraSpace.top = extraSpace.right = extraSpace.bottom = extraSpace.left = 0;
+
+ style = NULL;
+ bgColor = NULL;
+ buttonSensitive = true;
+ buttonSensitiveSet = false;
+
+ deleteCallbackData = NULL;
+ deleteCallbackFunc = NULL;
+
+ widgetImgRenderer = NULL;
+}
+
+Widget::~Widget ()
+{
+ if (deleteCallbackFunc)
+ deleteCallbackFunc (deleteCallbackData);
+
+ if (widgetImgRenderer) {
+ if (style && style->backgroundImage)
+ style->backgroundImage->removeExternalImgRenderer (widgetImgRenderer);
+ delete widgetImgRenderer;
+ }
+
+ if (style)
+ style->unref ();
+
+ if (parent)
+ parent->removeChild (this);
+ else if (layout)
+ layout->removeWidget ();
+
+ DBG_OBJ_DELETE ();
+}
+
+
+/**
+ * \brief Calculates the intersection of widget->allocation and area, returned
+ * in intersection (in widget coordinates!).
+ *
+ * Typically used by containers when
+ * drawing their children. Returns whether intersection is not empty.
+ */
+bool Widget::intersects (Rectangle *area, Rectangle *intersection)
+{
+ Rectangle parentArea, childArea;
+
+ parentArea = *area;
+ parentArea.x += parent->allocation.x;
+ parentArea.y += parent->allocation.y;
+
+ childArea.x = allocation.x;
+ childArea.y = allocation.y;
+ childArea.width = allocation.width;
+ childArea.height = getHeight ();
+
+ if (parentArea.intersectsWith (&childArea, intersection)) {
+ intersection->x -= allocation.x;
+ intersection->y -= allocation.y;
+ return true;
+ } else
+ return false;
+}
+
+void Widget::setParent (Widget *parent)
+{
+ this->parent = parent;
+ layout = parent->layout;
+
+ if (!buttonSensitiveSet)
+ buttonSensitive = parent->buttonSensitive;
+
+ DBG_OBJ_ASSOC_PARENT (parent);
+ //printf ("The %s %p becomes a child of the %s %p\n",
+ // getClassName(), this, parent->getClassName(), parent);
+
+ // Determine the container. Currently rather simple; will become
+ // more complicated when absolute and fixed positions are
+ // supported.
+ container = NULL;
+ for (Widget *widget = getParent (); widget != NULL && container == NULL;
+ widget = widget->getParent())
+ if (widget->isPossibleContainer ())
+ container = widget;
+ // If there is no possible container widget, there is
+ // (surprisingly!) also no container (i. e. the viewport is
+ // used). Does not occur in dillo, where the toplevel widget is a
+ // Textblock.
+ DBG_OBJ_SET_PTR ("container", container);
+
+ notifySetParent();
+}
+
+void Widget::setQuasiParent (Widget *quasiParent)
+{
+ this->quasiParent = quasiParent;
+
+ // More to do? Compare with setParent().
+
+ DBG_OBJ_SET_PTR ("quasiParent", quasiParent);
+}
+
+void Widget::queueDrawArea (int x, int y, int width, int height)
+{
+ /** \todo Maybe only the intersection? */
+
+ DBG_OBJ_ENTER ("draw", 0, "queueDrawArea", "%d, %d, %d, %d",
+ x, y, width, height);
+
+ _MSG("Widget::queueDrawArea alloc(%d %d %d %d) wid(%d %d %d %d)\n",
+ allocation.x, allocation.y,
+ allocation.width, allocation.ascent + allocation.descent,
+ x, y, width, height);
+ if (layout)
+ layout->queueDraw (x + allocation.x, y + allocation.y, width, height);
+
+ DBG_OBJ_LEAVE ();
+}
+
+/**
+ * \brief This method should be called, when a widget changes its size.
+ *
+ * A "fast" queueResize will ignore the anchestors, and furthermore
+ * not trigger the idle function. Used only within
+ * viewportSizeChanged, and not available outside Layout and Widget.
+ */
+void Widget::queueResize (int ref, bool extremesChanged, bool fast)
+{
+ DBG_OBJ_ENTER ("resize", 0, "queueResize", "%d, %s, %s",
+ ref, extremesChanged ? "true" : "false",
+ fast ? "true" : "false");
+
+ // queueResize() can be called recursively; calls are queued, so
+ // that actualQueueResize() is clean.
+
+ if (queueResizeEntered ()) {
+ DBG_OBJ_MSG ("resize", 1, "put into queue");
+ layout->queueQueueResizeList->pushUnder (new Layout::QueueResizeItem
+ (this, ref, extremesChanged,
+ fast));
+ } else {
+ actualQueueResize (ref, extremesChanged, fast);
+
+ DBG_IF_RTFL {
+ if (layout == NULL)
+ DBG_OBJ_MSG ("resize", 1, "layout is not set");
+ else if (layout->queueQueueResizeList->size () == 0)
+ DBG_OBJ_MSG ("resize", 1, "queue item list is empty");
+ }
+
+ while (layout != NULL && layout->queueQueueResizeList->size () > 0) {
+ DBG_IF_RTFL {
+ DBG_OBJ_MSGF ("resize", 1, "queue item list has %d elements:",
+ layout->queueQueueResizeList->size ());
+#if 0
+ // TODO This worked when queueQueueResizeList was a Vector; now,
+ // iterators should be used.
+ DBG_OBJ_MSG_START ();
+ for (int i = 0; i < layout->queueQueueResizeList->size (); i++) {
+ DBG_OBJ_MSGF
+ ("resize", 1,
+ "#%d: widget = %p, ref = %d, extremesChanged = %s, "
+ "fast = %s",
+ i, layout->queueQueueResizeList->get(i)->widget,
+ layout->queueQueueResizeList->get(i)->ref,
+ layout->queueQueueResizeList->get(i)->extremesChanged ?
+ "true" : "false",
+ layout->queueQueueResizeList->get(i)->fast ?
+ "true" : "false");
+ }
+ DBG_OBJ_MSG_END ();
+ DBG_OBJ_MSG ("resize", 1, "taking #0 out of list");
+#endif
+ }
+
+ Layout::QueueResizeItem *item =
+ layout->queueQueueResizeList->getTop ();
+ item->widget->actualQueueResize (item->ref, item->extremesChanged,
+ item->fast);
+ layout->queueQueueResizeList->pop ();
+ }
+ }
+
+ DBG_OBJ_LEAVE ();
+}
+
+void Widget::actualQueueResize (int ref, bool extremesChanged, bool fast)
+{
+ assert (!queueResizeEntered ());
+
+ DBG_OBJ_ENTER ("resize", 0, "actualQueueResize", "%d, %s, %s",
+ ref, extremesChanged ? "true" : "false",
+ fast ? "true" : "false");
+
+ enterQueueResize ();
+
+ Widget *widget2, *child;
+
+ Flags resizeFlag, extremesFlag;
+
+ if (layout) {
+ // If RESIZE_QUEUED is set, this widget is already in the list.
+ if (!resizeQueued ())
+ layout->queueResizeList->put (this);
+
+ resizeFlag = RESIZE_QUEUED;
+ extremesFlag = EXTREMES_QUEUED;
+ } else {
+ resizeFlag = NEEDS_RESIZE;
+ extremesFlag = EXTREMES_CHANGED;
+ }
+
+ setFlags (resizeFlag);
+ setFlags (ALLOCATE_QUEUED);
+ markSizeChange (ref);
+
+ if (extremesChanged) {
+ setFlags (extremesFlag);
+ markExtremesChange (ref);
+ }
+
+ if (fast) {
+ if (parent) {
+ // In this case, queueResize is called from top (may be a
+ // random entry point) to bottom, so markSizeChange and
+ // markExtremesChange have to be called explicitly for the
+ // parent. The tests (needsResize etc.) are uses to check
+ // whether queueResize has been called for the parent, or
+ // whether this widget is the enty point.
+ if (parent->needsResize () || parent->resizeQueued ())
+ parent->markSizeChange (parentRef);
+ if (parent->extremesChanged () || parent->extremesQueued ())
+ parent->markExtremesChange (parentRef);
+ }
+ } else {
+ for (widget2 = parent, child = this; widget2;
+ child = widget2, widget2 = widget2->parent) {
+ if (layout && !widget2->resizeQueued ())
+ layout->queueResizeList->put (widget2);
+
+ DBG_OBJ_MSGF ("resize", 2, "setting %s and ALLOCATE_QUEUED for %p",
+ resizeFlag == RESIZE_QUEUED ?
+ "RESIZE_QUEUED" : "NEEDS_RESIZE",
+ widget2);
+
+ widget2->setFlags (resizeFlag);
+ widget2->markSizeChange (child->parentRef);
+ widget2->setFlags (ALLOCATE_QUEUED);
+
+ if (extremesChanged) {
+ widget2->setFlags (extremesFlag);
+ widget2->markExtremesChange (child->parentRef);
+ }
+ }
+
+ if (layout)
+ layout->queueResize (extremesChanged);
+ }
+
+ leaveQueueResize ();
+
+ DBG_OBJ_LEAVE ();
+}
+
+void Widget::containerSizeChanged ()
+{
+ DBG_OBJ_ENTER0 ("resize", 0, "containerSizeChanged");
+
+ // If there is a container widget (not the viewport), which has not
+ // changed its size (which can be determined by the respective
+ // flags: this method is called recursively), this widget will
+ // neither change its size. Also, the recursive iteration can be
+ // stopped, since the children of this widget will
+ if (container == NULL ||
+ container->needsResize () || container->resizeQueued () ||
+ container->extremesChanged () || container->extremesQueued ()) {
+ // Viewport (container == NULL) or container widget has changed
+ // its size.
+ if (affectedByContainerSizeChange ())
+ queueResizeFast (0, true);
+
+ // Even if *this* widget is not affected, children may be, so
+ // iterate over children.
+ containerSizeChangedForChildren ();
+ }
+
+ DBG_OBJ_LEAVE ();
+}
+
+bool Widget::affectedByContainerSizeChange ()
+{
+ DBG_OBJ_ENTER0 ("resize", 0, "affectedByContainerSizeChange");
+
+ bool ret;
+
+ // This standard implementation is suitable for all widgets which
+ // call correctRequisition() and correctExtremes(), even in the way
+ // how Textblock and Image do (see comments there). Has to be kept
+ // in sync.
+
+ if (container == NULL) {
+ if (style::isAbsLength (getStyle()->width) &&
+ style::isAbsLength (getStyle()->height))
+ // Both absolute, i. e. fixed: no dependency.
+ ret = false;
+ else if (style::isPerLength (getStyle()->width) ||
+ style::isPerLength (getStyle()->height)) {
+ // Any percentage: certainly dependenant.
+ ret = true;
+ } else
+ // One or both is "auto": depends ...
+ ret =
+ (getStyle()->width == style::LENGTH_AUTO ?
+ usesAvailWidth () : false) ||
+ (getStyle()->height == style::LENGTH_AUTO ?
+ usesAvailHeight () : false);
+ } else
+ ret = container->affectsSizeChangeContainerChild (this);
+
+ DBG_OBJ_MSGF ("resize", 1, "=> %s", ret ? "true" : "false");
+ DBG_OBJ_LEAVE ();
+ return ret;
+}
+
+bool Widget::affectsSizeChangeContainerChild (Widget *child)
+{
+ DBG_OBJ_ENTER ("resize", 0, "affectsSizeChangeContainerChild", "%p", child);
+
+ bool ret;
+
+ // From the point of view of the container. This standard
+ // implementation should be suitable for most (if not all)
+ // containers.
+
+ if (style::isAbsLength (child->getStyle()->width) &&
+ style::isAbsLength (child->getStyle()->height))
+ // Both absolute, i. e. fixed: no dependency.
+ ret = false;
+ else if (style::isPerLength (child->getStyle()->width) ||
+ style::isPerLength (child->getStyle()->height)) {
+ // Any percentage: certainly dependenant.
+ ret = true;
+ } else
+ // One or both is "auto": depends ...
+ ret =
+ (child->getStyle()->width == style::LENGTH_AUTO ?
+ child->usesAvailWidth () : false) ||
+ (child->getStyle()->height == style::LENGTH_AUTO ?
+ child->usesAvailHeight () : false);
+
+ DBG_OBJ_MSGF ("resize", 1, "=> %s", ret ? "true" : "false");
+ DBG_OBJ_LEAVE ();
+ return ret;
+}
+
+void Widget::containerSizeChangedForChildren ()
+{
+ DBG_OBJ_ENTER0 ("resize", 0, "containerSizeChangedForChildren");
+
+ // Working, but inefficient standard implementation.
+ Iterator *it = iterator ((Content::Type)(Content::WIDGET_IN_FLOW |
+ Content::WIDGET_OOF_CONT),
+ false);
+ while (it->next ())
+ it->getContent()->widget->containerSizeChanged ();
+ it->unref ();
+
+ DBG_OBJ_LEAVE ();
+}
+
+/**
+ * \brief Must be implemengted by a method returning true, when
+ * getAvailWidth() is called.
+ */
+bool Widget::usesAvailWidth ()
+{
+ return false;
+}
+
+/**
+ * \brief Must be implemengted by a method returning true, when
+ * getAvailHeight() is called.
+ */
+bool Widget::usesAvailHeight ()
+{
+ return false;
+}
+
+/**
+ * \brief This method is a wrapper for Widget::sizeRequestImpl(); it calls
+ * the latter only when needed.
+ */
+void Widget::sizeRequest (Requisition *requisition)
+{
+ assert (!queueResizeEntered ());
+
+ DBG_OBJ_ENTER0 ("resize", 0, "sizeRequest");
+
+ enterSizeRequest ();
+
+ //printf ("The %stop-level %s %p with parentRef = %d: needsResize: %s, "
+ // "resizeQueued = %s\n",
+ // parent ? "non-" : "", getClassName(), this, parentRef,
+ // needsResize () ? "true" : "false",
+ // resizeQueued () ? "true" : "false");
+
+ if (resizeQueued ()) {
+ // This method is called outside of Layout::resizeIdle.
+ setFlags (NEEDS_RESIZE);
+ unsetFlags (RESIZE_QUEUED);
+ // The widget is not taken out of Layout::queueResizeList, since
+ // other *_QUEUED flags may still be set and processed in
+ // Layout::resizeIdle.
+ }
+
+ if (needsResize ()) {
+ /** \todo Check requisition == &(this->requisition) and do what? */
+ sizeRequestImpl (requisition);
+ this->requisition = *requisition;
+ unsetFlags (NEEDS_RESIZE);
+
+ DBG_OBJ_SET_NUM ("requisition.width", requisition->width);
+ DBG_OBJ_SET_NUM ("requisition.ascent", requisition->ascent);
+ DBG_OBJ_SET_NUM ("requisition.descent", requisition->descent);
+ } else
+ *requisition = this->requisition;
+
+ //printf (" ==> Result: %d x (%d + %d)\n",
+ // requisition->width, requisition->ascent, requisition->descent);
+
+ leaveSizeRequest ();
+
+ DBG_OBJ_LEAVE ();
+}
+
+/**
+ * \brief Used to evaluate Widget::adjustMinWidth.
+ *
+ * If extremes == NULL, getExtremes is called. ForceValue is the same
+ * value passed to getAvailWidth etc.; if false, getExtremes is not
+ * called.
+ */
+int Widget::getMinWidth (Extremes *extremes, bool forceValue)
+{
+ DBG_OBJ_ENTER ("resize", 0, "getMinWidth", "..., %s",
+ forceValue ? "true" : "false");
+ int minWidth;
+
+ if (getAdjustMinWidth ()) {
+ Extremes extremes2;
+ if (extremes == NULL) {
+ if (forceValue) {
+ getExtremes (&extremes2);
+ extremes = &extremes2;
+ }
+ }
+
+ // TODO Not completely clear whether this is feasable: Within
+ // the context of getAvailWidth(false) etc., getExtremes may not
+ // be called. We ignore the minimal width then.
+ minWidth = extremes ? extremes->minWidthIntrinsic : 0;
+ } else
+ minWidth = 0;
+
+ DBG_OBJ_MSGF ("resize", 1, "=> %d", minWidth);
+ DBG_OBJ_LEAVE ();
+
+ return minWidth;
+}
+
+/**
+ * Return available width including margin/border/padding
+ * (extraSpace?), not only the content width.
+ */
+int Widget::getAvailWidth (bool forceValue)
+{
+ DBG_OBJ_ENTER ("resize", 0, "getAvailWidth", "%s",
+ forceValue ? "true" : "false");
+
+ int width;
+
+ if (parent == NULL && quasiParent == NULL) {
+ DBG_OBJ_MSG ("resize", 1, "no parent, regarding viewport");
+ DBG_OBJ_MSG_START ();
+
+ // TODO Consider nested layouts (e. g. <button>).
+
+ int viewportWidth =
+ layout->viewportWidth - (layout->canvasHeightGreater ?
+ layout->vScrollbarThickness : 0);
+ width = -1;
+ calcFinalWidth (getStyle (), viewportWidth, NULL, 0, forceValue, &width);
+ if (width == -1)
+ width = viewportWidth;
+
+ DBG_OBJ_MSG_END ();
+ } else if (parent) {
+ DBG_OBJ_MSG ("resize", 1, "delegated to parent");
+ DBG_OBJ_MSG_START ();
+ width = parent->getAvailWidthOfChild (this, forceValue);
+ DBG_OBJ_MSG_END ();
+ } else /* if (quasiParent) */ {
+ DBG_OBJ_MSG ("resize", 1, "delegated to quasiParent");
+ DBG_OBJ_MSG_START ();
+ width = quasiParent->getAvailWidthOfChild (this, forceValue);
+ DBG_OBJ_MSG_END ();
+ }
+
+ DBG_OBJ_MSGF ("resize", 1, "=> %d", width);
+ DBG_OBJ_LEAVE ();
+
+ return width;
+}
+
+/**
+ * Return available height including margin/border/padding
+ * (extraSpace?), not only the content height.
+ */
+int Widget::getAvailHeight (bool forceValue)
+{
+ // TODO Correct by ... not extremes, but ...? (Height extremes?)
+
+ // TODO Consider 'min-height' and 'max-height'. (Minor priority, as long as
+ // "getAvailHeight (true)" is not used.
+
+ DBG_OBJ_ENTER ("resize", 0, "getAvailHeight", "%s",
+ forceValue ? "true" : "false");
+
+ int height;
+
+ if (parent == NULL && quasiParent == NULL) {
+ DBG_OBJ_MSG ("resize", 1, "no parent, regarding viewport");
+ DBG_OBJ_MSG_START ();
+
+ // TODO Consider nested layouts (e. g. <button>).
+ if (style::isAbsLength (getStyle()->height)) {
+ DBG_OBJ_MSGF ("resize", 1, "absolute height: %dpx",
+ style::absLengthVal (getStyle()->height));
+ height = style::absLengthVal (getStyle()->height) + boxDiffHeight ();
+ } else if (style::isPerLength (getStyle()->height)) {
+ DBG_OBJ_MSGF ("resize", 1, "percentage height: %g%%",
+ 100 * style::perLengthVal_useThisOnlyForDebugging
+ (getStyle()->height));
+ // Notice that here -- unlike getAvailWidth() --
+ // layout->hScrollbarThickness is not considered here;
+ // something like canvasWidthGreater (analogue to
+ // canvasHeightGreater) would be complicated and lead to
+ // possibly contradictory self-references.
+ height = applyPerHeight (layout->viewportHeight, getStyle()->height);
+ } else {
+ DBG_OBJ_MSG ("resize", 1, "no specification");
+ height = layout->viewportHeight;
+ }
+
+ DBG_OBJ_MSG_END ();
+ } else if (parent) {
+ DBG_OBJ_MSG ("resize", 1, "delegated to parent");
+ DBG_OBJ_MSG_START ();
+ height = parent->getAvailHeightOfChild (this, forceValue);
+ DBG_OBJ_MSG_END ();
+ } else /* if (quasiParent) */ {
+ DBG_OBJ_MSG ("resize", 1, "delegated to quasiParent");
+ DBG_OBJ_MSG_START ();
+ height = quasiParent->getAvailHeightOfChild (this, forceValue);
+ DBG_OBJ_MSG_END ();
+ }
+
+ DBG_OBJ_MSGF ("resize", 1, "=> %d", height);
+ DBG_OBJ_LEAVE ();
+
+ return height;
+}
+
+void Widget::correctRequisition (Requisition *requisition,
+ void (*splitHeightFun) (int, int *, int *))
+{
+ // TODO Correct height by ... not extremes, but ...? (Height extremes?)
+
+ DBG_OBJ_ENTER ("resize", 0, "correctRequisition", "%d * (%d + %d), ...",
+ requisition->width, requisition->ascent,
+ requisition->descent);
+
+ if (parent == NULL && quasiParent == NULL) {
+ DBG_OBJ_MSG ("resize", 1, "no parent, regarding viewport");
+ DBG_OBJ_MSG_START ();
+
+ int limitMinWidth = getMinWidth (NULL, true);
+ int viewportWidth =
+ layout->viewportWidth - (layout->canvasHeightGreater ?
+ layout->vScrollbarThickness : 0);
+ calcFinalWidth (getStyle (), viewportWidth, NULL, limitMinWidth, false,
+ &requisition->width);
+
+ // For layout->viewportHeight, see comment in getAvailHeight().
+ int height = calcHeight (getStyle()->height, false,
+ layout->viewportHeight, NULL, false);
+ int minHeight = calcHeight (getStyle()->minHeight, false,
+ layout->viewportHeight, NULL, false);
+ int maxHeight = calcHeight (getStyle()->maxHeight, false,
+ layout->viewportHeight, NULL, false);
+
+ // TODO Perhaps split first, then add box ascent and descent.
+ if (height != -1)
+ splitHeightFun (height, &requisition->ascent, &requisition->descent);
+ if (minHeight != -1 &&
+ requisition->ascent + requisition->descent < minHeight)
+ splitHeightFun (minHeight, &requisition->ascent,
+ &requisition->descent);
+ if (maxHeight != -1 &&
+ requisition->ascent + requisition->descent > maxHeight)
+ splitHeightFun (maxHeight, &requisition->ascent,
+ &requisition->descent);
+
+ DBG_OBJ_MSG_END ();
+ } else if (parent) {
+ DBG_OBJ_MSG ("resize", 1, "delegated to parent");
+ DBG_OBJ_MSG_START ();
+ parent->correctRequisitionOfChild (this, requisition, splitHeightFun);
+ DBG_OBJ_MSG_END ();
+ } else /* if (quasiParent) */ {
+ DBG_OBJ_MSG ("resize", 1, "delegated to quasiParent");
+ DBG_OBJ_MSG_START ();
+ quasiParent->correctRequisitionOfChild (this, requisition,
+ splitHeightFun);
+ DBG_OBJ_MSG_END ();
+ }
+
+ DBG_OBJ_MSGF ("resize", 1, "=> %d * (%d + %d)",
+ requisition->width, requisition->ascent,
+ requisition->descent);
+ DBG_OBJ_LEAVE ();
+}
+
+void Widget::correctExtremes (Extremes *extremes)
+{
+ DBG_OBJ_ENTER ("resize", 0, "correctExtremes", "%d (%d) / %d (%d)",
+ extremes->minWidth, extremes->minWidthIntrinsic,
+ extremes->maxWidth, extremes->maxWidthIntrinsic);
+
+ if (container == NULL && quasiParent == NULL) {
+ DBG_OBJ_MSG ("resize", 1, "no parent, regarding viewport");
+ DBG_OBJ_MSG_START ();
+
+ int limitMinWidth = getMinWidth (extremes, false);
+ int viewportWidth =
+ layout->viewportWidth - (layout->canvasHeightGreater ?
+ layout->vScrollbarThickness : 0);
+
+ int width = calcWidth (getStyle()->width, viewportWidth, NULL,
+ limitMinWidth, false);
+ int minWidth = calcWidth (getStyle()->minWidth, viewportWidth, NULL,
+ limitMinWidth, false);
+ int maxWidth = calcWidth (getStyle()->maxWidth, viewportWidth, NULL,
+ limitMinWidth, false);
+
+ DBG_OBJ_MSGF ("resize", 1, "width = %d, minWidth = %d, maxWidth = %d",
+ width, minWidth, maxWidth);
+
+ if (width != -1)
+ extremes->minWidth = extremes->maxWidth = width;
+ if (minWidth != -1)
+ extremes->minWidth = minWidth;
+ if (maxWidth != -1)
+ extremes->maxWidth = maxWidth;
+
+ DBG_OBJ_MSG_END ();
+ } else if (parent) {
+ DBG_OBJ_MSG ("resize", 1, "delegated to parent");
+ DBG_OBJ_MSG_START ();
+ parent->correctExtremesOfChild (this, extremes);
+ DBG_OBJ_MSG_END ();
+ } else /* if (quasiParent) */ {
+ DBG_OBJ_MSG ("resize", 1, "delegated to quasiParent");
+ DBG_OBJ_MSG_START ();
+ quasiParent->correctExtremesOfChild (this, extremes);
+ DBG_OBJ_MSG_END ();
+ }
+
+ if (extremes->maxWidth < extremes->minWidth)
+ extremes->maxWidth = extremes->minWidth;
+
+ DBG_OBJ_MSGF ("resize", 1, "=> %d / %d",
+ extremes->minWidth, extremes->maxWidth);
+ DBG_OBJ_LEAVE ();
+}
+
+int Widget::calcWidth (style::Length cssValue, int refWidth, Widget *refWidget,
+ int limitMinWidth, bool forceValue)
+{
+ DBG_OBJ_ENTER ("resize", 0, "calcWidth", "0x%x, %d, %p, %d",
+ cssValue, refWidth, refWidget, limitMinWidth);
+
+ assert (refWidth != -1 || refWidget != NULL);
+
+ int width;
+
+ if (style::isAbsLength (cssValue)) {
+ DBG_OBJ_MSGF ("resize", 1, "absolute width: %dpx",
+ style::absLengthVal (cssValue));
+ width = misc::max (style::absLengthVal (cssValue) + boxDiffWidth (),
+ limitMinWidth);
+ } else if (style::isPerLength (cssValue)) {
+ DBG_OBJ_MSGF ("resize", 1, "percentage width: %g%%",
+ 100 * style::perLengthVal_useThisOnlyForDebugging
+ (cssValue));
+ if (refWidth != -1)
+ width = misc::max (applyPerWidth (refWidth, cssValue), limitMinWidth);
+ else {
+ int availWidth = refWidget->getAvailWidth (forceValue);
+ if (availWidth != -1) {
+ int containerWidth = availWidth - refWidget->boxDiffWidth ();
+ width = misc::max (applyPerWidth (containerWidth, cssValue),
+ limitMinWidth);
+ } else
+ width = -1;
+ }
+ } else {
+ DBG_OBJ_MSG ("resize", 1, "not specified");
+ width = -1;
+ }
+
+ DBG_OBJ_MSGF ("resize", 1, "=> %d", width);
+ DBG_OBJ_LEAVE ();
+ return width;
+}
+
+// *finalWidth may be -1.
+void Widget::calcFinalWidth (style::Style *style, int refWidth,
+ Widget *refWidget, int limitMinWidth,
+ bool forceValue, int *finalWidth)
+{
+ DBG_OBJ_ENTER ("resize", 0, "calcFinalWidth", "..., %d, %p, %d, [%d]",
+ refWidth, refWidget, limitMinWidth, *finalWidth);
+
+ int width = calcWidth (style->width, refWidth, refWidget, limitMinWidth,
+ forceValue);
+ int minWidth = calcWidth (style->minWidth, refWidth, refWidget,
+ limitMinWidth, forceValue);
+ int maxWidth = calcWidth (style->maxWidth, refWidth, refWidget,
+ limitMinWidth, forceValue);
+
+ DBG_OBJ_MSGF ("resize", 1, "width = %d, minWidth = %d, maxWidth = %d",
+ width, minWidth, maxWidth);
+
+ if (width != -1)
+ *finalWidth = width;
+ if (minWidth != -1 && *finalWidth != -1 && *finalWidth < minWidth)
+ *finalWidth = minWidth;
+ if (maxWidth != -1 && *finalWidth == -1 && *finalWidth > maxWidth)
+ *finalWidth = maxWidth;
+
+ DBG_OBJ_MSGF ("resize", 1, "=> %d", *finalWidth);
+ DBG_OBJ_LEAVE ();
+}
+
+int Widget::calcHeight (style::Length cssValue, bool usePercentage,
+ int refHeight, Widget *refWidget, bool forceValue)
+{
+ // TODO Search for usage of this method and check the value of
+ // "usePercentage"; this has to be clarified.
+
+ DBG_OBJ_ENTER ("resize", 0, "calcHeight", "0x%x, %s, %d, %p",
+ cssValue, usePercentage ? "true" : "false", refHeight,
+ refWidget);
+
+ assert (refHeight != -1 || refWidget != NULL);
+
+ int height;
+
+ if (style::isAbsLength (cssValue)) {
+ DBG_OBJ_MSGF ("resize", 1, "absolute height: %dpx",
+ style::absLengthVal (cssValue));
+ height =
+ misc::max (style::absLengthVal (cssValue) + boxDiffHeight (), 0);
+ } else if (style::isPerLength (cssValue)) {
+ DBG_OBJ_MSGF ("resize", 1, "percentage height: %g%%",
+ 100 *
+ style::perLengthVal_useThisOnlyForDebugging (cssValue));
+ if (usePercentage) {
+ if (refHeight != -1)
+ height = misc::max (applyPerHeight (refHeight, cssValue), 0);
+ else {
+ int availHeight = refWidget->getAvailHeight (forceValue);
+ if (availHeight != -1) {
+ int containerHeight = availHeight - refWidget->boxDiffHeight ();
+ height =
+ misc::max (applyPerHeight (containerHeight, cssValue), 0);
+ } else
+ height = -1;
+ }
+ } else
+ height = -1;
+ } else {
+ DBG_OBJ_MSG ("resize", 1, "not specified");
+ height = -1;
+ }
+
+ DBG_OBJ_MSGF ("resize", 1, "=> %d", height);
+ DBG_OBJ_LEAVE ();
+ return height;
+}
+
+/**
+ * \brief Wrapper for Widget::getExtremesImpl().
+ */
+void Widget::getExtremes (Extremes *extremes)
+{
+ assert (!queueResizeEntered ());
+
+ DBG_OBJ_ENTER0 ("resize", 0, "getExtremes");
+
+ enterGetExtremes ();
+
+ if (extremesQueued ()) {
+ // This method is called outside of Layout::resizeIdle.
+ setFlags (EXTREMES_CHANGED);
+ unsetFlags (EXTREMES_QUEUED);
+ // The widget is not taken out of Layout::queueResizeList, since
+ // other *_QUEUED flags may still be set and processed in
+ // Layout::resizeIdle.
+ }
+
+ if (extremesChanged ()) {
+ // For backward compatibility (part 1/2):
+ extremes->minWidthIntrinsic = extremes->maxWidthIntrinsic = -1;
+
+ getExtremesImpl (extremes);
+
+ // For backward compatibility (part 2/2):
+ if (extremes->minWidthIntrinsic == -1)
+ extremes->minWidthIntrinsic = extremes->minWidth;
+ if (extremes->maxWidthIntrinsic == -1)
+ extremes->maxWidthIntrinsic = extremes->maxWidth;
+
+ this->extremes = *extremes;
+ unsetFlags (EXTREMES_CHANGED);
+
+ DBG_OBJ_SET_NUM ("extremes.minWidth", extremes->minWidth);
+ DBG_OBJ_SET_NUM ("extremes.minWidthIntrinsic",
+ extremes->minWidthIntrinsic);
+ DBG_OBJ_SET_NUM ("extremes.maxWidth", extremes->maxWidth);
+ DBG_OBJ_SET_NUM ("extremes.maxWidthIntrinsic",
+ extremes->maxWidthIntrinsic);
+ } else
+ *extremes = this->extremes;
+
+ leaveGetExtremes ();
+
+ DBG_OBJ_LEAVE ();
+}
+
+/**
+ * \brief Wrapper for Widget::sizeAllocateImpl, calls the latter only when
+ * needed.
+ */
+void Widget::sizeAllocate (Allocation *allocation)
+{
+ assert (!queueResizeEntered ());
+ assert (!sizeRequestEntered ());
+ assert (!getExtremesEntered ());
+ assert (resizeIdleEntered ());
+
+ DBG_OBJ_ENTER ("resize", 0, "sizeAllocate", "%d, %d; %d * (%d + %d)",
+ allocation->x, allocation->y, allocation->width,
+ allocation->ascent, allocation->descent);
+
+ DBG_OBJ_MSGF ("resize", 1,
+ "old allocation (%d, %d; %d * (%d + %d)); needsAllocate: %s",
+ this->allocation.x, this->allocation.y, this->allocation.width,
+ this->allocation.ascent, this->allocation.descent,
+ needsAllocate () ? "true" : "false");
+
+ enterSizeAllocate ();
+
+ /*printf ("The %stop-level %s %p is allocated:\n",
+ parent ? "non-" : "", getClassName(), this);
+ printf (" old = (%d, %d, %d + (%d + %d))\n",
+ this->allocation.x, this->allocation.y, this->allocation.width,
+ this->allocation.ascent, this->allocation.descent);
+ printf (" new = (%d, %d, %d + (%d + %d))\n",
+ allocation->x, allocation->y, allocation->width, allocation->ascent,
+ allocation->descent);
+ printf (" NEEDS_ALLOCATE = %s\n", needsAllocate () ? "true" : "false");*/
+
+ if (needsAllocate () ||
+ allocation->x != this->allocation.x ||
+ allocation->y != this->allocation.y ||
+ allocation->width != this->allocation.width ||
+ allocation->ascent != this->allocation.ascent ||
+ allocation->descent != this->allocation.descent) {
+
+ if (wasAllocated ()) {
+ layout->queueDrawExcept (
+ this->allocation.x,
+ this->allocation.y,
+ this->allocation.width,
+ this->allocation.ascent + this->allocation.descent,
+ allocation->x,
+ allocation->y,
+ allocation->width,
+ allocation->ascent + allocation->descent);
+ }
+
+ sizeAllocateImpl (allocation);
+
+ //DEBUG_MSG (DEBUG_ALLOC, "... to %d, %d, %d x %d x %d\n",
+ // widget->allocation.x, widget->allocation.y,
+ // widget->allocation.width, widget->allocation.ascent,
+ // widget->allocation.descent);
+
+ this->allocation = *allocation;
+ unsetFlags (NEEDS_ALLOCATE);
+ setFlags (WAS_ALLOCATED);
+
+ resizeDrawImpl ();
+
+ DBG_OBJ_SET_NUM ("allocation.x", this->allocation.x);
+ DBG_OBJ_SET_NUM ("allocation.y", this->allocation.y);
+ DBG_OBJ_SET_NUM ("allocation.width", this->allocation.width);
+ DBG_OBJ_SET_NUM ("allocation.ascent", this->allocation.ascent);
+ DBG_OBJ_SET_NUM ("allocation.descent", this->allocation.descent);
+ }
+
+ /*unsetFlags (NEEDS_RESIZE);*/
+
+ leaveSizeAllocate ();
+
+ DBG_OBJ_LEAVE ();
+}
+
+bool Widget::buttonPress (EventButton *event)
+{
+ return buttonPressImpl (event);
+}
+
+bool Widget::buttonRelease (EventButton *event)
+{
+ return buttonReleaseImpl (event);
+}
+
+bool Widget::motionNotify (EventMotion *event)
+{
+ return motionNotifyImpl (event);
+}
+
+void Widget::enterNotify (EventCrossing *event)
+{
+ enterNotifyImpl (event);
+}
+
+void Widget::leaveNotify (EventCrossing *event)
+{
+ leaveNotifyImpl (event);
+}
+
+/**
+ * \brief Change the style of a widget.
+ *
+ * The old style is automatically unreferred, the new is referred. If this
+ * call causes the widget to change its size, dw::core::Widget::queueResize
+ * is called.
+ */
+void Widget::setStyle (style::Style *style)
+{
+ bool sizeChanged;
+
+ if (widgetImgRenderer && this->style && this->style->backgroundImage)
+ this->style->backgroundImage->removeExternalImgRenderer
+ (widgetImgRenderer);
+
+ style->ref ();
+
+ if (this->style) {
+ sizeChanged = this->style->sizeDiffs (style);
+ this->style->unref ();
+ } else
+ sizeChanged = true;
+
+ this->style = style;
+
+ DBG_OBJ_ASSOC_CHILD (style);
+
+ if (style && style->backgroundImage) {
+ // Create instance of WidgetImgRenderer when needed. Until this
+ // widget is deleted, "widgetImgRenderer" will be kept, since it
+ // is not specific to the style, but only to this widget.
+ if (widgetImgRenderer == NULL)
+ widgetImgRenderer = new WidgetImgRenderer (this);
+ style->backgroundImage->putExternalImgRenderer (widgetImgRenderer);
+ }
+
+ if (layout != NULL) {
+ layout->updateCursor ();
+ }
+
+ if (sizeChanged)
+ queueResize (0, true);
+ else
+ queueDraw ();
+
+ // These should better be attributed to the style itself, and a
+ // script processing RTFL messages could transfer it to something
+ // equivalent:
+
+ DBG_OBJ_SET_NUM ("style.margin.top", style->margin.top);
+ DBG_OBJ_SET_NUM ("style.margin.bottom", style->margin.bottom);
+ DBG_OBJ_SET_NUM ("style.margin.left", style->margin.left);
+ DBG_OBJ_SET_NUM ("style.margin.right", style->margin.right);
+
+ DBG_OBJ_SET_NUM ("style.border-width.top", style->borderWidth.top);
+ DBG_OBJ_SET_NUM ("style.border-width.bottom", style->borderWidth.bottom);
+ DBG_OBJ_SET_NUM ("style.border-width.left", style->borderWidth.left);
+ DBG_OBJ_SET_NUM ("style.border-width.right", style->borderWidth.right);
+
+ DBG_OBJ_SET_NUM ("style.padding.top", style->padding.top);
+ DBG_OBJ_SET_NUM ("style.padding.bottom", style->padding.bottom);
+ DBG_OBJ_SET_NUM ("style.padding.left", style->padding.left);
+ DBG_OBJ_SET_NUM ("style.padding.right", style->padding.right);
+
+ DBG_OBJ_SET_NUM ("style.border-spacing (h)", style->hBorderSpacing);
+ DBG_OBJ_SET_NUM ("style.border-spacing (v)", style->vBorderSpacing);
+
+ DBG_OBJ_SET_SYM ("style.display",
+ style->display == style::DISPLAY_BLOCK ? "block" :
+ style->display == style::DISPLAY_INLINE ? "inline" :
+ style->display == style::DISPLAY_INLINE_BLOCK ?
+ "inline-block" :
+ style->display == style::DISPLAY_LIST_ITEM ? "list-item" :
+ style->display == style::DISPLAY_NONE ? "none" :
+ style->display == style::DISPLAY_TABLE ? "table" :
+ style->display == style::DISPLAY_TABLE_ROW_GROUP ?
+ "table-row-group" :
+ style->display == style::DISPLAY_TABLE_HEADER_GROUP ?
+ "table-header-group" :
+ style->display == style::DISPLAY_TABLE_FOOTER_GROUP ?
+ "table-footer-group" :
+ style->display == style::DISPLAY_TABLE_ROW ? "table-row" :
+ style->display == style::DISPLAY_TABLE_CELL ? "table-cell" :
+ "???");
+
+ DBG_OBJ_SET_NUM ("style.width (raw)", style->width);
+ DBG_OBJ_SET_NUM ("style.min-width (raw)", style->minWidth);
+ DBG_OBJ_SET_NUM ("style.max-width (raw)", style->maxWidth);
+ DBG_OBJ_SET_NUM ("style.height (raw)", style->height);
+ DBG_OBJ_SET_NUM ("style.min-height (raw)", style->minHeight);
+ DBG_OBJ_SET_NUM ("style.max-height (raw)", style->maxHeight);
+}
+
+/**
+ * \brief Set the background "behind" the widget, if it is not the
+ * background of the parent widget, e.g. the background of a table
+ * row.
+ */
+void Widget::setBgColor (style::Color *bgColor)
+{
+ this->bgColor = bgColor;
+}
+
+/**
+ * \brief Get the actual background of a widget.
+ */
+style::Color *Widget::getBgColor ()
+{
+ Widget *widget = this;
+
+ while (widget != NULL) {
+ if (widget->style->backgroundColor)
+ return widget->style->backgroundColor;
+ if (widget->bgColor)
+ return widget->bgColor;
+
+ widget = widget->parent;
+ }
+
+ return layout->getBgColor ();
+}
+
+
+/**
+ * \brief Draw borders and background of a widget part, which allocation is
+ * given by (x, y, width, height) (widget coordinates).
+ *
+ * area is given in widget coordinates.
+ */
+void Widget::drawBox (View *view, style::Style *style, Rectangle *area,
+ int x, int y, int width, int height, bool inverse)
+{
+ Rectangle canvasArea;
+ canvasArea.x = area->x + allocation.x;
+ canvasArea.y = area->y + allocation.y;
+ canvasArea.width = area->width;
+ canvasArea.height = area->height;
+
+ style::drawBorder (view, layout, &canvasArea,
+ allocation.x + x, allocation.y + y,
+ width, height, style, inverse);
+
+ // This method is used for inline elements, where the CSS 2 specification
+ // does not define what here is called "reference area". To make it look
+ // smoothly, the widget padding box is used.
+
+ // TODO Handle inverse drawing the same way as in drawWidgetBox?
+ // Maybe this method (drawBox) is anyway obsolete when extraSpace
+ // is fully supported (as in the "dillo_grows" repository).
+
+ int xPad, yPad, widthPad, heightPad;
+ getPaddingArea (&xPad, &yPad, &widthPad, &heightPad);
+ style::drawBackground
+ (view, layout, &canvasArea,
+ allocation.x + x + style->margin.left + style->borderWidth.left,
+ allocation.y + y + style->margin.top + style->borderWidth.top,
+ width - style->margin.left - style->borderWidth.left
+ - style->margin.right - style->borderWidth.right,
+ height - style->margin.top - style->borderWidth.top
+ - style->margin.bottom - style->borderWidth.bottom,
+ xPad, yPad, widthPad, heightPad, style, style->backgroundColor,
+ inverse, false);
+}
+
+/**
+ * \brief Draw borders and background of a widget.
+ *
+ * area is given in widget coordinates.
+ *
+ */
+void Widget::drawWidgetBox (View *view, Rectangle *area, bool inverse)
+{
+ Rectangle canvasArea;
+ canvasArea.x = area->x + allocation.x;
+ canvasArea.y = area->y + allocation.y;
+ canvasArea.width = area->width;
+ canvasArea.height = area->height;
+
+ style::drawBorder (view, layout, &canvasArea, allocation.x, allocation.y,
+ allocation.width, getHeight (), style, inverse);
+
+ int xPad, yPad, widthPad, heightPad;
+ getPaddingArea (&xPad, &yPad, &widthPad, &heightPad);
+
+ style::Color *bgColor;
+ if (inverse && style->backgroundColor == NULL) {
+ // See style::drawBackground: for inverse drawing, we need a
+ // defined background color. Search through ancestors.
+ Widget *w = this;
+ while (w != NULL && w->style->backgroundColor == NULL)
+ w = w->parent;
+
+ if (w != NULL && w->style->backgroundColor != NULL)
+ bgColor = w->style->backgroundColor;
+ else
+ bgColor = layout->getBgColor ();
+ } else
+ bgColor = style->backgroundColor;
+
+ style::drawBackground (view, layout, &canvasArea,
+ xPad, yPad, widthPad, heightPad,
+ xPad, yPad, widthPad, heightPad,
+ style, bgColor, inverse, parent == NULL);
+}
+
+/*
+ * This function is used by some widgets, when they are selected (as a whole).
+ *
+ * \todo This could be accelerated by using clipping bitmaps. Two important
+ * issues:
+ *
+ * (i) There should always been a pixel in the upper-left corner of the
+ * *widget*, so probably two different clipping bitmaps have to be
+ * used (10/01 and 01/10).
+ *
+ * (ii) Should a new GC always be created?
+ *
+ * \bug Not implemented.
+ */
+void Widget::drawSelected (View *view, Rectangle *area)
+{
+}
+
+
+void Widget::setButtonSensitive (bool buttonSensitive)
+{
+ this->buttonSensitive = buttonSensitive;
+ buttonSensitiveSet = true;
+}
+
+
+/**
+ * \brief Get the widget at the root of the tree, this widget is part from.
+ */
+Widget *Widget::getTopLevel ()
+{
+ Widget *widget = this;
+
+ while (widget->parent)
+ widget = widget->parent;
+
+ return widget;
+}
+
+/**
+ * \brief Get the level of the widget within the tree.
+ *
+ * The root widget has the level 0.
+ */
+int Widget::getLevel ()
+{
+ Widget *widget = this;
+ int level = 0;
+
+ while (widget->parent) {
+ level++;
+ widget = widget->parent;
+ }
+
+ return level;
+}
+
+/**
+ * \brief Get the level of the widget within the tree, regarting the
+ * generators, not the parents.
+ *
+ * The root widget has the level 0.
+ */
+int Widget::getGeneratorLevel ()
+{
+ Widget *widget = this;
+ int level = 0;
+
+ while (widget->getGenerator ()) {
+ level++;
+ widget = widget->getGenerator ();
+ }
+
+ return level;
+}
+
+/**
+ * \brief Get the widget with the highest level, which is a direct ancestor of
+ * widget1 and widget2.
+ */
+Widget *Widget::getNearestCommonAncestor (Widget *otherWidget)
+{
+ Widget *widget1 = this, *widget2 = otherWidget;
+ int level1 = widget1->getLevel (), level2 = widget2->getLevel();
+
+ /* Get both widgets onto the same level.*/
+ while (level1 > level2) {
+ widget1 = widget1->parent;
+ level1--;
+ }
+
+ while (level2 > level1) {
+ widget2 = widget2->parent;
+ level2--;
+ }
+
+ /* Search upwards. */
+ while (widget1 != widget2) {
+ if (widget1->parent == NULL) {
+ MSG_WARN("widgets in different trees\n");
+ return NULL;
+ }
+
+ widget1 = widget1->parent;
+ widget2 = widget2->parent;
+ }
+
+ return widget1;
+}
+
+
+/**
+ * \brief Search recursively through widget.
+ *
+ * Used by dw::core::Layout:getWidgetAtPoint.
+ */
+Widget *Widget::getWidgetAtPoint (int x, int y, int level)
+{
+ Iterator *it;
+ Widget *childAtPoint;
+
+ //printf ("%*s-> examining the %s %p (%d, %d, %d x (%d + %d))\n",
+ // 3 * level, "", getClassName (), this, allocation.x, allocation.y,
+ // allocation.width, allocation.ascent, allocation.descent);
+
+ if (x >= allocation.x &&
+ y >= allocation.y &&
+ x <= allocation.x + allocation.width &&
+ y <= allocation.y + getHeight ()) {
+ //_MSG ("%*s -> inside\n", 3 * level, "");
+ /*
+ * Iterate over the children of this widget. Test recursively, whether
+ * the point is within the child (or one of its children...). If there
+ * is such a child, it is returned. Otherwise, this widget is returned.
+ */
+ childAtPoint = NULL;
+ it = iterator ((Content::Type)
+ (Content::WIDGET_IN_FLOW | Content::WIDGET_OOF_CONT),
+ false);
+
+ while (childAtPoint == NULL && it->next ()) {
+ Widget *child = it->getContent()->widget;
+ if (child->wasAllocated ())
+ childAtPoint = child->getWidgetAtPoint (x, y, level + 1);
+ }
+
+ it->unref ();
+
+ if (childAtPoint)
+ return childAtPoint;
+ else
+ return this;
+ } else
+ return NULL;
+}
+
+
+void Widget::scrollTo (HPosition hpos, VPosition vpos)
+{
+ layout->scrollToWidget (hpos, vpos, this);
+}
+
+
+void Widget::scrollTo (HPosition hpos, VPosition vpos,
+ int x, int y, int width, int height)
+{
+ // TODO This should perhaps better be done by a new Layout::ScrollTarget.
+ layout->scrollTo (hpos, vpos,
+ x + allocation.x, y + allocation.y, width, height);
+}
+
+
+/**
+ * \brief Return the padding area (content plus padding).
+ *
+ * Used as "reference area" (ee comment of "style::drawBackground")
+ * for backgrounds.
+ */
+void Widget::getPaddingArea (int *xPad, int *yPad, int *widthPad,
+ int *heightPad)
+{
+ *xPad = allocation.x + style->margin.left + style->borderWidth.left;
+ *yPad = allocation.y + style->margin.top + style->borderWidth.top;
+ *widthPad = allocation.width - style->margin.left - style->borderWidth.left
+ - style->margin.right - style->borderWidth.right;
+ *heightPad = getHeight () - style->margin.top - style->borderWidth.top
+ - style->margin.bottom - style->borderWidth.bottom;
+}
+
+void Widget::sizeAllocateImpl (Allocation *allocation)
+{
+}
+
+void Widget::markSizeChange (int ref)
+{
+}
+
+void Widget::markExtremesChange (int ref)
+{
+}
+
+int Widget::applyPerWidth (int containerWidth, style::Length perWidth)
+{
+ return style::multiplyWithPerLength (containerWidth, perWidth)
+ + boxDiffWidth ();
+}
+
+int Widget::applyPerHeight (int containerHeight, style::Length perHeight)
+{
+ return style::multiplyWithPerLength (containerHeight, perHeight)
+ + boxDiffHeight ();
+}
+
+int Widget::getAvailWidthOfChild (Widget *child, bool forceValue)
+{
+ // This is a halfway suitable implementation for all
+ // containers. For simplification, this will be used during the
+ // development; then, a differentiation could be possible.
+
+ DBG_OBJ_ENTER ("resize", 0, "getAvailWidthOfChild", "%p, %s",
+ child, forceValue ? "true" : "false");
+
+ int width;
+
+ if (child->getStyle()->width == style::LENGTH_AUTO) {
+ DBG_OBJ_MSG ("resize", 1, "no specification");
+ if (forceValue)
+ width = misc::max (getAvailWidth (true) - boxDiffWidth (), 0);
+ else
+ width = -1;
+ } else {
+ // In most cases, the toplevel widget should be a container, so
+ // the container is non-NULL when the parent is non-NULL. Just
+ // in case, regard also parent. And quasiParent.
+ Widget *effContainer = child->quasiParent ? child->quasiParent :
+ (child->container ? child->container : child->parent);
+
+ if (effContainer == this) {
+ width = -1;
+ child->calcFinalWidth (child->getStyle(), -1, this, 0, forceValue,
+ &width);
+ } else {
+ DBG_OBJ_MSG ("resize", 1, "delegated to (effective) container");
+ DBG_OBJ_MSG_START ();
+ width = effContainer->getAvailWidthOfChild (child, forceValue);
+ DBG_OBJ_MSG_END ();
+ }
+ }
+
+ DBG_OBJ_MSGF ("resize", 1, "=> %d", width);
+ DBG_OBJ_LEAVE ();
+
+ return width;
+}
+
+int Widget::getAvailHeightOfChild (Widget *child, bool forceValue)
+{
+ // Again, a suitable implementation for all widgets (perhaps).
+
+ // TODO Consider 'min-height' and 'max-height'. (Minor priority, as long as
+ // "getAvailHeight (true)" is not used.
+
+ DBG_OBJ_ENTER ("resize", 0, "getAvailHeightOfChild", "%p, %s",
+ child, forceValue ? "true" : "false");
+
+ int height;
+
+ if (child->getStyle()->height == style::LENGTH_AUTO) {
+ DBG_OBJ_MSG ("resize", 1, "no specification");
+ if (forceValue)
+ height = misc::max (getAvailHeight (true) - boxDiffHeight (), 0);
+ else
+ height = -1;
+ } else {
+ // See comment in Widget::getAvailWidthOfChild.
+ Widget *effContainer = child->quasiParent ? child->quasiParent :
+ (child->container ? child->container : child->parent);
+
+ if (effContainer == this) {
+ if (style::isAbsLength (child->getStyle()->height)) {
+ DBG_OBJ_MSGF ("resize", 1, "absolute height: %dpx",
+ style::absLengthVal (child->getStyle()->height));
+ height = misc::max (style::absLengthVal (child->getStyle()->height)
+ + child->boxDiffHeight (), 0);
+ } else {
+ assert (style::isPerLength (child->getStyle()->height));
+ DBG_OBJ_MSGF ("resize", 1, "percentage height: %g%%",
+ 100 * style::perLengthVal_useThisOnlyForDebugging
+ (child->getStyle()->height));
+
+ int availHeight = getAvailHeight (forceValue);
+ if (availHeight == -1)
+ height = -1;
+ else
+ height =
+ misc::max (child->applyPerHeight (availHeight -
+ boxDiffHeight (),
+ child->getStyle()->height),
+ 0);
+ }
+ } else {
+ DBG_OBJ_MSG ("resize", 1, "delegated to (effective) container");
+ DBG_OBJ_MSG_START ();
+ height = effContainer->getAvailHeightOfChild (child, forceValue);
+ DBG_OBJ_MSG_END ();
+ }
+ }
+
+ DBG_OBJ_MSGF ("resize", 1, "=> %d", height);
+ DBG_OBJ_LEAVE ();
+
+ return height;
+}
+
+void Widget::correctRequisitionOfChild (Widget *child, Requisition *requisition,
+ void (*splitHeightFun) (int, int*,
+ int*))
+{
+ // Again, a suitable implementation for all widgets (perhaps).
+
+ DBG_OBJ_ENTER ("resize", 0, "correctRequisitionOfChild",
+ "%p, %d * (%d + %d), ...", child, requisition->width,
+ requisition->ascent, requisition->descent);
+
+ // See comment in Widget::getAvailWidthOfChild.
+ Widget *effContainer = child->quasiParent ? child->quasiParent :
+ (child->container ? child->container : child->parent);
+
+ if (effContainer == this) {
+ correctReqWidthOfChild (child, requisition);
+ correctReqHeightOfChild (child, requisition, splitHeightFun);
+ } else {
+ DBG_OBJ_MSG ("resize", 1, "delegated to (effective) container");
+ DBG_OBJ_MSG_START ();
+ effContainer->correctRequisitionOfChild (child, requisition,
+ splitHeightFun);
+ DBG_OBJ_MSG_END ();
+ }
+
+ DBG_OBJ_MSGF ("resize", 1, "=> %d * (%d + %d)",
+ requisition->width, requisition->ascent,
+ requisition->descent);
+ DBG_OBJ_LEAVE ();
+}
+
+void Widget::correctReqWidthOfChild (Widget *child, Requisition *requisition)
+{
+ DBG_OBJ_ENTER ("resize", 0, "correctReqWidthOfChild", "%p, %d * (%d + %d)",
+ child, requisition->width, requisition->ascent,
+ requisition->descent);
+
+ assert (this == child->quasiParent || this == child->container);
+
+ int limitMinWidth = child->getMinWidth (NULL, true);
+ child->calcFinalWidth (child->getStyle(), -1, this, limitMinWidth, false,
+ &requisition->width);
+
+ DBG_OBJ_MSGF ("resize", 1, "=> %d * (%d + %d)",
+ requisition->width, requisition->ascent,
+ requisition->descent);
+ DBG_OBJ_LEAVE ();
+}
+
+void Widget::correctReqHeightOfChild (Widget *child, Requisition *requisition,
+ void (*splitHeightFun) (int, int*, int*))
+{
+ // TODO Correct height by extremes? (Height extemes?)
+
+ assert (this == child->quasiParent || this == child->container);
+
+ DBG_OBJ_ENTER ("resize", 0, "correctReqHeightOfChild",
+ "%p, %d * (%d + %d), ...", child, requisition->width,
+ requisition->ascent, requisition->descent);
+
+ int height = child->calcHeight (child->getStyle()->height, false, -1, this,
+ false);
+ int minHeight = child->calcHeight (child->getStyle()->minHeight, false, -1,
+ this, false);
+ int maxHeight = child->calcHeight (child->getStyle()->maxHeight, false, -1,
+ this, false);
+
+ // TODO Perhaps split first, then add box ascent and descent.
+ if (height != -1)
+ splitHeightFun (height, &requisition->ascent, &requisition->descent);
+ if (minHeight != -1 &&
+ requisition->ascent + requisition->descent < minHeight)
+ splitHeightFun (minHeight, &requisition->ascent,
+ &requisition->descent);
+ if (maxHeight != -1 &&
+ requisition->ascent + requisition->descent > maxHeight)
+ splitHeightFun (maxHeight, &requisition->ascent,
+ &requisition->descent);
+
+ DBG_OBJ_MSGF ("resize", 1, "=> %d * (%d + %d)",
+ requisition->width, requisition->ascent,
+ requisition->descent);
+ DBG_OBJ_LEAVE ();
+}
+
+void Widget::correctExtremesOfChild (Widget *child, Extremes *extremes)
+{
+ // See comment in correctRequisitionOfChild.
+
+ DBG_OBJ_ENTER ("resize", 0, "correctExtremesOfChild",
+ "%p, %d (%d) / %d (%d)",
+ child, extremes->minWidth, extremes->minWidthIntrinsic,
+ extremes->maxWidth, extremes->maxWidthIntrinsic);
+
+ // See comment in Widget::getAvailWidthOfChild.
+ Widget *effContainer = child->quasiParent ? child->quasiParent :
+ (child->container ? child->container : child->parent);
+
+ if (effContainer == this) {
+ int limitMinWidth = child->getMinWidth (extremes, false);
+ int width = child->calcWidth (child->getStyle()->width, -1, this,
+ limitMinWidth, false);
+ int minWidth = child->calcWidth (child->getStyle()->minWidth, -1, this,
+ limitMinWidth, false);
+ int maxWidth = child->calcWidth (child->getStyle()->maxWidth, -1, this,
+ limitMinWidth, false);
+
+ DBG_OBJ_MSGF ("resize", 1, "width = %d, minWidth = %d, maxWidth = %d",
+ width, minWidth, maxWidth);
+
+ if (width != -1)
+ extremes->minWidth = extremes->maxWidth = width;
+ if (minWidth != -1)
+ extremes->minWidth = minWidth;
+ if (maxWidth != -1)
+ extremes->maxWidth = maxWidth;
+ } else {
+ DBG_OBJ_MSG ("resize", 1, "delegated to (effective) container");
+ DBG_OBJ_MSG_START ();
+ effContainer->correctExtremesOfChild (child, extremes);
+ DBG_OBJ_MSG_END ();
+ }
+
+
+ DBG_OBJ_MSGF ("resize", 1, "=> %d / %d",
+ extremes->minWidth, extremes->maxWidth);
+ DBG_OBJ_LEAVE ();
+}
+
+/**
+ * \brief This method is called after a widget has been set as the top of a
+ * widget tree.
+ *
+ * A widget may override this method when it is necessary to be notified.
+ */
+void Widget::notifySetAsTopLevel()
+{
+}
+
+/**
+ * \brief This method is called after a widget has been added to a parent.
+ *
+ * A widget may override this method when it is necessary to be notified.
+ */
+void Widget::notifySetParent()
+{
+}
+
+bool Widget::isBlockLevel ()
+{
+ // Most widgets are not block-level.
+ return false;
+}
+
+bool Widget::isPossibleContainer ()
+{
+ // In most (all?) cases identical to:
+ return isBlockLevel ();
+}
+
+bool Widget::buttonPressImpl (EventButton *event)
+{
+ return false;
+}
+
+bool Widget::buttonReleaseImpl (EventButton *event)
+{
+ return false;
+}
+
+bool Widget::motionNotifyImpl (EventMotion *event)
+{
+ return false;
+}
+
+void Widget::enterNotifyImpl (EventCrossing *)
+{
+ style::Tooltip *tooltip = getStyle()->x_tooltip;
+
+ if (tooltip)
+ tooltip->onEnter();
+}
+
+void Widget::leaveNotifyImpl (EventCrossing *)
+{
+ style::Tooltip *tooltip = getStyle()->x_tooltip;
+
+ if (tooltip)
+ tooltip->onLeave();
+}
+
+void Widget::removeChild (Widget *child)
+{
+ // Should be implemented.
+ misc::assertNotReached ();
+}
+
+// ----------------------------------------------------------------------
+
+void splitHeightPreserveAscent (int height, int *ascent, int *descent)
+{
+ *descent = height - *ascent;
+ if (*descent < 0) {
+ *descent = 0;
+ *ascent = height;
+ }
+}
+
+void splitHeightPreserveDescent (int height, int *ascent, int *descent)
+{
+ *ascent = height - *descent;
+ if (*ascent < 0) {
+ *ascent = 0;
+ *descent = height;
+ }
+}
+
+} // namespace core
+} // namespace dw
diff --git a/dw/widget.hh b/dw/widget.hh
new file mode 100644
index 0000000..d107fe1
--- /dev/null
+++ b/dw/widget.hh
@@ -0,0 +1,514 @@
+#ifndef __DW_WIDGET_HH__
+#define __DW_WIDGET_HH__
+
+#ifndef __INCLUDED_FROM_DW_CORE_HH__
+# error Do not include this file directly, use "core.hh" instead.
+#endif
+
+#include "../lout/identity.hh"
+
+/**
+ * \brief The type for callback functions.
+ */
+typedef void (*DW_Callback_t)(void *data);
+
+namespace dw {
+namespace core {
+
+/**
+ * \brief The base class of all dillo widgets.
+ *
+ * \sa\ref dw-overview, \ref dw-layout-widgets
+ */
+class Widget: public lout::identity::IdentifiableObject
+{
+ friend class Layout;
+
+protected:
+ enum Flags {
+ /**
+ * \todo Comment this.
+ */
+ RESIZE_QUEUED = 1 << 0,
+
+ /**
+ * \todo Comment this.
+ */
+ EXTREMES_QUEUED = 1 << 1,
+
+ /**
+ * \brief Set, when dw::core::Widget::requisition is not up to date
+ * anymore.
+ *
+ * \todo Update, see RESIZE_QUEUED.
+ */
+ NEEDS_RESIZE = 1 << 2,
+
+ /**
+ * \brief Only used internally, set to enforce size allocation.
+ *
+ * In some cases, the size of a widget remains the same, but the
+ * children are allocated at different positions and in
+ * different sizes, so that a simple comparison of old and new
+ * allocation is insufficient. Therefore, this flag is set
+ * (indirectly, as ALLOCATE_QUEUED) in queueResize.
+ */
+ NEEDS_ALLOCATE = 1 << 3,
+
+ /**
+ * \todo Comment this.
+ */
+ ALLOCATE_QUEUED = 1 << 4,
+
+ /**
+ * \brief Set, when dw::core::Widget::extremes is not up to date
+ * anymore.
+ *
+ * \todo Update, see RESIZE_QUEUED.
+ */
+ EXTREMES_CHANGED = 1 << 5,
+
+ /**
+ * \brief Set, when a widget was already once allocated,
+ *
+ * The dw::Image widget uses this flag, see dw::Image::setBuffer.
+ */
+ WAS_ALLOCATED = 1 << 6,
+ };
+
+ /**
+ * \brief Implementation which represents the whole widget.
+ *
+ * The only instance is set created needed.
+ */
+ class WidgetImgRenderer: public style::StyleImage::ExternalWidgetImgRenderer
+ {
+ private:
+ Widget *widget;
+
+ public:
+ inline WidgetImgRenderer (Widget *widget) { this->widget = widget; }
+
+ bool readyToDraw ();
+ void getBgArea (int *x, int *y, int *width, int *height);
+ void getRefArea (int *xRef, int *yRef, int *widthRef, int *heightRef);
+ style::Style *getStyle ();
+ void draw (int x, int y, int width, int height);
+ };
+
+ WidgetImgRenderer *widgetImgRenderer;
+
+private:
+ static bool adjustMinWidth;
+
+ /**
+ * \brief The parent widget, NULL for top-level widgets.
+ */
+ Widget *parent;
+
+ /**
+ * \brief ...
+ */
+ Widget *quasiParent;
+
+ /**
+ * \brief The generating widget, NULL for top-level widgets, or if
+ * not set; in the latter case, the effective generator (see
+ * getGenerator) is the parent.
+ */
+ Widget *generator;
+
+ /**
+ * \brief The containing widget, equivalent to the "containing
+ * block" defined by CSS. May be NULL, in this case the viewport
+ * is used.
+ */
+ Widget *container;
+
+ style::Style *style;
+
+ Flags flags;
+
+ /**
+ * \brief Size_request() stores the result of the last call of
+ * size_request_impl().
+ *
+ * Do not read this directly, but call size_request().
+ */
+ Requisition requisition;
+
+ /**
+ * \brief Analogue to dw::core::Widget::requisition.
+ */
+ Extremes extremes;
+
+ /**
+ * \brief See dw::core::Widget::setBgColor().
+ */
+ style::Color *bgColor;
+
+ /**
+ * \brief See dw::core::Widget::setButtonSensitive().
+ */
+ bool buttonSensitive;
+
+ /**
+ * \brief See dw::core::Widget::setButtonSensitive().
+ */
+ bool buttonSensitiveSet;
+
+ void queueResize (int ref, bool extremesChanged, bool fast);
+ inline void queueResizeFast (int ref, bool extremesChanged)
+ { queueResize (ref, extremesChanged, true); }
+ void actualQueueResize (int ref, bool extremesChanged, bool fast);
+
+public:
+ /**
+ * \brief This value is defined by the parent widget, and used for
+ * incremential resizing.
+ *
+ * See documentation for an explanation.
+ */
+ int parentRef;
+
+protected:
+
+ /**
+ * \brief The current allocation: size and position, always relative to the
+ * canvas.
+ */
+ Allocation allocation;
+
+ inline int getHeight () { return allocation.ascent + allocation.descent; }
+ inline int getContentWidth() { return allocation.width
+ - style->boxDiffWidth (); }
+ inline int getContentHeight() { return getHeight ()
+ - style->boxDiffHeight (); }
+
+ Layout *layout;
+
+ /**
+ * \brief Space around the margin box. Allocation is extraSpace +
+ * margin + border + padding + contents;
+ */
+ style::Box extraSpace;
+
+ /*inline void printFlags () {
+ DBG_IF_RTFL {
+ char buf[10 * 3 - 1 + 1];
+ snprintf (buf, sizeof (buf), "%s:%s:%s:%s:%s:%s:%s",
+ (flags & RESIZE_QUEUED) ? "Rq" : "--",
+ (flags & EXTREMES_QUEUED) ? "Eq" : "--",
+ (flags & NEEDS_RESIZE) ? "nR" : "--",
+ (flags & NEEDS_ALLOCATE) ? "nA" : "--",
+ (flags & ALLOCATE_QUEUED) ? "Aq" : "--",
+ (flags & EXTREMES_CHANGED) ? "Ec" : "--",
+ (flags & WAS_ALLOCATED) ? "wA" : "--");
+ DBG_OBJ_SET_SYM ("flags", buf);
+ }
+ }*/
+
+ inline void printFlag (Flags f) {
+ DBG_IF_RTFL {
+ switch (f) {
+ case RESIZE_QUEUED:
+ DBG_OBJ_SET_SYM ("flags.RESIZE_QUEUED",
+ (flags & RESIZE_QUEUED) ? "true" : "false");
+ break;
+
+ case EXTREMES_QUEUED:
+ DBG_OBJ_SET_SYM ("flags.EXTREMES_QUEUED",
+ (flags & EXTREMES_QUEUED) ? "true" : "false");
+ break;
+
+ case NEEDS_RESIZE:
+ DBG_OBJ_SET_SYM ("flags.NEEDS_RESIZE",
+ (flags & NEEDS_RESIZE) ? "true" : "false");
+ break;
+
+ case NEEDS_ALLOCATE:
+ DBG_OBJ_SET_SYM ("flags.NEEDS_ALLOCATE",
+ (flags & NEEDS_ALLOCATE) ? "true" : "false");
+ break;
+
+ case ALLOCATE_QUEUED:
+ DBG_OBJ_SET_SYM ("flags.ALLOCATE_QUEUED",
+ (flags & ALLOCATE_QUEUED) ? "true" : "false");
+ break;
+
+ case EXTREMES_CHANGED:
+ DBG_OBJ_SET_SYM ("flags.EXTREMES_CHANGED",
+ (flags & EXTREMES_CHANGED) ? "true" : "false");
+ break;
+
+ case WAS_ALLOCATED:
+ DBG_OBJ_SET_SYM ("flags.WAS_ALLOCATED",
+ (flags & WAS_ALLOCATED) ? "true" : "false");
+ break;
+ }
+ }
+ }
+
+ inline void setFlags (Flags f)
+ { flags = (Flags)(flags | f); printFlag (f); }
+ inline void unsetFlags (Flags f)
+ { flags = (Flags)(flags & ~f); printFlag (f); }
+
+
+ inline void queueDraw ()
+ { queueDrawArea (0, 0, allocation.width, getHeight()); }
+ void queueDrawArea (int x, int y, int width, int height);
+ inline void queueResize (int ref, bool extremesChanged)
+ { queueResize (ref, extremesChanged, false); }
+
+ /**
+ * \brief See \ref dw-widget-sizes.
+ */
+ virtual void sizeRequestImpl (Requisition *requisition) = 0;
+
+ /**
+ * \brief See \ref dw-widget-sizes.
+ */
+ virtual void getExtremesImpl (Extremes *extremes) = 0;
+
+ /**
+ * \brief See \ref dw-widget-sizes.
+ */
+ virtual void sizeAllocateImpl (Allocation *allocation);
+
+ /**
+ * \brief Called after sizeAllocateImpl() to redraw necessary areas.
+ * By default the whole widget is redrawn.
+ */
+ virtual void resizeDrawImpl () { queueDraw (); };
+
+ /**
+ * \brief See \ref dw-widget-sizes.
+ */
+ virtual void markSizeChange (int ref);
+
+ /**
+ * \brief See \ref dw-widget-sizes.
+ */
+ virtual void markExtremesChange (int ref);
+
+ int getMinWidth (Extremes *extremes, bool forceValue);
+
+ virtual int getAvailWidthOfChild (Widget *child, bool forceValue);
+ virtual int getAvailHeightOfChild (Widget *child, bool forceValue);
+ virtual void correctRequisitionOfChild (Widget *child,
+ Requisition *requisition,
+ void (*splitHeightFun) (int, int*,
+ int*));
+ void correctReqWidthOfChild (Widget *child, Requisition *requisition);
+ void correctReqHeightOfChild (Widget *child, Requisition *requisition,
+ void (*splitHeightFun) (int, int*, int*));
+ virtual void correctExtremesOfChild (Widget *child, Extremes *extremes);
+
+ virtual void containerSizeChangedForChildren ();
+
+ virtual bool affectedByContainerSizeChange ();
+ virtual bool affectsSizeChangeContainerChild (Widget *child);
+ virtual bool usesAvailWidth ();
+ virtual bool usesAvailHeight ();
+
+ virtual void notifySetAsTopLevel();
+ virtual void notifySetParent();
+
+ virtual bool buttonPressImpl (EventButton *event);
+ virtual bool buttonReleaseImpl (EventButton *event);
+ virtual bool motionNotifyImpl (EventMotion *event);
+ virtual void enterNotifyImpl (EventCrossing *event);
+ virtual void leaveNotifyImpl (EventCrossing *event);
+
+ inline char *addAnchor (const char* name)
+ { return layout->addAnchor (this, name); }
+
+ inline char *addAnchor (const char* name, int y)
+ { return layout->addAnchor (this, name, y); }
+
+ inline void changeAnchor (char* name, int y)
+ { layout->changeAnchor (this, name, y); }
+
+ inline void removeAnchor (char* name)
+ { if (layout) layout->removeAnchor (this, name); }
+
+ //inline void updateBgColor () { layout->updateBgColor (); }
+
+ inline void setCursor (style::Cursor cursor)
+ { layout->setCursor (cursor); }
+#if 0
+ inline bool selectionButtonPress (Iterator *it, int charPos, int linkNo,
+ EventButton *event, bool withinContent)
+ { return layout->selectionState.buttonPress (it, charPos, linkNo, event); }
+
+ inline bool selectionButtonRelease (Iterator *it, int charPos, int linkNo,
+ EventButton *event, bool withinContent)
+ { return layout->selectionState.buttonRelease (it, charPos, linkNo, event);}
+
+ inline bool selectionButtonMotion (Iterator *it, int charPos, int linkNo,
+ EventMotion *event, bool withinContent)
+ { return layout->selectionState.buttonMotion (it, charPos, linkNo, event); }
+#endif
+ inline bool selectionHandleEvent (SelectionState::EventType eventType,
+ Iterator *it, int charPos, int linkNo,
+ MousePositionEvent *event)
+ { return layout->selectionState.handleEvent (eventType, it, charPos, linkNo,
+ event); }
+
+private:
+ void *deleteCallbackData;
+ DW_Callback_t deleteCallbackFunc;
+
+public:
+ inline void setDeleteCallback(DW_Callback_t func, void *data)
+ { deleteCallbackFunc = func; deleteCallbackData = data; }
+
+private:
+ bool resizeIdleEntered () { return layout && layout->resizeIdleCounter; }
+
+ void enterQueueResize () { if (layout) layout->queueResizeCounter++; }
+ void leaveQueueResize () { if (layout) layout->queueResizeCounter--; }
+ bool queueResizeEntered () { return layout && layout->queueResizeCounter; }
+
+ void enterSizeAllocate () { if (layout) layout->sizeAllocateCounter++; }
+ void leaveSizeAllocate () { if (layout) layout->sizeAllocateCounter--; }
+ bool sizeAllocateEntered () { return layout && layout->sizeAllocateCounter; }
+
+ void enterSizeRequest () { if (layout) layout->sizeRequestCounter++; }
+ void leaveSizeRequest () { if (layout) layout->sizeRequestCounter--; }
+ bool sizeRequestEntered () { return layout && layout->sizeRequestCounter; }
+
+ void enterGetExtremes () { if (layout) layout->getExtremesCounter++; }
+ void leaveGetExtremes () { if (layout) layout->getExtremesCounter--; }
+ bool getExtremesEntered () { return layout && layout->getExtremesCounter; }
+
+
+public:
+ static int CLASS_ID;
+
+ inline static void setAdjustMinWidth (bool adjustMinWidth)
+ { Widget::adjustMinWidth = adjustMinWidth; }
+
+ Widget ();
+ ~Widget ();
+
+ inline bool resizeQueued () { return flags & RESIZE_QUEUED; }
+ inline bool extremesQueued () { return flags & EXTREMES_QUEUED; }
+ inline bool needsResize () { return flags & NEEDS_RESIZE; }
+ inline bool needsAllocate () { return flags & NEEDS_ALLOCATE; }
+ inline bool allocateQueued () { return flags & ALLOCATE_QUEUED; }
+ inline bool extremesChanged () { return flags & EXTREMES_CHANGED; }
+ inline bool wasAllocated () { return flags & WAS_ALLOCATED; }
+
+ void setParent (Widget *parent);
+ void setQuasiParent (Widget *quasiParent);
+
+ void setGenerator (Widget *generator) { this->generator = generator; }
+
+ inline style::Style *getStyle () { return style; }
+ /** \todo I do not like this. */
+ inline Allocation *getAllocation () { return &allocation; }
+
+ inline int boxOffsetX ()
+ { return extraSpace.left + getStyle()->boxOffsetX (); }
+ inline int boxRestWidth ()
+ { return extraSpace.right + getStyle()->boxRestWidth (); }
+ inline int boxDiffWidth () { return boxOffsetX () + boxRestWidth (); }
+ inline int boxOffsetY ()
+ { return extraSpace.top + getStyle()->boxOffsetY (); }
+ inline int boxRestHeight ()
+ { return extraSpace.bottom + getStyle()->boxRestHeight (); }
+ inline int boxDiffHeight () { return boxOffsetY () + boxRestHeight (); }
+
+ void sizeRequest (Requisition *requisition);
+ void getExtremes (Extremes *extremes);
+ void sizeAllocate (Allocation *allocation);
+
+ int getAvailWidth (bool forceValue);
+ int getAvailHeight (bool forceValue);
+ virtual bool getAdjustMinWidth () { return Widget::adjustMinWidth; }
+ void correctRequisition (Requisition *requisition,
+ void (*splitHeightFun) (int, int*, int*));
+ void correctExtremes (Extremes *extremes);
+ int calcWidth (style::Length cssValue, int refWidth, Widget *refWidget,
+ int limitMinWidth, bool forceValue);
+ void calcFinalWidth (style::Style *style, int refWidth, Widget *refWidget,
+ int limitMinWidth, bool forceValue, int *finalWidth);
+ int calcHeight (style::Length cssValue, bool usePercentage, int refHeight,
+ Widget *refWidget, bool forceValue);
+
+ virtual int applyPerWidth (int containerWidth, style::Length perWidth);
+ virtual int applyPerHeight (int containerHeight, style::Length perHeight);
+
+ virtual bool isBlockLevel ();
+ virtual bool isPossibleContainer ();
+
+ void containerSizeChanged ();
+
+ bool intersects (Rectangle *area, Rectangle *intersection);
+
+ /** Area is given in widget coordinates. */
+ virtual void draw (View *view, Rectangle *area) = 0;
+
+ bool buttonPress (EventButton *event);
+ bool buttonRelease (EventButton *event);
+ bool motionNotify (EventMotion *event);
+ void enterNotify (EventCrossing *event);
+ void leaveNotify (EventCrossing *event);
+
+ virtual void setStyle (style::Style *style);
+ void setBgColor (style::Color *bgColor);
+ style::Color *getBgColor ();
+
+ void drawBox (View *view, style::Style *style, Rectangle *area,
+ int x, int y, int width, int height, bool inverse);
+ void drawWidgetBox (View *view, Rectangle *area, bool inverse);
+ void drawSelected (View *view, Rectangle *area);
+
+ void setButtonSensitive (bool buttonSensitive);
+ inline bool isButtonSensitive () { return buttonSensitive; }
+
+ inline Widget *getParent () { return parent; }
+ inline Widget *getContainer () { return container; }
+ Widget *getTopLevel ();
+ int getLevel ();
+ int getGeneratorLevel ();
+ Widget *getNearestCommonAncestor (Widget *otherWidget);
+
+ inline Widget *getGenerator () { return generator ? generator : parent; }
+
+ inline Layout *getLayout () { return layout; }
+
+ virtual Widget *getWidgetAtPoint (int x, int y, int level);
+
+ void scrollTo (HPosition hpos, VPosition vpos);
+ void scrollTo (HPosition hpos, VPosition vpos,
+ int x, int y, int width, int height);
+
+ void getPaddingArea (int *xPad, int *yPad, int *widthPad, int *heightPad);
+
+ /**
+ * \brief Return an iterator for this widget.
+ *
+ * \em mask can narrow the types returned by the iterator, this can
+ * enhance performance quite much, e.g. when only searching for child
+ * widgets.
+ *
+ * With \em atEnd == false, the iterator starts \em before the beginning,
+ * i.e. the first call of dw::core::Iterator::next will let the iterator
+ * point on the first piece of contents. Likewise, With \em atEnd == true,
+ * the iterator starts \em after the last piece of contents, call
+ * dw::core::Iterator::prev in this case.
+ */
+ virtual Iterator *iterator (Content::Type mask, bool atEnd) = 0;
+ virtual void removeChild (Widget *child);
+};
+
+void splitHeightPreserveAscent (int height, int *ascent, int *descent);
+void splitHeightPreserveDescent (int height, int *ascent, int *descent);
+
+} // namespace core
+} // namespace dw
+
+#endif // __DW_WIDGET_HH__
diff --git a/dwr/Makefile.am b/dwr/Makefile.am
new file mode 100644
index 0000000..afd9925
--- /dev/null
+++ b/dwr/Makefile.am
@@ -0,0 +1,31 @@
+AM_CPPFLAGS = \
+ -I$(top_srcdir) \
+ -DCUR_WORKING_DIR='"@BASE_CUR_WORKING_DIR@/dwr"'
+
+noinst_LIBRARIES = \
+ libDw-rtfl.a
+
+libDw_rtfl_a_SOURCES = \
+ box.hh \
+ box.cc \
+ graph.hh \
+ graph.cc \
+ hbox.hh \
+ hbox.cc \
+ hideable.hh \
+ hideable.cc \
+ label.hh \
+ label.cc \
+ toggle.hh \
+ toggle.cc \
+ tools.hh \
+ tools.cc \
+ vbox.hh \
+ vbox.cc
+
+if USE_GRAPH2
+libDw_rtfl_a_SOURCES += \
+ graph2.hh \
+ graph2.cc \
+ graph2_iterator.cc
+endif
diff --git a/dwr/box.cc b/dwr/box.cc
new file mode 100644
index 0000000..2e72866
--- /dev/null
+++ b/dwr/box.cc
@@ -0,0 +1,258 @@
+/*
+ * RTFL
+ *
+ * Copyright 2013-2015 Sebastian Geerken <sgeerken@dillo.org>
+ *
+ * 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; with the following exception:
+ *
+ * The copyright holders of RTFL give you permission to link this file
+ * statically or dynamically against all versions of the graphviz
+ * library, which are published by AT&T Corp. under one of the following
+ * licenses:
+ *
+ * - Common Public License version 1.0 as published by International
+ * Business Machines Corporation (IBM), or
+ * - Eclipse Public License version 1.0 as published by the Eclipse
+ * Foundation.
+ *
+ * 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/>.
+ */
+
+#include <math.h>
+
+#include "box.hh"
+
+using namespace dw::core;
+using namespace dw::core::style;
+using namespace lout::container::typed;
+using namespace lout::misc;
+
+namespace rtfl {
+
+namespace dw {
+
+int Box::CLASS_ID = -1;
+
+#define LT(n) n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n
+
+const char Box::countZeroTable[256] = {
+ 8, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4,
+ LT(3), LT(2), LT(2), LT(1), LT(1), LT(1), LT(1),
+ LT(0), LT(0), LT(0), LT(0), LT(0), LT(0), LT(0), LT(0)
+};
+
+// ----------------------------------------------------------------------
+
+Box::BoxIterator::BoxIterator (Box *box, Content::Type mask,
+ bool atEnd) : Iterator (box, mask, atEnd)
+{
+ index = atEnd ? box->children->size() : -1;
+ content.type = atEnd ? Content::END : Content::START;
+}
+
+Box::BoxIterator::BoxIterator (Box *box, Content::Type mask,
+ int index) : Iterator (box, mask, false)
+{
+ this->index = index;
+
+ if (index < 0)
+ content.type = Content::START;
+ else if (index >= box->children->size ())
+ content.type = Content::END;
+ else {
+ content.type = Content::WIDGET_IN_FLOW;
+ content.widget = box->children->get (index);
+ }
+}
+
+lout::object::Object *Box::BoxIterator::clone ()
+{
+ return new BoxIterator ((Box*)getWidget(), getMask(), index);
+}
+
+int Box::BoxIterator::compareTo (lout::object::Comparable *other)
+{
+ return index - ((BoxIterator*)other)->index;
+}
+
+bool Box::BoxIterator::next ()
+{
+ Box *box = (Box*)getWidget();
+
+ if (content.type == Content::END)
+ return false;
+
+ // boxs only contain widgets:
+ if ((getMask() & Content::WIDGET_IN_FLOW) == 0) {
+ content.type = Content::END;
+ return false;
+ }
+
+ index++;
+ if (index >= box->children->size ()) {
+ content.type = Content::END;
+ return false;
+ } else {
+ content.type = Content::WIDGET_IN_FLOW;
+ content.widget = box->children->get (index);
+ return true;
+ }
+}
+
+bool Box::BoxIterator::prev ()
+{
+ Box *box = (Box*)getWidget();
+
+ if (content.type == Content::START)
+ return false;
+
+ // boxs only contain widgets:
+ if ((getMask() & Content::WIDGET_IN_FLOW) == 0) {
+ content.type = Content::START;
+ return false;
+ }
+
+ index--;
+ if (index < 0) {
+ content.type = Content::START;
+ return false;
+ } else {
+ content.type = Content::WIDGET_IN_FLOW;
+ content.widget = box->children->get (index);
+ return true;
+ }
+}
+
+void Box::BoxIterator::highlight (int start, int end, HighlightLayer layer)
+{
+ /** todo Needs this an implementation? */
+}
+
+void Box::BoxIterator::unhighlight (int direction, HighlightLayer layer)
+{
+ /** todo Needs this an implementation? */
+}
+
+void Box::BoxIterator::getAllocation (int start, int end,
+ Allocation *allocation)
+{
+ /** \bug Not implemented. */
+}
+
+// ----------------------------------------------------------------------
+
+Box::Box (bool stretchChildren)
+{
+ DBG_OBJ_CREATE ("rtfl::dw::Box");
+ registerName ("rtfl::dw::Box", &CLASS_ID);
+
+ this->stretchChildren = stretchChildren;
+ children = new Vector<Widget> (4, true);
+ inDestructor = false;
+}
+
+Box::~Box ()
+{
+ inDestructor = true;
+ delete children;
+
+ DBG_OBJ_DELETE ();
+}
+
+void Box::sizeRequestImplImpl (Requisition *requisition)
+{
+ actualSizeRequestImplImpl (requisition, 0);
+}
+
+void Box::actualSizeRequestImplImpl (::dw::core::Requisition *requisition,
+ int data1)
+{
+ // "data1" is a value passed from a special implementation of
+ // sizeRequestImplImpl to accumulateSize. See VBox for an example
+ // on usage. Extend by "data2" ... when needed.
+
+ requisition->width = requisition->ascent = requisition->descent = 0;
+
+ for (int i = 0; i < children->size (); i++) {
+ Requisition childReq;
+ children->get(i)->sizeRequest (&childReq);
+ accumulateSize (i, children->size (), requisition, &childReq, data1);
+ }
+
+ requisition->width += getStyle()->boxDiffWidth ();
+ requisition->ascent += getStyle()->boxOffsetY ();
+ requisition->descent += getStyle()->boxRestHeight ();
+}
+
+void Box::getExtremesImplImpl (Extremes *extremes)
+{
+ extremes->minWidth = extremes->maxWidth = 0;
+
+ for (int i = 0; i < children->size (); i++) {
+ Extremes childExtr;
+ children->get(i)->getExtremes (&childExtr);
+ accumulateExtremes (i, children->size (), extremes, &childExtr);
+ }
+
+ extremes->minWidth += getStyle()->boxDiffWidth ();
+ extremes->maxWidth += getStyle()->boxDiffWidth ();
+}
+
+void Box::drawImpl (View *view, Rectangle *area)
+{
+ DBG_OBJ_ENTER ("draw", 0, "draw", "%d, %d, %d * %d",
+ area->x, area->y, area->width, area->height);
+
+ drawWidgetBox (view, area, false);
+ for (int i = 0; i < children->size (); i++) {
+ Widget *child = children->get (i);
+ Rectangle childArea;
+ if (child->intersects (area, &childArea))
+ child->draw (view, &childArea);
+ }
+
+ DBG_OBJ_LEAVE ();
+}
+
+::dw::core::Iterator *Box::iterator (Content::Type mask, bool atEnd)
+{
+ return new BoxIterator (this, mask, atEnd);
+}
+
+void Box::removeChild (Widget *child)
+{
+ if (!inDestructor) {
+ for (int i = 0; i < children->size (); i++) {
+ if (children->get (i) == child) {
+ children->remove (i);
+ return;
+ }
+ }
+
+ assertNotReached ();
+ }
+}
+
+void Box::addChild (Widget *widget, int newPos)
+{
+ if (newPos == -1)
+ children->put (widget);
+ else
+ children->insert (widget, newPos);
+
+ widget->setParent (this);
+ queueResize (0, true);
+}
+
+} // namespace rtfl
+
+} // namespace dw
diff --git a/dwr/box.hh b/dwr/box.hh
new file mode 100644
index 0000000..2fe5b2b
--- /dev/null
+++ b/dwr/box.hh
@@ -0,0 +1,110 @@
+#ifndef __DWR_BOX_HH__
+#define __DWR_BOX_HH__
+
+#include "hideable.hh"
+
+namespace rtfl {
+
+namespace dw {
+
+class Box: public Hideable
+{
+private:
+ class BoxIterator: public ::dw::core::Iterator
+ {
+ private:
+ int index;
+
+ BoxIterator (Box *box, ::dw::core::Content::Type mask, int index);
+
+ public:
+ BoxIterator (Box *box, ::dw::core::Content::Type mask, bool atEnd);
+
+ lout::object::Object *clone ();
+ int compareTo (lout::object::Comparable *other);
+
+ bool next ();
+ bool prev ();
+ void highlight (int start, int end, ::dw::core::HighlightLayer layer);
+ void unhighlight (int direction, ::dw::core::HighlightLayer layer);
+ void getAllocation (int start, int end,
+ ::dw::core::Allocation *allocation);
+ };
+
+ bool inDestructor;
+ static const char countZeroTable[256];
+
+ /**
+ * \brief Calculate the number of bits 0 on the left.
+ *
+ * This is similar to calculating the logarithm base 2 (which finds
+ * the right-most bit 1), and a lookup as described at
+ * <http://graphics.stanford.edu/~seander/bithacks.html#IntegerLogLookup>
+ * is used.
+ */
+ static inline int getZeroBits (int i)
+ {
+ // TODO This should not work for 64 bit integers.
+ unsigned int ih, ilh, ihh;
+ if ((ih = i >> 16))
+ return ((ihh = ih >> 8)) ?
+ countZeroTable[ihh] : 8 + countZeroTable[ih];
+ else
+ return ((ilh = i >> 8)) ?
+ 16 + countZeroTable[ilh] : 24 + countZeroTable[i];
+ }
+
+protected:
+ lout::container::typed::Vector<Widget> *children;
+ bool stretchChildren;
+
+ void sizeRequestImplImpl (::dw::core::Requisition *requisition);
+ void actualSizeRequestImplImpl (::dw::core::Requisition *requisition,
+ int data1);
+ void getExtremesImplImpl (::dw::core::Extremes *extremes);
+
+ void drawImpl (::dw::core::View *view, ::dw::core::Rectangle *area);
+
+ /**
+ * \brief Return a * b / c, but avoid overflow for large a and b.
+ */
+ static inline unsigned int safeATimesBDividedByC (unsigned int a,
+ unsigned int b,
+ unsigned int c)
+ {
+ // TODO This should not work for 64 bit integers.
+ int z = getZeroBits (a) + getZeroBits (b);
+ if (z >= 32)
+ return a * b / c;
+ else {
+ //int n = 32 - z, n1 = n / 2, n2 = (n + 1) / 2;
+ int n = 32 - z, n1 = 0, n2 = n;
+ return (a >> n1) * (b >> n2) / (c >> n);
+ }
+ }
+
+ virtual void accumulateSize (int index, int size,
+ ::dw::core::Requisition *totalReq,
+ ::dw::core::Requisition *childReq,
+ int data1) = 0;
+ virtual void accumulateExtremes (int index, int size,
+ ::dw::core::Extremes *totalExtr,
+ ::dw::core::Extremes *childExtr) = 0;
+
+public:
+ static int CLASS_ID;
+
+ Box (bool stretchChildren);
+ ~Box ();
+
+ ::dw::core::Iterator *iterator (::dw::core::Content::Type mask, bool atEnd);
+ void removeChild (Widget *child);
+
+ void addChild (::dw::core::Widget *widget, int newPos = -1);
+};
+
+} // namespace rtfl
+
+} // namespace dw
+
+#endif // __DWR_BOX_HH__
diff --git a/dwr/graph.cc b/dwr/graph.cc
new file mode 100644
index 0000000..d8a1b35
--- /dev/null
+++ b/dwr/graph.cc
@@ -0,0 +1,642 @@
+/*
+ * RTFL
+ *
+ * Copyright 2013-2015 Sebastian Geerken <sgeerken@dillo.org>
+ *
+ * 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; with the following exception:
+ *
+ * The copyright holders of RTFL give you permission to link this file
+ * statically or dynamically against all versions of the graphviz
+ * library, which are published by AT&T Corp. under one of the following
+ * licenses:
+ *
+ * - Common Public License version 1.0 as published by International
+ * Business Machines Corporation (IBM), or
+ * - Eclipse Public License version 1.0 as published by the Eclipse
+ * Foundation.
+ *
+ * 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/>.
+ */
+
+#include "graph.hh"
+#include "tools.hh"
+
+using namespace dw::core;
+using namespace dw::core::style;
+using namespace lout::container::typed;
+using namespace lout::misc;
+
+namespace rtfl {
+
+namespace dw {
+
+int Graph::CLASS_ID = -1;
+
+// ----------------------------------------------------------------------
+
+// TODO: GraphIterator ignores the text nodes (for references). Are
+// they needed, anyway?
+Graph::GraphIterator::GraphIterator (Graph *graph, Content::Type mask,
+ bool atEnd) : Iterator (graph, mask, atEnd)
+{
+ index = atEnd ? graph->allWidgets->size() : -1;
+ content.type = atEnd ? Content::END : Content::START;
+}
+
+Graph::GraphIterator::GraphIterator (Graph *graph, Content::Type mask,
+ int index) : Iterator (graph, mask, false)
+{
+ this->index = index;
+
+ if (index < 0)
+ content.type = Content::START;
+ else if (index >= graph->allWidgets->size ())
+ content.type = Content::END;
+ else {
+ content.type = Content::WIDGET_IN_FLOW;
+ content.widget = graph->allWidgets->get (index);
+ }
+}
+
+lout::object::Object *Graph::GraphIterator::clone ()
+{
+ return new GraphIterator ((Graph*)getWidget(), getMask(), index);
+}
+
+int Graph::GraphIterator::compareTo (lout::object::Comparable *other)
+{
+ return index - ((GraphIterator*)other)->index;
+}
+
+bool Graph::GraphIterator::next ()
+{
+ Graph *graph = (Graph*)getWidget();
+
+ if (content.type == Content::END)
+ return false;
+
+ // graphs only contain widgets:
+ if ((getMask() & Content::WIDGET_IN_FLOW) == 0) {
+ content.type = Content::END;
+ return false;
+ }
+
+ index++;
+ if (index >= graph->allWidgets->size ()) {
+ content.type = Content::END;
+ return false;
+ } else {
+ content.type = Content::WIDGET_IN_FLOW;
+ content.widget = graph->allWidgets->get (index);
+ return true;
+ }
+}
+
+bool Graph::GraphIterator::prev ()
+{
+ Graph *graph = (Graph*)getWidget();
+
+ if (content.type == Content::START)
+ return false;
+
+ // graphs only contain widgets:
+ if ((getMask() & Content::WIDGET_IN_FLOW) == 0) {
+ content.type = Content::START;
+ return false;
+ }
+
+ index--;
+ if (index < 0) {
+ content.type = Content::START;
+ return false;
+ } else {
+ content.type = Content::WIDGET_IN_FLOW;
+ content.widget = graph->allWidgets->get (index);
+ return true;
+ }
+}
+
+void Graph::GraphIterator::highlight (int start, int end, HighlightLayer layer)
+{
+ /** todo Needs this an implementation? */
+}
+
+void Graph::GraphIterator::unhighlight (int direction, HighlightLayer layer)
+{
+ /** todo Needs this an implementation? */
+}
+
+void Graph::GraphIterator::getAllocation (int start, int end,
+ Allocation *allocation)
+{
+ /** \bug Not implemented. */
+}
+
+// ----------------------------------------------------------------------
+
+Graph::Node::Node (Widget *widget, Node *parent)
+{
+ type = WIDGET;
+ this->widget = widget;
+ this->parent = parent;
+ children = new List<Node> (true);
+}
+
+Graph::Node::Node (const char *text, Node *parent)
+{
+ type = REF;
+ this->text = strdup (text);
+ this->parent = parent;
+ children = new List<Node> (true);
+}
+
+Graph::Node::~Node ()
+{
+ if (type == WIDGET) {
+ if (widget) // see Graph::removeChild
+ delete widget;
+ } else
+ free (text);
+ delete children;
+}
+
+// ----------------------------------------------------------------------
+
+Graph::Graph ()
+{
+ DBG_OBJ_CREATE ("rtfl::dw::Graph");
+ registerName ("rtfl::dw::Graph", &CLASS_ID);
+
+ allWidgets = new Vector<Widget> (4, false);
+ topLevelNodes = new List<Node> (true);
+ refStyle = NULL;
+ pressedRefNode = NULL;
+ inDestructor = false;
+}
+
+Graph::~Graph ()
+{
+ inDestructor = true;
+ delete allWidgets;
+ delete topLevelNodes;
+ if (refStyle)
+ refStyle->unref ();
+
+ DBG_OBJ_DELETE ();
+}
+
+void Graph::sizeRequestImpl (Requisition *requisition)
+{
+ sizeRequest (requisition, topLevelNodes);
+
+ requisition->width += getStyle()->boxDiffWidth ();
+ requisition->ascent += getStyle()->boxOffsetY ();
+ requisition->descent += getStyle()->boxRestHeight ();
+}
+
+void Graph::sizeRequest (Requisition *requisition, List<Node> *list)
+{
+ // For simlicity, descent is set to 0. (Anyway never needed within
+ // RTFL.)
+ requisition->width = requisition->descent = 0;
+ requisition->ascent = max (VDIFF * (list->size () - 1), 0);
+
+ for (lout::container::typed::Iterator<Node> it = list->iterator ();
+ it.hasNext (); ) {
+ Node *node = it.getNext ();
+ Requisition nodeReq;
+ sizeRequest (&nodeReq, node);
+
+ requisition->width = max (requisition->width, nodeReq.width);
+ requisition->ascent += (nodeReq.ascent + nodeReq.descent);
+ }
+}
+
+void Graph::sizeRequest (Requisition *requisition, Node *node)
+{
+ if (node->type == Node::WIDGET)
+ node->widget->sizeRequest (&node->rootReq);
+ else {
+ node->rootReq.width =
+ layout->textWidth (refStyle->font, node->text, strlen (node->text)) +
+ refStyle->boxDiffWidth ();
+ node->rootReq.ascent = refStyle->font->ascent + refStyle->boxOffsetY ();
+ node->rootReq.descent =
+ refStyle->font->descent + refStyle->boxRestHeight ();
+ }
+
+ if (node->children->isEmpty ())
+ *requisition = node->rootReq;
+ else {
+ sizeRequest (&node->childrenReq, node->children);
+
+ requisition->ascent =
+ max (node->rootReq.ascent + node->rootReq.descent,
+ node->childrenReq.ascent + node->childrenReq.descent);
+ requisition->descent = 0;
+ requisition->width =
+ node->rootReq.width + HDIFF + node->childrenReq.width;
+ }
+}
+
+void Graph::getExtremesImpl (Extremes *extremes)
+{
+ getExtremes (extremes, topLevelNodes);
+
+ extremes->minWidth += getStyle()->boxDiffWidth ();
+ extremes->maxWidth += getStyle()->boxDiffWidth ();
+}
+
+void Graph::getExtremes (Extremes *extremes, List<Node> *list)
+{
+ extremes->minWidth = extremes->maxWidth = 0;
+
+ for (lout::container::typed::Iterator<Node> it = list->iterator ();
+ it.hasNext (); ) {
+ Node *node = it.getNext ();
+ Extremes nodeExtr;
+ getExtremes (&nodeExtr, node);
+
+ extremes->minWidth = max (extremes->minWidth, nodeExtr.minWidth);
+ extremes->maxWidth = max (extremes->maxWidth, nodeExtr.maxWidth);
+ }
+}
+
+void Graph::getExtremes (Extremes *extremes, Node *node)
+{
+ Extremes rootExtr;
+ if (node->type == Node::WIDGET)
+ node->widget->getExtremes (&rootExtr);
+ else
+ rootExtr.minWidth = rootExtr.maxWidth =
+ layout->textWidth (refStyle->font, node->text, strlen (node->text)) +
+ refStyle->boxDiffWidth ();
+
+ if (node->children->isEmpty ())
+ *extremes = rootExtr;
+ else {
+ Extremes childrenExtr;
+ getExtremes (&childrenExtr, node->children);
+
+ extremes->minWidth = rootExtr.minWidth + HDIFF + childrenExtr.minWidth;
+ extremes->maxWidth = rootExtr.maxWidth + HDIFF + childrenExtr.maxWidth;
+ }
+}
+
+void Graph::sizeAllocateImpl (Allocation *allocation)
+{
+ // Assumes that sizeRequest has been called before. Only position,
+ // not allocation size, is considered.
+ //printf ("sizeAllocate (%d, %d, ...)\n", allocation->x, allocation->y);
+ sizeAllocate (allocation->x + getStyle()->boxOffsetX (),
+ allocation->y + getStyle()->boxOffsetY (), topLevelNodes);
+}
+
+void Graph::sizeAllocate (int x, int y, List<Node> *list)
+{
+ //printf (" List: sizeAllocate (%d, %d, ...)\n", x, y);
+
+ for (lout::container::typed::Iterator<Node> it = list->iterator ();
+ it.hasNext (); ) {
+ Node *node = it.getNext ();
+ sizeAllocate (x, y, node);
+ int h = node->children->isEmpty () ?
+ node->rootReq.ascent + node->rootReq.descent :
+ max (node->rootReq.ascent + node->rootReq.descent,
+ node->childrenReq.ascent + node->childrenReq.descent);
+ y += (VDIFF + h);
+ }
+}
+
+void Graph::sizeAllocate (int x, int y, Node *node)
+{
+ // Notice that node->childrenReq is undefined when there are no
+ // children.
+
+ node->rootX = x;
+ node->rootY = node->children->isEmpty () ? y :
+ y + max ((node->childrenReq.ascent + node->childrenReq.descent
+ - (node->rootReq.ascent + node->rootReq.descent)) / 2, 0);
+
+
+ if (node->type == Node::WIDGET) {
+ Allocation rootAlloc;
+ rootAlloc.x = node->rootX;
+ rootAlloc.y = node->rootY;
+ rootAlloc.width = node->rootReq.width;
+ rootAlloc.ascent = node->rootReq.ascent;
+ rootAlloc.descent = node->rootReq.descent;
+ node->widget->sizeAllocate (&rootAlloc);
+ }
+
+ if (!node->children->isEmpty ())
+ sizeAllocate (x + HDIFF + node->rootReq.width,
+ y + max ((node->rootReq.ascent + node->rootReq.descent
+ - (node->childrenReq.ascent
+ + node->childrenReq.descent)) / 2, 0),
+ node->children);
+}
+
+void Graph::draw (View *view, Rectangle *area)
+{
+ DBG_OBJ_ENTER ("draw", 0, "draw", "%d, %d, %d * %d",
+ area->x, area->y, area->width, area->height);
+
+ drawWidgetBox (view, area, false);
+ draw (view, area, topLevelNodes);
+
+ DBG_OBJ_LEAVE ();
+}
+
+void Graph::draw (View *view, Rectangle *area, List<Node> *list)
+{
+ for (lout::container::typed::Iterator<Node> it = list->iterator ();
+ it.hasNext (); ) {
+ Node *node = it.getNext ();
+
+ if (node->type == Node::WIDGET) {
+ Rectangle childArea;
+ if (node->widget->intersects (area, &childArea))
+ node->widget->draw (view, &childArea);
+ } else {
+ drawBox (view, refStyle, area, node->rootX, node->rootY,
+ node->rootReq.width,
+ node->rootReq.ascent + node->rootReq.descent, false);
+ view-> drawText (refStyle->font, refStyle->color,
+ Color::SHADING_NORMAL,
+ node->rootX + refStyle->boxOffsetX (),
+ node->rootY + node->rootReq.ascent,
+ node->text, strlen (node->text));
+ }
+
+ drawArrows (view, area, node);
+
+ draw (view, area, node->children);
+ }
+}
+
+void Graph::drawArrows (View *view, Rectangle *area, Node *node)
+{
+ // TODO Regarding "area" could make this faster, especially for
+ // large graphs.
+
+ int x1 = node->rootX + node->rootReq.width;
+ int y1 = node->rootY + (node->rootReq.ascent + node->rootReq.descent) / 2;
+
+ for (lout::container::typed::Iterator<Node> it = node->children->iterator ();
+ it.hasNext (); ) {
+ Node *child = it.getNext ();
+
+ int x2 = child->rootX;
+ int y2 =
+ child->rootY + (child->rootReq.ascent + child->rootReq.descent) / 2;
+
+ view->drawLine (getStyle()->color, Color::SHADING_NORMAL, x1, y1, x2, y2);
+ tools::drawArrowHead (view, getStyle(), x1, y1, x2, y2, AHEADLEN);
+ }
+}
+
+::dw::core::Iterator *Graph::iterator (Content::Type mask, bool atEnd)
+{
+ return new GraphIterator (this, mask, atEnd);
+}
+
+void Graph::removeChild (Widget *child)
+{
+ if (!inDestructor) {
+ Node *node = searchWidget (child);
+ assert (node != NULL);
+ assert (node->type == Node::WIDGET);
+
+ // Otherwise, Node::~Node would delete the widget again:
+ Widget *widget = node->widget;
+ node->widget = NULL;
+
+ // TODO No full implementation, only when all edges have been removed.
+ assert (node->parent == NULL);
+ assert (node->children->isEmpty ());
+
+ bool removed = topLevelNodes->removeRef (node);
+ assert (removed);
+
+ int pos = -1;
+ for (int i = 0; pos == -1 && i < allWidgets->size (); i++) {
+ if (allWidgets->get (i) == widget)
+ pos = i;
+ }
+
+ assert (pos != -1);
+ allWidgets->remove (pos);
+ }
+}
+
+void Graph::setStyle (Style *style)
+{
+ Widget::setStyle (style);
+ if (refStyle == NULL && style != NULL) {
+ refStyle = style;
+ refStyle->ref ();
+ }
+}
+
+Graph::Node *Graph::searchRefNode (MousePositionEvent *event, List<Node> *list)
+{
+ for (lout::container::typed::Iterator<Node> it = list->iterator ();
+ it.hasNext (); ) {
+ Node *node = it.getNext ();
+ if (event->xCanvas >= node->rootX &&
+ event->xCanvas < node->rootX + node->rootReq.width &&
+ event->yCanvas >= node->rootY &&
+ event->yCanvas < node->rootY + node->rootReq.ascent
+ + node->rootReq.descent)
+ return node;
+
+ Node *node2 = searchRefNode (event, node->children);
+ if (node2)
+ return node2;
+ }
+
+ return NULL;
+}
+
+bool Graph::buttonPressImpl (EventButton *event)
+{
+ if (event->button == 1) {
+ pressedRefNode = searchRefNode (event);
+ return pressedRefNode != NULL;
+ } else
+ return false;
+}
+
+bool Graph::buttonReleaseImpl (EventButton *event)
+{
+ if (event->button == 1 && pressedRefNode != NULL) {
+ Node *newRefNode = searchRefNode (event);
+ if (newRefNode == pressedRefNode) {
+ Node *ref = pressedRefNode->reference;
+ scrollTo (HPOS_CENTER, VPOS_CENTER, ref->rootX + getAllocation()->x,
+ ref->rootY + getAllocation()->y, ref->rootReq.width,
+ ref->rootReq.ascent + ref->rootReq.descent);
+ pressedRefNode = NULL;
+ }
+ return true;
+ } else
+ return false;
+}
+
+bool Graph::motionNotifyImpl (::dw::core::EventMotion *event)
+{
+ if ((event->state & BUTTON1_MASK) && pressedRefNode) {
+ Node *newRefNode = searchRefNode (event);
+ if (newRefNode != pressedRefNode)
+ pressedRefNode = NULL;
+ }
+ return false;
+}
+
+void Graph::leaveNotifyImpl (EventCrossing *event)
+{
+ pressedRefNode = NULL;
+}
+
+bool Graph::isAncestorOf (Node *n1, Node *n2)
+{
+ for (Node *node = n2; node; node = node->parent)
+ if (node == n1)
+ return true;
+
+ return false;
+}
+
+void Graph::addReference (Node *from, Node *to)
+{
+ assert (from->type == Node::WIDGET);
+ assert (to->type == Node::WIDGET);
+ //printf ("edge from %s %p to %s %p implemented as reference.\n",
+ // from->widget->getClassName (), from->widget,
+ // to->widget->getClassName (), to->widget);
+
+ Node *ref1 = new Node ("…", from);
+ from->children->append (ref1);
+
+ Node *ref2 = new Node ("…", to);
+ List<Node> *list = to->parent ? to->parent->children : topLevelNodes;
+ list->insertBefore (to, ref2);
+ list->detachRef (to);
+ ref2->children->append (to);
+
+ ref1->reference = ref2;
+ ref2->reference = ref1;
+}
+
+void Graph::addNode (Widget *widget)
+{
+ if (searchWidget (widget))
+ fprintf (stderr, "WARNING: widget %p added twice.\n", widget);
+ else {
+ allWidgets->put (widget);
+ topLevelNodes->append (new Node (widget, NULL));
+ widget->setParent (this);
+ queueResize (0, true);
+ }
+}
+
+void Graph::addEdge (Widget *from, Widget *to)
+{
+ Node *nodeFrom, *nodeTo;
+
+ if ((nodeFrom = searchWidget (from)) == NULL) {
+ fprintf (stderr, "WARNING: adding edge starting from unknown widget %p\n",
+ from);
+ return;
+ }
+
+ if ((nodeTo = searchWidget (to)) == NULL) {
+ fprintf (stderr, "WARNING: adding edge ending in unknown widget %p\n",
+ to);
+ return;
+ }
+
+ if (nodeTo->parent) {
+ if (nodeTo->parent == nodeFrom)
+ fprintf (stderr,
+ "WARNING: edge from widget %p to widget %p added twice.\n",
+ from, to);
+ else {
+ // Second node is already the end of an edge, so no new is
+ // added, but a reference.
+ addReference (nodeFrom, nodeTo);
+ }
+ } else {
+ // Here, nodeTo->parent is NULL.
+ if (isAncestorOf (nodeTo, nodeFrom))
+ // Would cause a cycle otherwise.
+ addReference (nodeFrom, nodeTo);
+ else {
+ topLevelNodes->detachRef (nodeTo);
+ nodeTo->parent = nodeFrom;
+ nodeFrom->children->append (nodeTo);
+ }
+ }
+
+ queueResize (0, true);
+}
+
+void Graph::removeEdge (::dw::core::Widget *from, ::dw::core::Widget *to)
+{
+ Node *nodeFrom, *nodeTo;
+
+ if ((nodeFrom = searchWidget (from)) == NULL) {
+ fprintf (stderr, "WARNING: adding edge starting from unknown widget %p\n",
+ from);
+ return;
+ }
+
+ if ((nodeTo = searchWidget (to)) == NULL) {
+ fprintf (stderr, "WARNING: adding edge ending in unknown widget %p\n",
+ to);
+ return;
+ }
+
+ assertNotReached (); // TODO
+
+ queueResize (0, true);
+}
+
+Graph::Node *Graph::searchWidget (Widget *widget, List<Node> *list)
+{
+ for (lout::container::typed::Iterator<Node> it = list->iterator ();
+ it.hasNext (); ) {
+ Node *node = it.getNext ();
+ if (node->type == Node::WIDGET && node->widget == widget)
+ return node;
+
+ Node *node2 = searchWidget (widget, node->children);
+ if (node2)
+ return node2;
+ }
+
+ return NULL;
+}
+
+void Graph::setRefStyle (::dw::core::style::Style *style)
+{
+ if (refStyle)
+ refStyle->unref ();
+
+ refStyle = style;
+ refStyle->ref ();
+}
+
+} // namespace rtfl
+
+} // namespace dw
diff --git a/dwr/graph.hh b/dwr/graph.hh
new file mode 100644
index 0000000..7e0897e
--- /dev/null
+++ b/dwr/graph.hh
@@ -0,0 +1,126 @@
+#ifndef __DWR_GRAPH_HH__
+#define __DWR_GRAPH_HH__
+
+#include "dw/core.hh"
+#include "lout/misc.hh"
+
+namespace rtfl {
+
+namespace dw {
+
+class Graph: public ::dw::core::Widget
+{
+private:
+ class GraphIterator: public ::dw::core::Iterator
+ {
+ private:
+ int index;
+
+ GraphIterator (Graph *graph, ::dw::core::Content::Type mask, int index);
+
+ public:
+ GraphIterator (Graph *graph, ::dw::core::Content::Type mask, bool atEnd);
+
+ lout::object::Object *clone ();
+ int compareTo (lout::object::Comparable *other);
+
+ bool next ();
+ bool prev ();
+ void highlight (int start, int end, ::dw::core::HighlightLayer layer);
+ void unhighlight (int direction, ::dw::core::HighlightLayer layer);
+ void getAllocation (int start, int end,
+ ::dw::core::Allocation *allocation);
+ };
+
+ class Node: public lout::object::Object
+ {
+ public:
+ enum { WIDGET, REF } type;
+ union {
+ ::dw::core::Widget *widget;
+ struct {
+ char *text;
+ Node *reference;
+ };
+ };
+ Node *parent;
+ lout::container::typed::List<Node> *children;
+
+ int rootX, rootY;
+ ::dw::core::Requisition rootReq, childrenReq;
+
+ Node (::dw::core::Widget *widget, Node *parent);
+ Node (const char *text, Node *parent);
+ ~Node ();
+ };
+
+ enum { HDIFF = 50, VDIFF = 20, AHEADLEN = 10 };
+
+ lout::container::typed::Vector<Widget> *allWidgets;
+ lout::container::typed::List<Node> *topLevelNodes;
+ ::dw::core::style::Style *refStyle;
+ Node *pressedRefNode;
+ bool inDestructor;
+
+ Node *searchWidget (::dw::core::Widget *widget,
+ lout::container::typed::List<Node> *list);
+ inline Node *searchWidget (::dw::core::Widget *widget)
+ { return searchWidget (widget, topLevelNodes); }
+
+ void sizeRequest (::dw::core::Requisition *requisition,
+ lout::container::typed::List<Node> *list);
+ void sizeRequest (::dw::core::Requisition *requisition, Node *node);
+ void getExtremes (::dw::core::Extremes *extremes,
+ lout::container::typed::List<Node> *list);
+ void getExtremes (::dw::core::Extremes *extremes, Node *node);
+ void sizeAllocate (int x, int y, lout::container::typed::List<Node> *list);
+ void sizeAllocate (int x, int y, Node *node);
+
+ void draw (::dw::core::View *view, ::dw::core::Rectangle *area,
+ lout::container::typed::List<Node> *list);
+ void drawArrows (::dw::core::View *view, ::dw::core::Rectangle *area,
+ Node *node);
+
+ bool isAncestorOf (Node *n1, Node *n2);
+ void addReference (Node *from, Node *to);
+
+ // TODO Not very efficient. Since there are not many ref nodes,
+ // they could be kept in one list.
+ Node *searchRefNode (::dw::core::MousePositionEvent *event)
+ { return searchRefNode (event, topLevelNodes); }
+ Node *searchRefNode (::dw::core::MousePositionEvent *event,
+ lout::container::typed::List<Node> *list);
+
+protected:
+ void sizeRequestImpl (::dw::core::Requisition *requisition);
+ void getExtremesImpl (::dw::core::Extremes *extremes);
+ void sizeAllocateImpl (::dw::core::Allocation *allocation);
+
+ bool buttonPressImpl (::dw::core::EventButton *event);
+ bool buttonReleaseImpl (::dw::core::EventButton *event);
+ bool motionNotifyImpl (::dw::core::EventMotion *event);
+ void leaveNotifyImpl (::dw::core::EventCrossing *event);
+
+public:
+ static int CLASS_ID;
+
+ Graph ();
+ ~Graph ();
+
+ void draw (::dw::core::View *view, ::dw::core::Rectangle *area);
+ ::dw::core::Iterator *iterator (::dw::core::Content::Type mask, bool atEnd);
+ void removeChild (Widget *child);
+ void setStyle (::dw::core::style::Style *style);
+
+ void addNode (::dw::core::Widget *widget);
+ void addEdge (::dw::core::Widget *from, ::dw::core::Widget *to);
+ void removeEdge (::dw::core::Widget *from, ::dw::core::Widget *to);
+
+ void setRefStyle (::dw::core::style::Style *style);
+};
+
+} // namespace rtfl
+
+} // namespace dw
+
+#endif // __DWR_GRAPH_HH__
diff --git a/dwr/graph2.cc b/dwr/graph2.cc
new file mode 100644
index 0000000..28f03f9
--- /dev/null
+++ b/dwr/graph2.cc
@@ -0,0 +1,505 @@
+/*
+ * RTFL
+ *
+ * Copyright 2014, 2015 Sebastian Geerken <sgeerken@dillo.org>
+ *
+ * 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; with the following exception:
+ *
+ * The copyright holders of RTFL give you permission to link this file
+ * statically or dynamically against all versions of the graphviz
+ * library, which are published by AT&T Corp. under one of the following
+ * licenses:
+ *
+ * - Common Public License version 1.0 as published by International
+ * Business Machines Corporation (IBM), or
+ * - Eclipse Public License version 1.0 as published by the Eclipse
+ * Foundation.
+ *
+ * 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/>.
+ */
+
+/* ----------------------------------------------------------------------
+
+ This is an experimenal graph widget which replaces the widget Graph
+ currently used by rtfl-objview. It uses Graphviz for layouting; in
+ detail, pixels and points (1 point = 1/72 of an inch) are treated
+ as identical, for attributes "bb", "pos" etc. ("width" and "height"
+ are given in inch, so these values are calculated by division by
+ 72).
+
+ See <http://www.graphviz.org/doc/info/attrs.html> for informations
+ on Graphviz attributes.
+
+ Open issues:
+
+ - The order of the children should be preserved. When B1, B2 and B3
+ are associated to A, in this order, this order should be visible,
+ even at the expense of other factors.
+
+ (My original idea was to implement this widget from scratch,
+ using a force directed approach with
+
+ (i) invisible edges between the "children" (in the example
+ above: B1 -> B2 and B2 -> B3), which cause attraction of
+ the respective nodes in a similar way the visible nodes do
+ ("springs");
+
+ (ii) a homogeneous force field directed to the right and acting
+ on the heads of the *visible* edges, so giving the graph
+ layout an orientation from left to right;
+
+ (iii) a second homogeneous force field directed to the bottom,
+ which acts only on the heads of the *invisible* edges.
+
+ (i) and (iii) would lead to the desired result.)
+
+ Update: setting "ordering" to "out" is a step into this
+ direction. (This seems to enforce the order of the edges, not the
+ nodes.)
+
+ - Configurability: the algorithm (currently "dot") and some more
+ parameters (like "rankdir=LR") could be made configurable.
+
+ ---------------------------------------------------------------------- */
+
+#include "graph2.hh"
+#include "tools.hh"
+#include "../common/tools.hh"
+#include "../lout/misc.hh"
+
+using namespace dw::core;
+using namespace dw::core::style;
+using namespace lout::container::typed;
+using namespace lout::misc;
+
+namespace rtfl {
+
+namespace dw {
+
+int Graph2::CLASS_ID = -1;
+
+Graph2::Node::Node (Graph2 *graph, Widget *widget, int index)
+{
+ this->graph = graph;
+ this->widget = widget;
+ this->index = index;
+
+ initAg ();
+}
+
+Graph2::Node::~Node ()
+{
+ if (widget)
+ delete widget;
+
+ cleanupAg ();
+}
+
+void Graph2::Node::initAg ()
+{
+ assert (graph->graph);
+
+ char buf[64];
+ snprintf (buf, 64, "n%d", index);
+ node = agnode(graph->graph, buf, TRUE);
+ agsafeset (node, (char*)"shape", (char*)"rect", (char*)"");
+}
+
+void Graph2::Node::cleanupAg ()
+{
+ if (node) {
+ assert (graph->graph);
+ agdelete (graph->graph, node);
+ node = NULL;
+ }
+}
+
+Graph2::Edge::Edge (Graph2 *graph, Node *from, Node *to, int index)
+{
+ this->graph = graph;
+ this->from = from;
+ this->to = to;
+ this->index = index;
+
+ initAg ();
+
+ numPoints = numPointsAlloc = 0;
+ pointX = NULL;
+ pointY = NULL;
+ pointType = NULL;
+
+ count = 1;
+}
+
+Graph2::Edge::~Edge ()
+{
+ cleanupAg ();
+ cleanupPoints ();
+}
+
+void Graph2::Edge::initAg ()
+{
+ assert (graph->graph);
+
+ char buf[64];
+ snprintf (buf, 64, "e%d", index);
+ edge = agedge (graph->graph, from->node, to->node, (char*)buf, TRUE);
+}
+
+void Graph2::Edge::cleanupAg ()
+{
+ if (edge) {
+ assert (graph->graph);
+ agdelete (graph->graph, edge);
+ edge = NULL;
+ }
+}
+
+void Graph2::Edge::cleanupPoints ()
+{
+ if (numPointsAlloc > 0) {
+ delete[] pointX;
+ delete[] pointY;
+ delete[] pointType;
+
+ pointX = NULL;
+ pointY = NULL;
+ pointType = NULL;
+
+ numPointsAlloc = 0;
+ }
+}
+
+void Graph2::Edge::setNumPoints (int numPoints)
+{
+ if (numPoints > numPointsAlloc) {
+ cleanupPoints ();
+
+ numPointsAlloc = numPoints;
+
+ pointX = new int[numPointsAlloc];
+ pointY = new int[numPointsAlloc];
+ pointType = new char[numPointsAlloc];
+ }
+
+ this->numPoints = numPoints;
+}
+
+void Graph2::Edge::sortPoints ()
+{
+ // If a start point exists, it is at the beginning. If an end point
+ // exists, it is also at the beginning or follows the start point.
+ // Here, it is moved at the end of the list.
+
+ if ((numPoints >= 1 && pointType[0] == 'e') ||
+ (numPoints >= 2 && pointType[1] == 'e')) {
+ int epos = pointType[0] == 'e' ? 0 : 1;
+ int ex = pointX[epos], ey = pointY[epos];
+
+ for (int i = epos; i < numPoints - 1; i++) {
+ pointX[i] = pointX[i + 1];
+ pointY[i] = pointY[i + 1];
+ pointType[i] = pointType[i + 1];
+ }
+
+ pointX[numPoints - 1] = ex;
+ pointY[numPoints - 1] = ey;
+ pointType[numPoints - 1] = 'e';
+ }
+}
+
+Graph2::Graph2 ()
+{
+ DBG_OBJ_CREATE ("rtfl::dw:"###);
+ registerName ("rtfl::dw::Graph2", &CLASS_ID);
+
+ nodes = new Vector<Node> (4, true);
+ edges = new Vector<Edge> (4, true);
+
+ initAg ();
+}
+
+Graph2::~Graph2 ()
+{
+ inDestructor = true;
+
+ cleanupAg ();
+
+ delete nodes;
+ delete edges;
+
+ DBG_OBJ_DELETE ();
+}
+
+void Graph2::initAg ()
+{
+ gvc = gvContext ();
+ graph = agopen ((char*)"", Agdirected, NULL);
+ agsafeset (graph, (char*)"rankdir", (char*)"LR", (char*)"");
+ agsafeset (graph, (char*)"ordering", (char*)"out", (char*)"");
+
+ for (int i = 0; i < nodes->size (); i++)
+ nodes->get(i)->initAg ();
+
+ for (int i = 0; i < edges->size (); i++)
+ edges->get(i)->initAg ();
+}
+
+void Graph2::cleanupAg ()
+{
+ for (int i = 0; i < nodes->size (); i++)
+ nodes->get(i)->cleanupAg ();
+
+ for (int i = 0; i < edges->size (); i++)
+ edges->get(i)->cleanupAg ();
+
+ if (graph) {
+ agclose (graph);
+ graph = NULL;
+ }
+
+ if (gvc) {
+ gvFreeContext(gvc);
+ gvc = NULL;
+ }
+}
+
+void Graph2::sizeRequestImpl (Requisition *requisition)
+{
+ for (int i = 0; i < nodes->size (); i++) {
+ Node *node = nodes->get (i);
+
+ Requisition childReq;
+ node->widget->sizeRequest (&childReq);
+
+ char buf[64];
+ snprintf (buf, 64, "%f", (float)childReq.width / 72);
+ agsafeset (node->node, (char*)"width", buf, (char*)"");
+ snprintf (buf, 64, "%f",
+ (float)(childReq.ascent + childReq.descent) / 72);
+ agsafeset (node->node, (char*)"height", buf, (char*)"");
+ }
+
+ //puts ("---------- before layouting ----------");
+ //agwrite (graph, stdout);
+
+ gvLayout (gvc, graph, "dot");
+ gvRender(gvc, graph, "dot", NULL);
+ gvFreeLayout(gvc, graph);
+
+ //puts ("---------- after layouting ----------");
+ //agwrite (graph, stdout);
+
+ float x, y, width, height;
+ sscanf (agget (graph, (char*)"bb"), "%f,%f,%f,%f", &x, &y, &width, &height);
+
+ requisition->width = width + getStyle()->boxDiffWidth ();
+ requisition->ascent = height + getStyle()->boxOffsetY ();
+ requisition->descent = getStyle()->boxRestHeight ();
+}
+
+void Graph2::getExtremesImpl (Extremes *extremes)
+{
+ assertNotReached ();
+}
+
+void Graph2::sizeAllocateImpl (Allocation *allocation)
+{
+ //agwrite (graph, stdout);
+
+ Requisition req;
+ sizeRequest (&req);
+
+ for (int i = 0; i < nodes->size (); i++) {
+ Node *node = nodes->get (i);
+
+ Requisition childReq;
+ node->widget->sizeRequest (&childReq);
+
+ float x, y;
+ sscanf (agget (node->node, (char*)"pos"), "%f,%f", &x, &y);
+
+ Allocation childAlloc;
+ childAlloc.x = getStyle()->boxOffsetX () + x - childReq.width / 2;
+ childAlloc.y = getStyle()->boxOffsetY ()
+ + (req.ascent + req.descent - getStyle()->boxDiffHeight ())
+ - y - (childReq.ascent + childReq.descent) / 2;
+ childAlloc.width = childReq.width;
+ childAlloc.ascent = childReq.ascent;
+ childAlloc.descent = childReq.descent;
+ node->widget->sizeAllocate (&childAlloc);
+ }
+
+ for (int i = 0; i < edges->size (); i++) {
+ Edge *edge = edges->get (i);
+
+ char *pos = agget (edge->edge, (char*)"pos");
+ int lenPos = strlen (pos);
+ char *posBuf = new char[lenPos + 1];
+ strncpy (posBuf, pos, lenPos + 1);
+
+ int numSpaces = 0;
+ for (char *s = posBuf; *s; s++)
+ if (*s == ' ')
+ numSpaces++;
+
+ edge->setNumPoints (numSpaces + 1);
+
+ int noPoint = 0;
+ bool atEnd = false;
+ for (char *start = posBuf; !atEnd; ) {
+ char *end = start;
+ while (*end != ' ' && *end != 0)
+ end++;
+ atEnd = (*end == 0);
+
+ *end = 0;
+
+ char pointType, *posStart;
+ if ((start[0] == 's' || start[0] == 'e') && start[1] == ',') {
+ pointType = start[0];
+ posStart = start + 2;
+ } else {
+ pointType = 0;
+ posStart = start;
+ }
+
+ float x, y;
+ sscanf (posStart, "%f,%f", &x, &y);
+
+ edge->pointX[noPoint] = getStyle()->boxOffsetX () + x;
+ edge->pointY[noPoint] = getStyle()->boxOffsetY ()
+ + (req.ascent + req.descent - getStyle()->boxDiffHeight ()) - y;
+ edge->pointType[noPoint] = pointType;
+
+ noPoint++;
+ start = end + 1;
+ }
+
+ edge->sortPoints ();
+
+ delete[] posBuf;
+ }
+}
+
+void Graph2::draw (View *view, Rectangle *area)
+{
+ DBG_OBJ_ENTER ("draw", 0, "draw", "%d, %d, %d * %d",
+ area->x, area->y, area->width, area->height);
+
+ drawWidgetBox (view, area, false);
+
+ for (int i = 0; i < nodes->size (); i++) {
+ Widget *widget = nodes->get(i)->widget;
+ Rectangle childArea;
+ if (widget->intersects (area, &childArea))
+ widget->draw (view, &childArea);
+ }
+
+ for (int i = 0; i < edges->size (); i++) {
+ Edge *edge = edges->get (i);
+
+ tools::drawBSpline (view, getStyle(), 4, edge->numPoints, edge->pointX,
+ edge->pointY);
+
+ for (int j = 0; j < edge->numPoints - 1; j++) {
+ // TODO: arrow heads should only be drawn at the first and the last
+ // point. In this case, the direction is correct; in other cases, the
+ // the points are not even part of the curve.
+
+ if (edge->pointType[j] == 'e')
+ tools::drawArrowHead (view, getStyle (),
+ edge->pointX[j + 1], edge->pointY[j + 1],
+ edge->pointX[j], edge->pointY[j],
+ AHEADLEN);
+
+ if (edge->pointType[j + 1] == 'e')
+ tools::drawArrowHead (view, getStyle (),
+ edge->pointX[j], edge->pointY[j],
+ edge->pointX[j + 1], edge->pointY[j + 1],
+ AHEADLEN);
+ }
+ }
+
+ DBG_OBJ_LEAVE ();
+}
+
+::dw::core::Iterator *Graph2::iterator (Content::Type mask, bool atEnd)
+{
+ return new Graph2Iterator (this, mask, atEnd);
+}
+
+void Graph2::removeChild (Widget *child)
+{
+ if (!inDestructor) {
+ int nodeIndex = searchNodeIndex (child);
+ Node *node = nodes->get (nodeIndex);
+
+ // Otherwise, Node::~Node would delete the widget again:
+ node->widget = NULL;
+
+ for (int i = 0; i < edges->size (); i++) {
+ Edge *edge = edges->get (i);
+ if (edge->from == node || edge->to == node)
+ edges->remove (i);
+ }
+
+ nodes->remove (nodeIndex);
+
+ queueResize (0, true);
+ }
+}
+
+void Graph2::addNode (Widget *widget)
+{
+ Node *node = new Node (this, widget, nodes->size ());
+ nodes->put (node);
+
+ widget->setParent (this);
+
+ queueResize (0, true);
+}
+
+void Graph2::addEdge (Widget *from, Widget *to)
+{
+ for (int i = 0; i < edges->size (); i++) {
+ Edge *edge = edges->get (i);
+ if (edge->from->widget == from && edge->to->widget == to) {
+ edge->count++;
+ printf ("WARNING: Edge already added the %d%s time.\n", edge->count,
+ rtfl::tools::numSuffix (edge->count));
+ return;
+ }
+ }
+
+ Edge *edge =
+ new Edge (this, searchNode (from), searchNode (to), edges->size ());
+ edges->put (edge);
+
+ queueResize (0, true);
+}
+
+int Graph2::searchNodeIndex (Widget *widget)
+{
+ for (int i = 0; i < nodes->size (); i++) {
+ Node *node = nodes->get (i);
+ if (node->widget == widget)
+ return i;
+ }
+
+ assertNotReached ();
+ return 0;
+}
+
+} // namespace rtfl
+
+} // namespace dw
diff --git a/dwr/graph2.hh b/dwr/graph2.hh
new file mode 100644
index 0000000..128ba32
--- /dev/null
+++ b/dwr/graph2.hh
@@ -0,0 +1,122 @@
+#ifndef __DWR_GRAPH2_HH__
+#define __DWR_GRAPH2_HH__
+
+#include <graphviz/gvc.h>
+
+#include "dw/core.hh"
+
+namespace rtfl {
+
+namespace dw {
+
+class Graph2: public ::dw::core::Widget
+{
+private:
+ class Graph2Iterator: public ::dw::core::Iterator
+ {
+ private:
+ int index;
+
+ Graph2Iterator (Graph2 *graph, ::dw::core::Content::Type mask, int index);
+
+ public:
+ Graph2Iterator (Graph2 *graph, ::dw::core::Content::Type mask,
+ bool atEnd);
+
+ lout::object::Object *clone ();
+ int compareTo (lout::object::Comparable *other);
+
+ bool next ();
+ bool prev ();
+ void highlight (int start, int end, ::dw::core::HighlightLayer layer);
+ void unhighlight (int direction, ::dw::core::HighlightLayer layer);
+ void getAllocation (int start, int end,
+ ::dw::core::Allocation *allocation);
+ };
+
+ class Node: public lout::object::Object
+ {
+ private:
+ Graph2 *graph;
+ int index;
+
+ public:
+ Node (Graph2 *graph, Widget *widget, int index);
+ ~Node ();
+
+ void initAg ();
+ void cleanupAg ();
+
+ Widget *widget;
+ Agnode_t *node;
+ };
+
+ class Edge: public lout::object::Object
+ {
+ private:
+ Graph2 *graph;
+ int numPointsAlloc, index;
+
+ void cleanupPoints ();
+
+ public:
+ Edge (Graph2 *graph, Node *from, Node *to, int index);
+ ~Edge ();
+
+ void initAg ();
+ void cleanupAg ();
+
+ void setNumPoints (int numPoints);
+ void sortPoints ();
+
+ Node *from, *to;
+ Agedge_t *edge;
+ int numPoints;
+ int *pointX, *pointY;
+ char *pointType;
+
+ int count;
+ };
+
+ enum { AHEADLEN = 10 };
+
+ Agraph_t *graph;
+ GVC_t *gvc;
+ lout::container::typed::Vector<Node> *nodes;
+ lout::container::typed::Vector<Edge> *edges;
+ bool inDestructor;
+
+ void initAg ();
+ void cleanupAg ();
+
+ int searchNodeIndex (Widget *widget);
+ inline Node *searchNode (Widget *widget)
+ { return nodes->get (searchNodeIndex (widget)); }
+
+protected:
+ void sizeRequestImpl (::dw::core::Requisition *requisition);
+ void getExtremesImpl (::dw::core::Extremes *extremes);
+ void sizeAllocateImpl (::dw::core::Allocation *allocation);
+
+public:
+ static int CLASS_ID;
+
+ Graph2 ();
+ ~Graph2 ();
+
+ void draw (::dw::core::View *view, ::dw::core::Rectangle *area);
+ ::dw::core::Iterator *iterator (::dw::core::Content::Type mask, bool atEnd);
+ void removeChild (Widget *child);
+
+ inline void setRefStyle (::dw::core::style::Style *style)
+ { /* No need anymore. */ }
+
+ void addNode (Widget *widget);
+ void addEdge (::dw::core::Widget *from, ::dw::core::Widget *to);
+};
+
+} // namespace rtfl
+
+} // namespace dw
+
+#endif // __DWR_GRAPH2_HH__
diff --git a/dwr/graph2_iterator.cc b/dwr/graph2_iterator.cc
new file mode 100644
index 0000000..d546d39
--- /dev/null
+++ b/dwr/graph2_iterator.cc
@@ -0,0 +1,139 @@
+/*
+ * RTFL
+ *
+ * Copyright 2014, 2015 Sebastian Geerken <sgeerken@dillo.org>
+ *
+ * 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; with the following exception:
+ *
+ * The copyright holders of RTFL give you permission to link this file
+ * statically or dynamically against all versions of the graphviz
+ * library, which are published by AT&T Corp. under one of the following
+ * licenses:
+ *
+ * - Common Public License version 1.0 as published by International
+ * Business Machines Corporation (IBM), or
+ * - Eclipse Public License version 1.0 as published by the Eclipse
+ * Foundation.
+ *
+ * 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/>.
+ */
+
+#include "graph2.hh"
+
+using namespace dw::core;
+
+namespace rtfl {
+
+namespace dw {
+
+Graph2::Graph2Iterator::Graph2Iterator (Graph2 *graph, Content::Type mask,
+ bool atEnd) :
+ Iterator (graph, mask, atEnd)
+{
+ index = atEnd ? graph->nodes->size() : -1;
+ content.type = atEnd ? Content::END : Content::START;
+}
+
+Graph2::Graph2Iterator::Graph2Iterator (Graph2 *graph, Content::Type mask,
+ int index) :
+ Iterator (graph, mask, false)
+{
+ this->index = index;
+
+ if (index < 0)
+ content.type = Content::START;
+ else if (index >= graph->nodes->size ())
+ content.type = Content::END;
+ else {
+ content.type = Content::WIDGET_IN_FLOW;
+ content.widget = graph->nodes->get(index)->widget;
+ }
+}
+
+lout::object::Object *Graph2::Graph2Iterator::clone ()
+{
+ return new Graph2Iterator ((Graph2*)getWidget(), getMask(), index);
+}
+
+int Graph2::Graph2Iterator::compareTo (lout::object::Comparable *other)
+{
+ return index - ((Graph2Iterator*)other)->index;
+}
+
+bool Graph2::Graph2Iterator::next ()
+{
+ Graph2 *graph = (Graph2*)getWidget();
+
+ if (content.type == Content::END)
+ return false;
+
+ // graphs only contain widgets:
+ if ((getMask() & Content::WIDGET_IN_FLOW) == 0) {
+ content.type = Content::END;
+ return false;
+ }
+
+ index++;
+ if (index >= graph->nodes->size ()) {
+ content.type = Content::END;
+ return false;
+ } else {
+ content.type = Content::WIDGET_IN_FLOW;
+ content.widget = graph->nodes->get(index)->widget;
+ return true;
+ }
+}
+
+bool Graph2::Graph2Iterator::prev ()
+{
+ Graph2 *graph = (Graph2*)getWidget();
+
+ if (content.type == Content::START)
+ return false;
+
+ // graphs only contain widgets:
+ if ((getMask() & Content::WIDGET_IN_FLOW) == 0) {
+ content.type = Content::START;
+ return false;
+ }
+
+ index--;
+ if (index < 0) {
+ content.type = Content::START;
+ return false;
+ } else {
+ content.type = Content::WIDGET_IN_FLOW;
+ content.widget = graph->nodes->get(index)->widget;
+ return true;
+ }
+}
+
+void Graph2::Graph2Iterator::highlight (int start, int end,
+ HighlightLayer layer)
+{
+ /** todo Needs this an implementation? */
+}
+
+void Graph2::Graph2Iterator::unhighlight (int direction, HighlightLayer layer)
+{
+ /** todo Needs this an implementation? */
+}
+
+void Graph2::Graph2Iterator::getAllocation (int start, int end,
+ Allocation *allocation)
+{
+ /** \bug Not implemented. */
+}
+
+} // namespace rtfl
+
+} // namespace dw
diff --git a/dwr/hbox.cc b/dwr/hbox.cc
new file mode 100644
index 0000000..6184078
--- /dev/null
+++ b/dwr/hbox.cc
@@ -0,0 +1,123 @@
+/*
+ * RTFL
+ *
+ * Copyright 2013-2015 Sebastian Geerken <sgeerken@dillo.org>
+ *
+ * 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; with the following exception:
+ *
+ * The copyright holders of RTFL give you permission to link this file
+ * statically or dynamically against all versions of the graphviz
+ * library, which are published by AT&T Corp. under one of the following
+ * licenses:
+ *
+ * - Common Public License version 1.0 as published by International
+ * Business Machines Corporation (IBM), or
+ * - Eclipse Public License version 1.0 as published by the Eclipse
+ * Foundation.
+ *
+ * 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/>.
+ */
+
+#include "hbox.hh"
+
+using namespace dw::core;
+using namespace lout::misc;
+
+namespace rtfl {
+
+namespace dw {
+
+int HBox::CLASS_ID = -1;
+
+HBox::HBox (bool stretchChildren): Box (stretchChildren)
+{
+ DBG_OBJ_CREATE ("rtfl::dw::HBox");
+ registerName ("rtfl::dw::HBox", &CLASS_ID);
+}
+
+HBox::~HBox ()
+{
+ DBG_OBJ_DELETE ();
+}
+
+void HBox::sizeAllocateImpl (Allocation *allocation)
+{
+ Allocation allocWOBorders;
+ allocWOBorders.x = allocation->x + getStyle()->boxOffsetX ();
+ allocWOBorders.y = allocation->y + getStyle()->boxOffsetY ();
+ allocWOBorders.width = allocation->width - getStyle()->boxDiffWidth ();
+ allocWOBorders.ascent = allocation->ascent - getStyle()->boxOffsetY ();
+ allocWOBorders.descent = allocation->descent - getStyle()->boxRestHeight ();
+
+ int sumReqWidth = 0;
+ for (int i = 0; i < children->size (); i++) {
+ Requisition childReq;
+ children->get(i)->sizeRequest (&childReq);
+ sumReqWidth += childReq.width;
+ }
+
+ bool stretch = stretchChildren && sumReqWidth < allocWOBorders.width;
+
+ // Cf. doc/rounding-errors.doc, with: x[i] = child requisition,
+ // y[i] = child allocation, a = total allocation, b = sumReqWidth.
+ int cumChildReqWidth = 0, cumChildAllocWidth = 0;
+ for (int i = 0; i < children->size (); i++) {
+ Widget *child = children->get (i);
+
+ Requisition childReq;
+ child->sizeRequest (&childReq);
+
+ Allocation childAlloc;
+ childAlloc.x = allocWOBorders.x + cumChildAllocWidth;
+ childAlloc.y = allocWOBorders.y;
+
+ if (stretch) {
+ cumChildReqWidth += childReq.width;
+ childAlloc.width = sumReqWidth > 0 ?
+ safeATimesBDividedByC (cumChildReqWidth, allocWOBorders.width,
+ sumReqWidth) - cumChildAllocWidth :
+ 0;
+ childAlloc.ascent = allocWOBorders.ascent;
+ childAlloc.descent = allocWOBorders.descent;
+ } else
+ childAlloc.width = childReq.width;
+
+ childAlloc.ascent = allocWOBorders.ascent;
+ childAlloc.descent = allocWOBorders.descent;
+ cumChildAllocWidth += childAlloc.width;
+
+ child->sizeAllocate (&childAlloc);
+
+ //printf ("hbox: %dth child at (%d, %d), %d, (%d x %d)\n",
+ // i, childAlloc.x, childAlloc.y, childAlloc.width,
+ // childAlloc.ascent, childAlloc.descent);
+ }
+}
+
+void HBox::accumulateSize (int index, int size, Requisition *totalReq,
+ Requisition *childReq, int data1)
+{
+ totalReq->width += childReq->width;
+ totalReq->ascent = max (totalReq->ascent, childReq->ascent);
+ totalReq->descent = max (totalReq->descent, childReq->descent);
+}
+
+void HBox::accumulateExtremes (int index, int size, Extremes *totalExtr,
+ Extremes *childExtr)
+{
+ totalExtr->minWidth += childExtr->minWidth;
+ totalExtr->maxWidth += childExtr->maxWidth;
+}
+
+} // namespace rtfl
+
+} // namespace dw
diff --git a/dwr/hbox.hh b/dwr/hbox.hh
new file mode 100644
index 0000000..79b71ff
--- /dev/null
+++ b/dwr/hbox.hh
@@ -0,0 +1,31 @@
+#ifndef __DWR_HBOX_HH__
+#define __DWR_HBOX_HH__
+
+#include "box.hh"
+
+namespace rtfl {
+
+namespace dw {
+
+class HBox: public Box
+{
+protected:
+ void sizeAllocateImpl (::dw::core::Allocation *allocation);
+ void accumulateSize (int index, int size, ::dw::core::Requisition *totalReq,
+ ::dw::core::Requisition *childReq, int data1);
+ void accumulateExtremes (int index, int size,
+ ::dw::core::Extremes *totalExtr,
+ ::dw::core::Extremes *childExtr);
+
+public:
+ static int CLASS_ID;
+
+ HBox (bool stretchChildren);
+ ~HBox ();
+};
+
+} // namespace rtfl
+
+} // namespace dw
+
+#endif // __DWR_HBOX_HH__
diff --git a/dwr/hideable.cc b/dwr/hideable.cc
new file mode 100644
index 0000000..def90a5
--- /dev/null
+++ b/dwr/hideable.cc
@@ -0,0 +1,104 @@
+/*
+ * RTFL
+ *
+ * Copyright 2014, 2015 Sebastian Geerken <sgeerken@dillo.org>
+ *
+ * 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; with the following exception:
+ *
+ * The copyright holders of RTFL give you permission to link this file
+ * statically or dynamically against all versions of the graphviz
+ * library, which are published by AT&T Corp. under one of the following
+ * licenses:
+ *
+ * - Common Public License version 1.0 as published by International
+ * Business Machines Corporation (IBM), or
+ * - Eclipse Public License version 1.0 as published by the Eclipse
+ * Foundation.
+ *
+ * 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/>.
+ */
+
+#include "hideable.hh"
+
+using namespace dw::core;
+using namespace dw::core::style;
+using namespace lout::misc;
+
+namespace rtfl {
+
+namespace dw {
+
+int Hideable::CLASS_ID = -1;
+
+Hideable::Hideable ()
+{
+ DBG_OBJ_CREATE ("rtfl::dw::Hideable");
+ registerName ("rtfl::dw::Hideable", &CLASS_ID);
+
+ hidden = drawable = false;
+}
+
+Hideable::~Hideable ()
+{
+ DBG_OBJ_DELETE ();
+}
+
+void Hideable::sizeRequestImpl (Requisition *requisition)
+{
+ if (hidden) {
+ requisition->width = requisition->ascent = requisition->descent = 0;
+ drawable = false;
+ } else {
+ sizeRequestImplImpl (requisition);
+ drawable = true;
+ }
+}
+
+void Hideable::getExtremesImpl (Extremes *extremes)
+{
+ if (hidden)
+ extremes->minWidth = extremes->minWidthIntrinsic = extremes->maxWidth =
+ extremes->maxWidthIntrinsic = 0;
+ else
+ getExtremesImplImpl (extremes);
+}
+
+void Hideable::draw (View *view, Rectangle *area)
+{
+ DBG_OBJ_ENTER ("draw", 0, "draw", "%d, %d, %d * %d",
+ area->x, area->y, area->width, area->height);
+
+ if (drawable)
+ drawImpl (view, area);
+
+ DBG_OBJ_LEAVE ();
+}
+
+void Hideable::show ()
+{
+ if (hidden) {
+ hidden = false;
+ queueResize (0, true);
+ }
+}
+
+void Hideable::hide ()
+{
+ if (!hidden) {
+ hidden = true;
+ queueResize (0, true);
+ }
+}
+
+} // namespace rtfl
+
+} // namespace dw
diff --git a/dwr/hideable.hh b/dwr/hideable.hh
new file mode 100644
index 0000000..aabf807
--- /dev/null
+++ b/dwr/hideable.hh
@@ -0,0 +1,39 @@
+#ifndef __DWR_HIDEABLE_HH__
+#define __DWR_HIDEABLE_HH__
+
+#include "dw/core.hh"
+
+namespace rtfl {
+
+namespace dw {
+
+class Hideable: public ::dw::core::Widget
+{
+ bool hidden, drawable;
+
+protected:
+ void sizeRequestImpl (::dw::core::Requisition *requisition);
+ void getExtremesImpl (::dw::core::Extremes *extremes);
+
+ virtual void sizeRequestImplImpl (::dw::core::Requisition *requisition) = 0;
+ virtual void getExtremesImplImpl (::dw::core::Extremes *extremes) = 0;
+ virtual void drawImpl (::dw::core::View *view, ::dw::core::Rectangle *area)
+ = 0;
+
+public:
+ static int CLASS_ID;
+
+ Hideable ();
+ ~Hideable ();
+
+ void draw (::dw::core::View *view, ::dw::core::Rectangle *area);
+
+ void show ();
+ void hide ();
+};
+
+} // namespace rtfl
+
+} // namespace dw
+
+#endif // __DWR_HIDEABLE_HH__
diff --git a/dwr/label.cc b/dwr/label.cc
new file mode 100644
index 0000000..dfef145
--- /dev/null
+++ b/dwr/label.cc
@@ -0,0 +1,378 @@
+/*
+ * RTFL
+ *
+ * Copyright 2013-2015 Sebastian Geerken <sgeerken@dillo.org>
+ *
+ * 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; with the following exception:
+ *
+ * The copyright holders of RTFL give you permission to link this file
+ * statically or dynamically against all versions of the graphviz
+ * library, which are published by AT&T Corp. under one of the following
+ * licenses:
+ *
+ * - Common Public License version 1.0 as published by International
+ * Business Machines Corporation (IBM), or
+ * - Eclipse Public License version 1.0 as published by the Eclipse
+ * Foundation.
+ *
+ * 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/>.
+ */
+
+#include "label.hh"
+
+using namespace dw::core;
+using namespace dw::core::style;
+using namespace lout::misc;
+
+namespace rtfl {
+
+namespace dw {
+
+int Label::CLASS_ID = -1;
+
+// ----------------------------------------------------------------------
+
+Label::LabelIterator::LabelIterator (Label *label, Content::Type mask,
+ bool atEnd) : Iterator (label, mask, atEnd)
+{
+ index = atEnd ? label->words->size() : -1;
+ content.type = atEnd ? Content::END : Content::START;
+}
+
+Label::LabelIterator::LabelIterator (Label *label, Content::Type mask,
+ int index) : Iterator (label, mask, false)
+{
+ this->index = index;
+
+ if (index < 0)
+ content.type = Content::START;
+ else if (index >= label->words->size ())
+ content.type = Content::END;
+ else {
+ content.type = Content::TEXT;
+ content.text = label->words->getRef(index)->text;
+ }
+}
+
+lout::object::Object *Label::LabelIterator::clone()
+{
+ return new LabelIterator ((Label*)getWidget(), getMask(), index);
+}
+
+int Label::LabelIterator::compareTo(lout::object::Comparable *other)
+{
+ return index - ((LabelIterator*)other)->index;
+}
+
+bool Label::LabelIterator::next ()
+{
+ Label *label = (Label*)getWidget();
+
+ if (content.type == Content::END)
+ return false;
+
+ // labels only contain widgets:
+ if ((getMask() & Content::TEXT) == 0) {
+ content.type = Content::END;
+ return false;
+ }
+
+ index++;
+ if (index >= label->words->size ()) {
+ content.type = Content::END;
+ return false;
+ } else {
+ content.type = Content::TEXT;
+ content.text = label->words->getRef(index)->text;
+ return true;
+ }
+}
+
+bool Label::LabelIterator::prev ()
+{
+ Label *label = (Label*)getWidget();
+
+ if (content.type == Content::START)
+ return false;
+
+ // labels only contain widgets:
+ if ((getMask() & Content::TEXT) == 0) {
+ content.type = Content::START;
+ return false;
+ }
+
+ index--;
+ if (index < 0) {
+ content.type = Content::START;
+ return false;
+ } else {
+ content.type = Content::TEXT;
+ content.text = label->words->getRef(index)->text;
+ return true;
+ }
+}
+
+void Label::LabelIterator::highlight (int start, int end, HighlightLayer layer)
+{
+ /** \bug Not implemented. */
+}
+
+void Label::LabelIterator::unhighlight (int direction, HighlightLayer layer)
+{
+ /** \bug Not implemented. */
+}
+
+void Label::LabelIterator::getAllocation (int start, int end,
+ Allocation *allocation)
+{
+ /** \bug Not implemented. */
+}
+
+// ----------------------------------------------------------------------
+
+Label::Label (const char *text, int link)
+{
+ DBG_OBJ_CREATE ("rtfl::dw::Label");
+ registerName ("rtfl::dw::Label", &CLASS_ID);
+
+ words = new SimpleVector<Word> (1);
+
+ for (int i = 0; i < 4; i++)
+ styles[i] = NULL;
+
+ selected = buttonDown = false;
+ this->link = link;
+
+ setText (text);
+}
+
+Label::~Label ()
+{
+ clearWords ();
+ delete words;
+
+ clearStyles ();
+
+ DBG_OBJ_DELETE ();
+}
+
+void Label::setText (const char *text)
+{
+ clearWords ();
+
+ DBG_OBJ_SET_STR ("text", text);
+
+ // Parse text for tags <i>, </i>, <b>, </b>. Very simple, no stack.
+ const char *start = text;
+ int styleIndex = 0;
+ while (*start) {
+ const char *end = start;
+
+ while (!(*end == 0 ||
+ strncmp (end, "<i>", 3) == 0 || strncmp (end, "<b>", 3) == 0 ||
+ strncmp (end, "</i>", 4) == 0 || strncmp (end, "</b>", 4) == 0))
+ end++;
+
+ //printf ("start: '%s', end: '%s'\n", start, end);
+
+ if (end > start) {
+ words->increase ();
+ Word *word = words->getLastRef ();
+ word->text = strndup (start, end - start);
+ word->styleIndex = styleIndex;
+
+ //printf (" new word '%s' with attributes %c%c\n", word->text,
+ // (word->styleIndex & ITALIC) ? 'i' : '-',
+ // (word->styleIndex & BOLD) ? 'b' : '-');
+ }
+
+ if (*end == 0)
+ start = end;
+ else if (strncmp (end, "<i>", 3) == 0) {
+ start = end + 3;
+ styleIndex |= ITALIC;
+ } else if (strncmp (end, "<b>", 3) == 0) {
+ start = end + 3;
+ styleIndex |= BOLD;
+ } else if (strncmp (end, "</i>", 4) == 0) {
+ start = end + 4;
+ styleIndex &= ~ITALIC;
+ } else if (strncmp (end, "</b>", 4) == 0) {
+ start = end + 4;
+ styleIndex &= ~BOLD;
+ } else
+ assertNotReached ();
+ }
+
+ queueResize (0, true);
+}
+
+void Label::clearWords ()
+{
+ for (int i = 0; i < words->size (); i++)
+ free (words->getRef(i)->text);
+ words->setSize (0);
+}
+
+void Label::clearStyles ()
+{
+ for (int i = 0; i < 4; i++)
+ if (styles[i]) {
+ styles[i]->unref ();
+ styles[i] = NULL;
+ }
+}
+
+void Label::ensureStyles ()
+{
+ if (getStyle () && styles[0] == NULL) {
+ styles[0] = getStyle ();
+ styles[0]->ref ();
+
+ for (int i = 1; i < 4; i++) {
+ StyleAttrs styleAttrs = *getStyle ();
+ FontAttrs fontAttrs = *(styleAttrs.font);
+ fontAttrs.weight = (i & BOLD) ? 700 : 400;
+ fontAttrs.style = (i & ITALIC) ? FONT_STYLE_ITALIC : FONT_STYLE_NORMAL;
+ styleAttrs.font = Font::create (layout, &fontAttrs);
+ styles[i] = Style::create (&styleAttrs);
+ }
+ }
+}
+
+void Label::sizeRequestImplImpl (Requisition *requisition)
+{
+ totalSize.width = totalSize.ascent = totalSize.descent = 0;
+
+ if (getStyle ()) {
+ ensureStyles ();
+
+ for (int i = 0; i < words->size (); i++) {
+ Word *word = words->getRef(i);
+ Font *font = styles[(int)word->styleIndex]->font;
+
+ word->size.width =
+ layout->textWidth (font, word->text, strlen (word->text));
+ word->size.ascent = font->ascent;
+ word->size.descent = font->descent;
+
+ totalSize.width += word->size.width;
+ totalSize.ascent = max (totalSize.ascent, word->size.ascent);
+ totalSize.descent = max (totalSize.descent, word->size.descent);
+ }
+ } else
+ totalSize.width = totalSize.ascent = totalSize.descent = 0;
+
+ requisition->width = totalSize.width + getStyle()->boxDiffWidth ();
+ requisition->ascent = totalSize.ascent + getStyle()->boxOffsetY ();
+ requisition->descent = totalSize.descent + getStyle()->boxRestHeight ();
+}
+
+void Label::getExtremesImplImpl (Extremes *extremes)
+{
+ // Not used within RTFL.
+ assertNotReached ();
+}
+
+void Label::drawImpl (View *view, Rectangle *area)
+{
+ DBG_OBJ_ENTER ("drawImpl", 0, "draw", "%d, %d, %d * %d",
+ area->x, area->y, area->width, area->height);
+
+ drawWidgetBox (view, area, selected);
+
+ if (getStyle ()) {
+ ensureStyles ();
+
+ // Could adhere to style::textAlign. This can be used for
+ // centered text:
+ //
+ // int x = getAllocation()->x
+ // + (getAllocation()->width - totalSize.width) / 2;
+ //
+ // Now, only left-aligned text is supported.
+
+ int x = getAllocation()->x + getStyle()->boxOffsetX ();
+
+ // Same for style::valign:
+ //
+ // int baseY = getAllocation()->y
+ // + (getHeight () - (totalSize.ascent + totalSize.descent)) / 2
+ // + totalSize.ascent;
+
+ int baseY =
+ getAllocation()->y + totalSize.ascent + getStyle()->boxOffsetY ();
+
+ for (int i = 0; i < words->size (); i++) {
+ Word *word = words->getRef(i);
+ view-> drawText (styles[(int)word->styleIndex]->font,
+ styles[(int)word->styleIndex]->color,
+ selected ? Color::SHADING_INVERSE
+ : Color::SHADING_NORMAL,
+ x, baseY, word->text, strlen (word->text));
+ x += word->size.width;
+ }
+ }
+
+ DBG_OBJ_LEAVE ();
+}
+
+void Label::leaveNotifyImpl (EventCrossing *event)
+{
+ buttonDown = false;
+}
+
+bool Label::buttonPressImpl (EventButton *event)
+{
+ if (link != -1 && event->button == 1) {
+ buttonDown = true;
+ return true;
+ } else
+ return false;
+}
+
+bool Label::buttonReleaseImpl (EventButton *event)
+{
+ if (link != -1 && event->button == 1) {
+ if (buttonDown)
+ linkEmitter.emitClick (this, link, -1, -1, -1, event);
+ return true;
+ } else
+ return false;
+}
+
+Iterator *Label::iterator (Content::Type mask, bool atEnd)
+{
+ return new LabelIterator (this, mask, atEnd);
+}
+
+void Label::setStyle (Style *style)
+{
+ Widget::setStyle (style);
+ clearStyles ();
+}
+
+void Label::select ()
+{
+ selected = true;
+ queueDraw ();
+}
+
+void Label::unselect ()
+{
+ selected = false;
+ queueDraw ();
+}
+
+} // namespace rtfl
+
+} // namespace dw
diff --git a/dwr/label.hh b/dwr/label.hh
new file mode 100644
index 0000000..8a069b0
--- /dev/null
+++ b/dwr/label.hh
@@ -0,0 +1,87 @@
+#ifndef __DWR_LABEL_HH__
+#define __DWR_LABEL_HH__
+
+#include "dwr/hideable.hh"
+#include "lout/misc.hh"
+
+namespace rtfl {
+
+namespace dw {
+
+class Label: public Hideable
+{
+private:
+ class LabelIterator: public ::dw::core::Iterator
+ {
+ private:
+ int index;
+
+ LabelIterator (Label *label, ::dw::core::Content::Type mask, int index);
+
+ public:
+ LabelIterator (Label *label, ::dw::core::Content::Type mask, bool atEnd);
+
+ lout::object::Object *clone ();
+ int compareTo (lout::object::Comparable *other);
+
+ bool next ();
+ bool prev ();
+ void highlight (int start, int end, ::dw::core::HighlightLayer layer);
+ void unhighlight (int direction, ::dw::core::HighlightLayer layer);
+ void getAllocation (int start, int end,
+ ::dw::core::Allocation *allocation);
+ };
+
+ enum { ITALIC = 2, BOLD = 1 };
+
+ struct Word
+ {
+ char *text;
+ char styleIndex;
+ ::dw::core::Requisition size;
+ };
+
+ ::dw::core::style::Style *styles[4];
+ lout::misc::SimpleVector<Word> *words;
+ ::dw::core::Requisition totalSize;
+ bool selected, buttonDown;
+ int link;
+ ::dw::core::Layout::LinkEmitter linkEmitter;
+
+ void clearWords ();
+ void clearStyles ();
+ void ensureStyles ();
+
+protected:
+ void sizeRequestImplImpl (::dw::core::Requisition *requisition);
+ void getExtremesImplImpl (::dw::core::Extremes *extremes);
+ void drawImpl (::dw::core::View *view, ::dw::core::Rectangle *area);
+
+ bool buttonPressImpl (::dw::core::EventButton *event);
+ bool buttonReleaseImpl (::dw::core::EventButton *event);
+ void leaveNotifyImpl (::dw::core::EventCrossing *event);
+
+public:
+ static int CLASS_ID;
+
+ Label (const char *text, int link = -1);
+ ~Label ();
+
+ void setText (const char *text);
+ inline void setLink (int link) { this->link = link; }
+
+ ::dw::core::Iterator *iterator (::dw::core::Content::Type mask, bool atEnd);
+ void setStyle (::dw::core::style::Style *style);
+
+ void select ();
+ void unselect ();
+
+ inline void connectLink (::dw::core::Layout::LinkReceiver *receiver)
+ { linkEmitter.connectLink (receiver); }
+};
+
+} // namespace rtfl
+
+} // namespace dw
+
+#endif // __DWR_LABEL_HH__
diff --git a/dwr/toggle.cc b/dwr/toggle.cc
new file mode 100644
index 0000000..a400237
--- /dev/null
+++ b/dwr/toggle.cc
@@ -0,0 +1,402 @@
+/*
+ * RTFL
+ *
+ * Copyright 2013-2015 Sebastian Geerken <sgeerken@dillo.org>
+ *
+ * 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; with the following exception:
+ *
+ * The copyright holders of RTFL give you permission to link this file
+ * statically or dynamically against all versions of the graphviz
+ * library, which are published by AT&T Corp. under one of the following
+ * licenses:
+ *
+ * - Common Public License version 1.0 as published by International
+ * Business Machines Corporation (IBM), or
+ * - Eclipse Public License version 1.0 as published by the Eclipse
+ * Foundation.
+ *
+ * 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/>.
+ */
+
+#include <math.h>
+
+#include "toggle.hh"
+
+using namespace dw::core;
+using namespace dw::core::style;
+using namespace lout::misc;
+
+namespace rtfl {
+
+namespace dw {
+
+int Toggle::CLASS_ID = -1;
+
+Toggle::ButtonStyle Toggle::buttonStyle = PLUS_MINUS;
+
+// ----------------------------------------------------------------------
+
+Toggle::ToggleIterator::ToggleIterator (Toggle *toggle, Content::Type mask,
+ bool atEnd) :
+ Iterator (toggle, mask, atEnd)
+{
+ content.type = atEnd ? Content::END : Content::START;
+}
+
+lout::object::Object *Toggle::ToggleIterator::clone ()
+{
+ ToggleIterator *ti =
+ new ToggleIterator ((Toggle*)getWidget(), getMask(), false);
+ ti->content = content;
+ return ti;
+}
+
+int Toggle::ToggleIterator::index ()
+{
+ switch (content.type) {
+ case Content::START:
+ return 0;
+ case Content::WIDGET_IN_FLOW:
+ return content.widget == ((Toggle*)getWidget())->small ? 1 : 2;
+ case Content::END:
+ return 3;
+ default:
+ assertNotReached ();
+ return 0;
+ }
+}
+
+int Toggle::ToggleIterator::compareTo (lout::object::Comparable *other)
+{
+ return index () - ((ToggleIterator*)other)->index ();
+}
+
+bool Toggle::ToggleIterator::next ()
+{
+ Toggle *toggle = (Toggle*)getWidget();
+
+ if (content.type == Content::END)
+ return false;
+
+ // toggles only contain widgets:
+ if ((getMask() & Content::WIDGET_IN_FLOW) == 0) {
+ content.type = Content::END;
+ return false;
+ }
+
+ if (content.type == Content::START) {
+ if (toggle->small != NULL) {
+ content.type = Content::WIDGET_IN_FLOW;
+ content.widget = toggle->small;
+ return true;
+ } else if (toggle->large != NULL) {
+ content.type = Content::WIDGET_IN_FLOW;
+ content.widget = toggle->large;
+ return true;
+ } else {
+ content.type = Content::END;
+ return false;
+ }
+ } else /* if (content.type == Content::WIDGET) */ {
+ if (content.widget == toggle->small && toggle->large != NULL) {
+ content.widget = toggle->large;
+ return true;
+ } else {
+ content.type = Content::END;
+ return false;
+ }
+ }
+}
+
+bool Toggle::ToggleIterator::prev ()
+{
+ Toggle *toggle = (Toggle*)getWidget();
+
+ if (content.type == Content::START)
+ return false;
+
+ // toggles only contain widgets:
+ if ((getMask() & Content::WIDGET_IN_FLOW) == 0) {
+ content.type = Content::START;
+ return false;
+ }
+
+ if (content.type == Content::END) {
+ if (toggle->large != NULL) {
+ content.type = Content::WIDGET_IN_FLOW;
+ content.widget = toggle->large;
+ return true;
+ } else if (toggle->small != NULL) {
+ content.type = Content::WIDGET_IN_FLOW;
+ content.widget = toggle->small;
+ return true;
+ } else {
+ content.type = Content::START;
+ return false;
+ }
+ } else /* if (content.type == Content::WIDGET) */ {
+ if (content.widget == toggle->large && toggle->small != NULL) {
+ content.widget = toggle->small;
+ return true;
+ } else {
+ content.type = Content::START;
+ return false;
+ }
+ }
+}
+
+void Toggle::ToggleIterator::highlight (int start, int end, HighlightLayer layer)
+{
+ /** todo Needs this an implementation? */
+}
+
+void Toggle::ToggleIterator::unhighlight (int direction, HighlightLayer layer)
+{
+ /** todo Needs this an implementation? */
+}
+
+void Toggle::ToggleIterator::getAllocation (int start, int end,
+ Allocation *allocation)
+{
+ /** \bug Not implemented. */
+}
+
+// ----------------------------------------------------------------------
+
+Toggle::Toggle (bool showLarge)
+{
+ DBG_OBJ_CREATE ("rtfl::dw::Toggle");
+ registerName ("rtfl::dw::Toggle", &CLASS_ID);
+
+ this->showLarge = showLarge;
+ small = large = NULL;
+ buttonDown = false;
+}
+
+Toggle::~Toggle ()
+{
+ if (small)
+ delete small;
+ if (large)
+ delete large;
+
+ DBG_OBJ_DELETE ();
+}
+
+void Toggle::sizeRequestImplImpl (Requisition *requisition)
+{
+ Widget *child = showLarge ? large : small;
+ Requisition childReq;
+ if (child)
+ child->sizeRequest (&childReq);
+ else
+ childReq.width = childReq.ascent = childReq.descent = 0;
+
+ int buttonSize = calcButtonSize ();
+ requisition->width =
+ buttonSize + childReq.width + getStyle()->boxDiffWidth ();
+ requisition->ascent =
+ max (buttonSize, childReq.ascent) + getStyle()->boxOffsetY ();
+ requisition->descent = childReq.descent + getStyle()->boxRestHeight ();
+}
+
+
+void Toggle::getExtremesImplImpl (Extremes *extremes)
+{
+ Widget *child = showLarge ? large : small;
+ Extremes childExtr;
+ if (child)
+ child->getExtremes (&childExtr);
+ else
+ childExtr.minWidth = childExtr.maxWidth = 0;
+
+ int buttonSize = calcButtonSize ();
+ extremes->minWidth =
+ buttonSize + childExtr.minWidth + getStyle()->boxDiffWidth ();
+ extremes->maxWidth =
+ buttonSize + childExtr.maxWidth + getStyle()->boxDiffWidth ();
+}
+
+
+void Toggle::sizeAllocateImpl (Allocation *allocation)
+{
+ Widget *visChild = showLarge ? large : small;
+ Widget *invisChild = showLarge ? small : large;
+ Allocation childAlloc;
+ int buttonSize = calcButtonSize ();
+
+ if (visChild) {
+ childAlloc.x = allocation->x + buttonSize + getStyle()->boxOffsetX ();
+ childAlloc.y = allocation->y + getStyle()->boxOffsetY ();
+ childAlloc.width =
+ allocation->width - buttonSize - getStyle()->boxDiffWidth ();
+ childAlloc.ascent = allocation->ascent - getStyle()->boxOffsetY ();
+ childAlloc.descent = allocation->descent - getStyle()->boxRestHeight ();
+ visChild->sizeAllocate (&childAlloc);
+ }
+
+ //printf ("toggle: visible child at (%d, %d), %d, (%d x %d)\n",
+ // childAlloc.x, childAlloc.y, childAlloc.width,
+ // childAlloc.ascent, childAlloc.descent);
+
+ if (invisChild) {
+ // Zero size is used to hide a widget.
+ childAlloc.width = childAlloc.ascent = childAlloc.descent = 0;
+ invisChild->sizeAllocate (&childAlloc);
+ }
+}
+
+void Toggle::drawImpl (View *view, Rectangle *area)
+{
+ DBG_OBJ_ENTER ("draw", 0, "draw", "%d, %d, %d * %d",
+ area->x, area->y, area->width, area->height);
+
+ drawWidgetBox (view, area, false);
+ Widget *child = showLarge ? large : small;
+ Rectangle childArea;
+ if (child && child->intersects (area, &childArea))
+ child->draw (view, &childArea);
+
+ int buttonSize = calcButtonSize ();
+ int x0 = getAllocation()->x + getStyle()->boxOffsetX ();
+ int y0 = getAllocation()->y + getAllocation()->ascent - buttonSize;
+
+ switch (buttonStyle) {
+ case PLUS_MINUS:
+ view->drawLine (getStyle()->color, Color::SHADING_NORMAL,
+ x0 + 1, y0 + buttonSize / 2,
+ x0 + buttonSize - 2, y0 + buttonSize / 2);
+ if (!showLarge)
+ view->drawLine (getStyle()->color, Color::SHADING_NORMAL,
+ x0 + buttonSize / 2, y0 + 1,
+ x0 + buttonSize / 2, y0 + buttonSize - 2);
+ break;
+
+ case TRIANGLE:
+ if (showLarge) {
+ view->drawLine (getStyle()->color, Color::SHADING_NORMAL,
+ x0 + 1, y0 + 1, x0 + buttonSize - 2, y0 + 1);
+ view->drawLine (getStyle()->color, Color::SHADING_NORMAL,
+ x0 + 1, y0 + 1,
+ x0 + buttonSize / 2, y0 + buttonSize - 2);
+ view->drawLine (getStyle()->color, Color::SHADING_NORMAL,
+ x0 + buttonSize - 2, y0 + 1,
+ x0 + buttonSize / 2, y0 + buttonSize - 2);
+ } else {
+ view->drawLine (getStyle()->color, Color::SHADING_NORMAL,
+ x0 + 1, y0 + 1, x0 + 1, y0 + buttonSize - 2);
+ view->drawLine (getStyle()->color, Color::SHADING_NORMAL,
+ x0 + 1, y0 + 1,
+ x0 + buttonSize - 2, y0 + buttonSize / 2);
+ view->drawLine (getStyle()->color, Color::SHADING_NORMAL,
+ x0 + 1, y0 + buttonSize - 2,
+ x0 + buttonSize - 2, y0 + buttonSize / 2);
+ }
+ break;
+ }
+
+ DBG_OBJ_LEAVE ();
+}
+
+::dw::core::Iterator *Toggle::iterator (Content::Type mask, bool atEnd)
+{
+ return new ToggleIterator (this, mask, atEnd);
+}
+
+bool Toggle::insideButton (MousePositionEvent *event)
+{
+ int buttonSize = calcButtonSize ();
+ return
+ event->xWidget >= getStyle()->boxOffsetX () &&
+ event->xWidget < getStyle()->boxOffsetX () + buttonSize &&
+ event->yWidget >= getAllocation()->ascent - buttonSize &&
+ event->yWidget < getAllocation()->ascent;
+}
+
+bool Toggle::buttonPressImpl (EventButton *event)
+{
+ if (event->button == 1 && insideButton (event)) {
+ buttonDown = true;
+ return true;
+ } else
+ return false;
+}
+
+bool Toggle::buttonReleaseImpl (EventButton *event)
+{
+ if (event->button == 1 && insideButton (event)) {
+ if (buttonDown) {
+ showLarge = !showLarge;
+ queueResize (0, true);
+ }
+ return true;
+ } else
+ return false;
+}
+
+bool Toggle::motionNotifyImpl (::dw::core::EventMotion *event)
+{
+ if ((event->state & BUTTON1_MASK) && !insideButton (event))
+ buttonDown = false;
+ return false;
+}
+
+void Toggle::leaveNotifyImpl (EventCrossing *event)
+{
+ buttonDown = false;
+}
+
+void Toggle::removeChild (Widget *child)
+{
+ if (child == small)
+ small = NULL;
+ else if (child == large)
+ large = NULL;
+ else
+ assertNotReached ();
+}
+
+void Toggle::setSmall (Widget *widget)
+{
+ if (small)
+ delete small;
+
+ small = widget;
+ if (small)
+ small->setParent (this);
+
+ if (!showLarge)
+ queueResize (0, true);
+}
+
+void Toggle::setLarge (Widget *widget)
+{
+ if (large)
+ delete large;
+
+ large = widget;
+ if (large)
+ large->setParent (this);
+
+ if (showLarge)
+ queueResize (0, true);
+}
+
+void Toggle::toggle (bool showLarge)
+{
+ this->showLarge = showLarge;
+ queueResize (0, true);
+}
+
+} // namespace rtfl
+
+} // namespace dw
diff --git a/dwr/toggle.hh b/dwr/toggle.hh
new file mode 100644
index 0000000..8962ade
--- /dev/null
+++ b/dwr/toggle.hh
@@ -0,0 +1,77 @@
+#ifndef __DWR_TOGGLE_HH__
+#define __DWR_TOGGLE_HH__
+
+#include "hideable.hh"
+
+namespace rtfl {
+
+namespace dw {
+
+class Toggle: public Hideable
+{
+private:
+ class ToggleIterator: public ::dw::core::Iterator
+ {
+ private:
+ int index ();
+
+ public:
+ ToggleIterator (Toggle *toggle, ::dw::core::Content::Type mask,
+ bool atEnd);
+
+ lout::object::Object *clone ();
+ int compareTo (lout::object::Comparable *other);
+
+ bool next ();
+ bool prev ();
+ void highlight (int start, int end, ::dw::core::HighlightLayer layer);
+ void unhighlight (int direction, ::dw::core::HighlightLayer layer);
+ void getAllocation (int start, int end,
+ ::dw::core::Allocation *allocation);
+ };
+
+ static enum ButtonStyle { PLUS_MINUS, TRIANGLE } buttonStyle;
+
+ bool showLarge, buttonDown;
+ Widget *small, *large;
+
+ bool insideButton (::dw::core::MousePositionEvent *event);
+ inline int calcButtonSize ()
+ { // Always return an odd number.
+ int s = getStyle()->font->ascent; return (s % 2) ? s : s - 1; }
+
+protected:
+ void sizeRequestImplImpl (::dw::core::Requisition *requisition);
+ void getExtremesImplImpl (::dw::core::Extremes *extremes);
+ void sizeAllocateImpl (::dw::core::Allocation *allocation);
+
+ void drawImpl (::dw::core::View *view, ::dw::core::Rectangle *area);
+
+ bool buttonPressImpl (::dw::core::EventButton *event);
+ bool buttonReleaseImpl (::dw::core::EventButton *event);
+ bool motionNotifyImpl (::dw::core::EventMotion *event);
+ void leaveNotifyImpl (::dw::core::EventCrossing *event);
+
+public:
+ static int CLASS_ID;
+
+ Toggle (bool showLarge);
+ ~Toggle ();
+
+ ::dw::core::Iterator *iterator (::dw::core::Content::Type mask, bool atEnd);
+ void removeChild (Widget *child);
+
+ inline ::dw::core::Widget *getSmall () { return small; }
+ inline ::dw::core::Widget *getLarge () { return large; }
+ void setSmall (::dw::core::Widget *widget);
+ void setLarge (::dw::core::Widget *widget);
+
+ inline bool isLargeShown () { return showLarge; }
+ void toggle (bool showLarge);
+};
+
+} // namespace rtfl
+
+} // namespace dw
+
+#endif // __DWR_TOGGLE_HH__
diff --git a/dwr/tools.cc b/dwr/tools.cc
new file mode 100644
index 0000000..d45ebd3
--- /dev/null
+++ b/dwr/tools.cc
@@ -0,0 +1,243 @@
+/*
+ * RTFL
+ *
+ * Copyright 2013-2015 Sebastian Geerken <sgeerken@dillo.org>
+ *
+ * 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; with the following exception:
+ *
+ * The copyright holders of RTFL give you permission to link this file
+ * statically or dynamically against all versions of the graphviz
+ * library, which are published by AT&T Corp. under one of the following
+ * licenses:
+ *
+ * - Common Public License version 1.0 as published by International
+ * Business Machines Corporation (IBM), or
+ * - Eclipse Public License version 1.0 as published by the Eclipse
+ * Foundation.
+ *
+ * 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/>.
+ *
+ * ----------------------------------------------------------------------
+ *
+ * A part of the code was written by Keith Vertanen and has been
+ * released to the public domain; see below.
+ */
+
+#include "tools.hh"
+
+#include <math.h>
+
+using namespace dw::core;
+using namespace dw::core::style;
+
+namespace rtfl {
+
+namespace dw {
+
+namespace tools {
+
+// Used for b-splines, see below.
+struct point {
+ double x;
+ double y;
+ double z;
+};
+
+static void bspline (int n, int t, point *control, point *output,
+ int num_output);
+
+void drawArrowHead (View *view, Style *style,
+ int x1, int y1, int x2, int y2, int aheadlen)
+{
+ if (x1 != x2 || y1 != y2) {
+ // TODO: Use faster algorithm avoding floating point numbers. Also,
+ // regard that using integers could cause overflow errors.
+
+ int l = sqrt ((double)(x2 - x1) * (double)(x2 - x1) +
+ (double)(y2 - y1) * (double)(y2 - y1));
+ int x3 = (aheadlen * x1 + (l - aheadlen) * x2) / l;
+ int y3 = (aheadlen * y1 + (l - aheadlen) * y2) / l;
+
+ int x4 = x3 - (y2 - y3) / 2;
+ int y4 = y3 + (x2 - x3) / 2;
+ view->drawLine (style->color, Color::SHADING_NORMAL, x2, y2, x4, y4);
+
+ int x5 = x3 + (y2 - y3) / 2;
+ int y5 = y3 - (x2 - x3) / 2;
+ view->drawLine (style->color, Color::SHADING_NORMAL, x2, y2, x5, y5);
+ }
+}
+
+void drawBSpline (::dw::core::View *view, ::dw::core::style::Style *style,
+ int degree, int numPoints, int *x, int *y)
+{
+ point *in = new point[numPoints];
+ for (int i = 0; i < numPoints; i++) {
+ in[i].x = x[i];
+ in[i].y = y[i];
+ in[i].z = 0;
+ }
+
+ int numOut = 5 * numPoints;
+ point *out = new point[numOut];
+
+ bspline(numPoints - 1, degree, in, out, numOut);
+
+ for (int i = 0; i < numOut - 1; i++)
+ view->drawLine (style->color, ::dw::core::style::Color::SHADING_NORMAL,
+ out[i].x, out[i].y,
+ out[i + 1].x, out[i + 1].y);
+
+ delete[] in;
+ delete[] out;
+}
+
+/* ----------------------------------------------------------------------
+ The following code was copied from
+ <ftp://ftp.grnet.gr/pub/lang/algorithms/c++/bspline.cpp>.
+
+ It should be modified so that it is better adapted to our needs
+ (no z coordinate, no unnecessary conversion between int and
+ double, etc.)
+ ---------------------------------------------------------------------- */
+
+/*********************************************************************
+
+ Simple b-spline curve algorithm
+
+ Copyright 1994 by Keith Vertanen (vertankd@cda.mrs.umn.edu)
+
+ Released to the public domain (your mileage may vary)
+
+**********************************************************************/
+
+static void compute_intervals(int *u, int n, int t);
+static double blend(int k, int t, int *u, double v);
+static void compute_point(int *u, int n, int t, double v, point *control,
+ point *output);
+
+void bspline(int n, int t, point *control, point *output, int num_output)
+
+/*********************************************************************
+
+Parameters:
+ n - the number of control points minus 1
+ t - the degree of the polynomial plus 1
+ control - control point array made up of point stucture
+ output - array in which the calculate spline points are to be put
+ num_output - how many points on the spline are to be calculated
+
+Pre-conditions:
+ n+2>t (no curve results if n+2<=t)
+ control array contains the number of points specified by n
+ output array is the proper size to hold num_output point structures
+
+
+**********************************************************************/
+
+{
+ int *u;
+ double increment,interval;
+ point calcxyz;
+ int output_index;
+
+ u=new int[n+t+1];
+ compute_intervals(u, n, t);
+
+ increment=(double) (n-t+2)/(num_output-1); // how much parameter goes up each time
+ interval=0;
+
+ for (output_index=0; output_index<num_output-1; output_index++)
+ {
+ compute_point(u, n, t, interval, control, &calcxyz);
+ output[output_index].x = calcxyz.x;
+ output[output_index].y = calcxyz.y;
+ output[output_index].z = calcxyz.z;
+ interval=interval+increment; // increment our parameter
+ }
+ output[num_output-1].x=control[n].x; // put in the last point
+ output[num_output-1].y=control[n].y;
+ output[num_output-1].z=control[n].z;
+
+ delete u;
+}
+
+double blend(int k, int t, int *u, double v) // calculate the blending value
+{
+ double value;
+
+ if (t==1) // base case for the recursion
+ {
+ if ((u[k]<=v) && (v<u[k+1]))
+ value=1;
+ else
+ value=0;
+ }
+ else
+ {
+ if ((u[k+t-1]==u[k]) && (u[k+t]==u[k+1])) // check for divide by zero
+ value = 0;
+ else
+ if (u[k+t-1]==u[k]) // if a term's denominator is zero,use just the other
+ value = (u[k+t] - v) / (u[k+t] - u[k+1]) * blend(k+1, t-1, u, v);
+ else
+ if (u[k+t]==u[k+1])
+ value = (v - u[k]) / (u[k+t-1] - u[k]) * blend(k, t-1, u, v);
+ else
+ value = (v - u[k]) / (u[k+t-1] - u[k]) * blend(k, t-1, u, v) +
+ (u[k+t] - v) / (u[k+t] - u[k+1]) * blend(k+1, t-1, u, v);
+ }
+ return value;
+}
+
+void compute_intervals(int *u, int n, int t) // figure out the knots
+{
+ int j;
+
+ for (j=0; j<=n+t; j++)
+ {
+ if (j<t)
+ u[j]=0;
+ else
+ if ((t<=j) && (j<=n))
+ u[j]=j-t+1;
+ else
+ if (j>n)
+ u[j]=n-t+2; // if n-t=-2 then we're screwed, everything goes to 0
+ }
+}
+
+void compute_point(int *u, int n, int t, double v, point *control,
+ point *output)
+{
+ int k;
+ double temp;
+
+ // initialize the variables that will hold our outputted point
+ output->x=0;
+ output->y=0;
+ output->z=0;
+
+ for (k=0; k<=n; k++)
+ {
+ temp = blend(k,t,u,v); // same blend is used for each dimension coordinate
+ output->x = output->x + (control[k]).x * temp;
+ output->y = output->y + (control[k]).y * temp;
+ output->z = output->z + (control[k]).z * temp;
+ }
+}
+
+} // namespace tools
+
+} // namespace rtfl
+
+} // namespace dw
diff --git a/dwr/tools.hh b/dwr/tools.hh
new file mode 100644
index 0000000..8e7bb2b
--- /dev/null
+++ b/dwr/tools.hh
@@ -0,0 +1,24 @@
+#ifndef __DWR_TOOLS_HH__
+#define __DWR_TOOLS_HH__
+
+#include "dw/core.hh"
+
+namespace rtfl {
+
+namespace dw {
+
+namespace tools {
+
+void drawArrowHead (::dw::core::View *view, ::dw::core::style::Style *style,
+ int x1, int y1, int x2, int y2, int aheadlen);
+
+void drawBSpline (::dw::core::View *view, ::dw::core::style::Style *style,
+ int degree, int numPoints, int *x, int *y);
+
+} // namespace tools
+
+} // namespace rtfl
+
+} // namespace dw
+
+#endif // __DWR_TOOLS_HH__
diff --git a/dwr/vbox.cc b/dwr/vbox.cc
new file mode 100644
index 0000000..6649488
--- /dev/null
+++ b/dwr/vbox.cc
@@ -0,0 +1,164 @@
+/*
+ * RTFL
+ *
+ * Copyright 2013-2015 Sebastian Geerken <sgeerken@dillo.org>
+ *
+ * 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; with the following exception:
+ *
+ * The copyright holders of RTFL give you permission to link this file
+ * statically or dynamically against all versions of the graphviz
+ * library, which are published by AT&T Corp. under one of the following
+ * licenses:
+ *
+ * - Common Public License version 1.0 as published by International
+ * Business Machines Corporation (IBM), or
+ * - Eclipse Public License version 1.0 as published by the Eclipse
+ * Foundation.
+ *
+ * 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/>.
+ */
+
+#include "vbox.hh"
+#include "lout/misc.hh"
+
+using namespace dw::core;
+using namespace lout::misc;
+
+namespace rtfl {
+
+namespace dw {
+
+int VBox::CLASS_ID = -1;
+
+VBox::VBox (bool stretchChildren): Box (stretchChildren)
+{
+ DBG_OBJ_CREATE ("rtfl::dw::VBox");
+ registerName ("rtfl::dw::VBox", &CLASS_ID);
+}
+
+VBox::~VBox ()
+{
+ DBG_OBJ_DELETE ();
+}
+
+int VBox::findFirstVisibleChild ()
+{
+ for (int i = 0; i < children->size (); i++) {
+ Requisition childReq;
+ children->get(i)->sizeRequest (&childReq);
+ if (childReq.ascent > 0 || childReq.descent > 0)
+ return i;
+ }
+
+ return 0;
+}
+
+void VBox::sizeRequestImplImpl (Requisition *requisition)
+{
+ actualSizeRequestImplImpl (requisition, findFirstVisibleChild ());
+}
+
+void VBox::sizeAllocateImpl (Allocation *allocation)
+{
+ // TODO "stretchChildren" is not regarded.
+
+ Allocation allocWOBorders;
+ allocWOBorders.x = allocation->x + getStyle()->boxOffsetX ();
+ allocWOBorders.y = allocation->y + getStyle()->boxOffsetY ();
+ allocWOBorders.width = allocation->width - getStyle()->boxDiffWidth ();
+ allocWOBorders.ascent = allocation->ascent - getStyle()->boxOffsetY ();
+ allocWOBorders.descent = allocation->descent - getStyle()->boxRestHeight ();
+
+ // Unlike HBox, the ascent of the first visible widget (set as
+ // allocation ascent) is treated differently; the distribution is
+ // only done for the rest. Also, the difference is distributed to
+ // ascent (except first widget) and descent independently.
+
+ int sumReqHeight = 0, firstVisibleChild = findFirstVisibleChild ();
+ for (int i = firstVisibleChild; i < children->size (); i++) {
+ Requisition childReq;
+ children->get(i)->sizeRequest (&childReq);
+ if (i > firstVisibleChild)
+ sumReqHeight += childReq.ascent;
+ sumReqHeight += childReq.descent;
+ }
+
+ //bool stretch = stretchChildren && sumReqHeight < allocWOBorders.descent;
+
+ // Cf. doc/rounding-errors.doc, with: x[i] = child requisition,
+ // y[i] = child allocation, a = total allocation, b = sumReqHeight.
+ int cumChildReqHeight = 0, cumChildAllocHeight = 0;
+ for (int i = 0; i < children->size (); i++) {
+ Widget *child = children->get (i);
+
+ Requisition childReq;
+ child->sizeRequest (&childReq);
+
+ Allocation childAlloc;
+ childAlloc.x = allocWOBorders.x;
+ childAlloc.width = allocWOBorders.width;
+
+ if (i == firstVisibleChild) {
+ childAlloc.y = allocWOBorders.y;
+ childAlloc.ascent = allocWOBorders.ascent;
+ } else {
+ childAlloc.y =
+ allocWOBorders.y + allocWOBorders.ascent + cumChildAllocHeight;
+ cumChildReqHeight += childReq.ascent;
+ childAlloc.ascent = sumReqHeight > 0 ?
+ safeATimesBDividedByC (cumChildReqHeight, allocWOBorders.descent,
+ sumReqHeight) - cumChildAllocHeight :
+ 0;
+ cumChildAllocHeight += childAlloc.ascent;
+ }
+
+ cumChildReqHeight += childReq.descent;
+ childAlloc.descent = sumReqHeight > 0 ?
+ safeATimesBDividedByC (cumChildReqHeight, allocWOBorders.descent,
+ sumReqHeight) - cumChildAllocHeight :
+ 0;
+ cumChildAllocHeight += childAlloc.descent;
+
+ child->sizeAllocate (&childAlloc);
+
+ //printf ("vbox: %dth child at (%d, %d), %d, (%d x %d)\n",
+ // i, childAlloc.x, childAlloc.y, childAlloc.width,
+ // childAlloc.ascent, childAlloc.descent);
+
+ }
+}
+
+void VBox::accumulateSize (int index, int size, Requisition *totalReq,
+ Requisition *childReq, int data1)
+{
+ int firstVisibleChild = data1;
+
+ totalReq->width = max (totalReq->width, childReq->width);
+ if (index == firstVisibleChild) {
+ // Resulting baseline is the baseline of the first child.
+ totalReq->ascent = childReq->ascent;
+ totalReq->descent = childReq->descent;
+ } else
+ totalReq->descent += (childReq->ascent + childReq->descent);
+}
+
+
+void VBox::accumulateExtremes (int index, int size, Extremes *totalExtr,
+ Extremes *childExtr)
+{
+ totalExtr->minWidth = max (totalExtr->minWidth, childExtr->minWidth);
+ totalExtr->maxWidth = max (totalExtr->maxWidth, childExtr->maxWidth);
+}
+
+} // namespace rtfl
+
+} // namespace dw
diff --git a/dwr/vbox.hh b/dwr/vbox.hh
new file mode 100644
index 0000000..b586217
--- /dev/null
+++ b/dwr/vbox.hh
@@ -0,0 +1,35 @@
+#ifndef __DWR_VBOX_HH__
+#define __DWR_VBOX_HH__
+
+#include "box.hh"
+
+namespace rtfl {
+
+namespace dw {
+
+class VBox: public Box
+{
+private:
+ int findFirstVisibleChild ();
+
+protected:
+ void sizeRequestImplImpl (::dw::core::Requisition *requisition);
+ void sizeAllocateImpl (::dw::core::Allocation *allocation);
+ void accumulateSize (int index, int size, ::dw::core::Requisition *totalReq,
+ ::dw::core::Requisition *childReq, int data1);
+ void accumulateExtremes (int index, int size,
+ ::dw::core::Extremes *totalExtr,
+ ::dw::core::Extremes *childExtr);
+
+public:
+ static int CLASS_ID;
+
+ VBox (bool stretchChildren);
+ ~VBox ();
+};
+
+} // namespace rtfl
+
+} // namespace dw
+
+#endif // __DWR_VBOX_HH__
diff --git a/java/Hello.java b/java/Hello.java
new file mode 100644
index 0000000..04eadd7
--- /dev/null
+++ b/java/Hello.java
@@ -0,0 +1,21 @@
+package rtfl;
+
+public class Hello
+{
+ int i1;
+ Integer i2;
+ String s1;
+
+ public static void main (String[] args)
+ {
+ new Hello().hello();
+ }
+
+ public void hello()
+ {
+ System.out.println ("===== Hello Java! =====");
+ i1 = 5;
+ i2 = new Integer(7);
+ s1 = "Hi!";
+ }
+}
diff --git a/java/Makefile.am b/java/Makefile.am
new file mode 100644
index 0000000..9d3f511
--- /dev/null
+++ b/java/Makefile.am
@@ -0,0 +1,46 @@
+AM_CFLAGS = -Wall $(JAVA_CFLAGS)
+
+JAVA = $(JAVA_HOME)/jre/bin/java
+JAVAC = $(JAVA_HOME)/bin/javac
+
+lib_LTLIBRARIES = librtfl-jvm-ti.la
+
+librtfl_jvm_ti_la_SOURCES = \
+ main.c \
+ class.h \
+ class.c \
+ method.h \
+ method.c \
+ field.h \
+ field.c \
+ config.h \
+ config.c \
+ misc.h \
+ misc.c
+
+EXTRA_DIST = README Hello.java TestRtflObjects1.java
+
+# Run tests without installation.
+LIBPATH=./.libs
+
+run-hello: $(LIBPATH)/librtfl-jvm-ti.so rtfl/Hello.class
+ LD_LIBRARY_PATH=$(LIBPATH) $(JAVA) -agentlib:rtfl-jvm-ti rtfl.Hello
+
+run-test-rtfl-objects-1: $(LIBPATH)/librtfl-jvm-ti.so rtfl/TestRtflObjects1.class
+ LD_LIBRARY_PATH=$(LIBPATH) $(JAVA) -agentlib:rtfl-jvm-ti rtfl.TestRtflObjects1
+
+run-test-rtfl-objects-2: $(LIBPATH)/librtfl-jvm-ti.so rtfl/TestRtflObjects2.class
+ LD_LIBRARY_PATH=$(LIBPATH) $(JAVA) -agentlib:rtfl-jvm-ti rtfl.TestRtflObjects2
+
+rtfl/Hello.class: Hello.java
+ $(JAVAC) -g -d . Hello.java
+
+rtfl/TestRtflObjects1.class: TestRtflObjects1.java
+ $(JAVAC) -g -d . TestRtflObjects1.java
+
+rtfl/TestRtflObjects2.class: TestRtflObjects2.java
+ $(JAVAC) -g -d . TestRtflObjects2.java
+
+clean-local:
+ find -name "*.class" | xargs rm -f
+
diff --git a/java/README b/java/README
new file mode 100644
index 0000000..e0196a0
--- /dev/null
+++ b/java/README
@@ -0,0 +1,40 @@
+This sub-project aims to provide an agent for the Java Virtual
+Machine, which uses the JVM Tool Interface (see [1] and [2]) to print
+RTFL messages for Java programs, which must not necessarily be
+prepared. This makes using RTFL much less time-consuming and so lowers
+the entrance barrier.
+
+The agent consists of the file "librtfl-jvm-ti.so", which is passed to
+"java" by the option "-agentlib:rtfl-jvm-ti"; see Makefile.am for
+details.
+
+Run "make run-hello" or "run run-test-rtfl-objects-1" to run some
+sample programs with the agent.
+
+
+How it works
+------------
+Several commands from the object module (like "create") follow the
+program structure, and can so easily be printed when the respective
+JVM-TI event is processed. Others (like "enter") can be printed by
+this approach, but some parameters are missing (aspect and priority)
+and so replaced by standard values (empty aspect and priority 0). It
+is planned to make these parameters configurable, either by files or
+by annotations.
+
+A third group of commands (like "msg") must still be added explicitly
+to code. (For "msg", one could think of an integration with existing
+logging frameworks.)
+
+Since Java programs often use many third-party code (libraries,
+containers, ...), it is crucial for the performance to filter quite
+early, and so reduce the total amount of messages. Filtering by
+packages seems feasible (like "com.acme" and sub-packages when code of
+ACME is debugged). Currently, only "rtfl" and its sub-packages are
+considered; this is hard-coded in the function include_class() in
+"config.c".
+
+----------------------------------------------------------------------
+
+[1] http://docs.oracle.com/javase/8/docs/technotes/guides/jvmti/index.html
+[2] http://www.oracle.com/technetwork/articles/javase/jvmti-136367.html
diff --git a/java/TestRtflObjects1.java b/java/TestRtflObjects1.java
new file mode 100644
index 0000000..fece128
--- /dev/null
+++ b/java/TestRtflObjects1.java
@@ -0,0 +1,50 @@
+package rtfl;
+
+import java.util.LinkedList;
+import java.util.List;
+
+public class TestRtflObjects1
+{
+ private static class A
+ {
+ private A other = null;
+ private List<Integer> numbers = new LinkedList<Integer>();
+
+ public void setOther (A other)
+ {
+ this.other = other;
+ }
+
+ public int doSomething (int n)
+ {
+ int r = (int)(Math.random() * 251);
+ numbers.add (new Integer (r));
+
+ if (other != null && n > 0)
+ other.doSomething (n - 1);
+
+ return r;
+ }
+ }
+
+ private static class B extends A
+ {
+ }
+
+ private static class C extends A
+ {
+ }
+
+ public static void main (String[] args)
+ {
+ A x = new A ();
+ B y = new B ();
+ C z = new C ();
+
+ x.setOther (y);
+ y.setOther (z);
+ z.setOther (x);
+
+ x.doSomething (8);
+ }
+}
diff --git a/java/class.c b/java/class.c
new file mode 100644
index 0000000..d4e78ae
--- /dev/null
+++ b/java/class.c
@@ -0,0 +1,39 @@
+#include "class.h"
+#include "config.h"
+#include "misc.h"
+
+void JNICALL class_prepare(jvmtiEnv *jvmti, JNIEnv* jni, jthread thread,
+ jclass klass)
+{
+ jvmtiError error;
+ char *class_sig = NULL, *class_name = NULL;
+
+ if ((error = (*jvmti)->GetClassSignature (jvmti, klass, &class_sig, NULL))
+ != JVMTI_ERROR_NONE)
+ jvmti_error (jvmti, error, "GetClassSignature");
+ else {
+ if ((class_name = get_class_name_from_sig (class_sig, TRUE)) &&
+ include_class (class_name)) {
+ jint field_count;
+ jfieldID* fields;
+ if ((error = (*jvmti)->GetClassFields (jvmti, klass, &field_count,
+ &fields))
+ != JVMTI_ERROR_NONE)
+ jvmti_error (jvmti, error, "GetClassFields");
+ else {
+ int i;
+ for (i = 0; i < field_count; i++) {
+ if ((error =
+ (*jvmti)->SetFieldModificationWatch (jvmti, klass,
+ fields[i]))
+ != JVMTI_ERROR_NONE)
+ jvmti_error (jvmti, error, "SetFieldModificationWatch");
+ }
+ }
+ }
+ }
+
+ jvmti_dealloc (jvmti, class_sig);
+ simple_free (class_name);
+
+}
diff --git a/java/class.h b/java/class.h
new file mode 100644
index 0000000..41ffb74
--- /dev/null
+++ b/java/class.h
@@ -0,0 +1,9 @@
+#ifndef __JAVA_CLASS_H__
+#define __JAVA_CLASS_H__
+
+#include <jvmti.h>
+
+void JNICALL class_prepare(jvmtiEnv *jvmti, JNIEnv* jni, jthread thread,
+ jclass klass);
+
+#endif /* __JAVA_CLASS_H__ */
diff --git a/java/field.c b/java/field.c
new file mode 100644
index 0000000..3427218
--- /dev/null
+++ b/java/field.c
@@ -0,0 +1,156 @@
+#include <string.h>
+#include <stdlib.h>
+
+#include "field.h"
+#include "config.h"
+#include "misc.h"
+
+/* ----------------------------------------------------------------------
+
+ A sketch on how field modifications could be processed:
+
+ A field modification results in a "set" or in an "assoc"
+ command. Neither is the field name *necessarily* the name of the "set"
+ command (or "assoc", if it would support names), nor is the field
+ value necessarily the respective value. Instead, the following rules
+ are used to determine the structure of the fields.
+
+ (A) If the value type is "printable" (i. e. primitive, or a wrapper
+ class for a primitive type, or java.lang.String, or an enum (more
+ cases?)), then a set command is printed, with the name and the value
+ of the field.
+
+ (B) If the value is a visible object, and it is not configured as
+ sub-structure (see below), an "assoc" command is printed, between this
+ object and the value object. (As soon as associations get a name, the
+ field name is used for this.)
+
+ (C) If the value is an invisible object, or a visible object which is
+ configured as sub-structure, regard it as structured, according to the
+ rules which follow.
+
+ Structured values are divided into sub-values with sub-names; the
+ field name, followed by a dot, is used as base-name; all sub-values
+ and sub-names are processed recursively according to the same rules,
+ while the base-name is eventually prepended to all sub-names.
+
+ (C1) If the value is of type java.util.Map, and the keys are printable
+ (see (A)), use the keys as sub-names, the values as sub-values. ("The
+ keys are printable": does this mean that the type for the keys is a
+ class which is generally printable?)
+
+ (C2) If the value is of type java.util.Map, and the keys are not
+ printable (see also C1), regard the value as unsorted list of
+ elements, which are themselves structured sub-values
+ (java.util.Map.Entry?).
+
+ (C3) If the value is of type java.util.List, use the indices as
+ sub-names, and the elements as sub-values.
+
+ (C4) If the value is an unsorted collection, i. e. of type
+ java.util.Collection, but not of java.util.Map or java.util.List,
+ apply a random order and proceed as in (C4). (Unsorted collections are
+ not really supported in RTFL.)
+
+ The rules (C1) to (C4) apply not when configured otherwise ("do not
+ show logical structure").
+
+ (C5) Otherwise (not of type java.util.Collection or java.util.Map),
+ examine fields of the value; regard the names of its fields as
+ sub-names; their values as sub-values;
+
+ (Alternative: Java Beans?)
+
+ For simplification, ignore C1 to C4 in the first place and focus on
+ C5; then implement C1 to C4 by and by.
+
+ ---------------------------------------------------------------------- */
+
+static void print_field (jvmtiEnv *jvmti, JNIEnv* jni, jclass field_klass,
+ jobject object, jfieldID field, jvalue value,
+ char *base_name);
+static void print_string_field (jvmtiEnv *jvmti, JNIEnv* jni, char *object_str,
+ char *base_name, char *field_name,
+ jstring string);
+
+void JNICALL field_modification (jvmtiEnv *jvmti, JNIEnv* jni, jthread thread,
+ jmethodID method, jlocation location,
+ jclass field_klass, jobject object,
+ jfieldID field, char signature_type,
+ jvalue new_value)
+{
+ // The class name is irrelevant here, since classes are already
+ // filtered inclass_prepare(), where SetFieldModificationWatch()
+ // is called.
+
+ print_field (jvmti, jni, field_klass, object, field, new_value, "");
+}
+
+void print_field (jvmtiEnv *jvmti, JNIEnv* jni, jclass field_klass,
+ jobject object, jfieldID field, jvalue value, char *base_name)
+{
+ jvmtiError error;
+ char object_buf1[SIZE_OBJECT_BUF], object_buf2[SIZE_OBJECT_BUF];
+ char *class_name = NULL, *field_name = NULL, *field_sig = NULL;
+
+ if ((error = (*jvmti)->GetFieldName (jvmti, field_klass, field, &field_name,
+ &field_sig, NULL))
+ != JVMTI_ERROR_NONE)
+ jvmti_error (jvmti, error, "GetFieldName");
+ else {
+ //printf ("==> %s - %s\n", field_name, field_sig);
+
+ fill_object_buf (jni, object_buf1, object);
+
+ if ((class_name = get_class_name_from_sig (field_sig, FALSE))) {
+ if (include_class (class_name)) {
+ // The field represents an instance of a class which is also
+ // included: this is an association, not a simple field.
+ // ("field_name" could be used here, as soon as associations get
+ // a name.)
+
+ if (value.l) {
+ fill_object_buf (jni, object_buf2, value.l);
+ RTFL_OBJ_PRINT ("assoc", "s:s", object_buf1, object_buf2);
+ }
+ } else {
+ if (strcmp (class_name, "java.lang.String")) {
+ print_string_field (jvmti, jni, object_buf1, base_name,
+ field_name, (jstring)(value.l));
+
+ }
+ }
+ }
+ }
+
+ jvmti_dealloc (jvmti, field_name);
+ jvmti_dealloc (jvmti, field_sig);
+ simple_free (class_name);
+}
+
+void print_string_field (jvmtiEnv *jvmti, JNIEnv* jni, char *object_str,
+ char *base_name, char *field_name, jstring string)
+{
+ if (string == NULL)
+ RTFL_OBJ_PRINT ("set", "s:ss:s", object_str, base_name, field_name,
+ "null");
+ else {
+ // TODO: JNI calls somehow cause an abortion. Just some test
+ // code.
+
+ //jsize len = (*jni)->GetStringLength (jni, string);
+ //const jchar *chars = (*jni)->GetStringChars (jni, string, NULL);
+
+ //char *chars0 = (char*)malloc (len + 1);
+ //memcpy (chars0, chars, len);
+ //chars0[len] = 0;
+
+ char *chars0 = "?\"?\"?";
+
+ RTFL_OBJ_PRINT ("set", "s:ss:\"q\"", object_str, base_name, field_name,
+ chars0);
+
+ //free (chars0);
+ //(*jni)->ReleaseStringChars (jni, string, chars);
+ }
+}
diff --git a/java/field.h b/java/field.h
new file mode 100644
index 0000000..6d580ee
--- /dev/null
+++ b/java/field.h
@@ -0,0 +1,12 @@
+#ifndef __JAVA_FIELD_H__
+#define __JAVA_FIELD_H__
+
+#include <jvmti.h>
+
+void JNICALL field_modification (jvmtiEnv *jvmti, JNIEnv* jni, jthread thread,
+ jmethodID method, jlocation location,
+ jclass field_klass, jobject object,
+ jfieldID field, char signature_type,
+ jvalue new_value);
+
+#endif /* __JAVA_FIELD_H__ */
diff --git a/java/main.c b/java/main.c
new file mode 100644
index 0000000..dc7e954
--- /dev/null
+++ b/java/main.c
@@ -0,0 +1,68 @@
+#include <jvmti.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "class.h"
+#include "method.h"
+#include "field.h"
+#include "misc.h"
+
+JNIEXPORT jint JNICALL Agent_OnLoad (JavaVM *jvm, char *options, void *reserved)
+{
+ rtfl_print ("obj", RTFL_OBJ_VERSION, "", 0, "s", "noident");
+
+ jvmtiEnv *jvmti = NULL;
+
+ (*jvm)->GetEnv (jvm, (void**)&jvmti, JVMTI_VERSION_1_0);
+
+ jvmtiCapabilities capa;
+ memset (&capa, 0, sizeof(jvmtiCapabilities));
+ capa.can_generate_method_entry_events = 1;
+ capa.can_generate_method_exit_events = 1;
+ capa.can_access_local_variables = 1;
+ capa.can_generate_field_modification_events = 1;
+
+ jvmtiEventCallbacks callbacks;
+ (void)memset(&callbacks, 0, sizeof(callbacks));
+ callbacks.ClassPrepare = &class_prepare;
+ callbacks.MethodEntry = &method_entry;
+ callbacks.MethodExit = &method_exit;
+ callbacks.FieldModification = &field_modification;
+
+ jvmtiError error;
+ if ((error = (*jvmti)->AddCapabilities(jvmti, &capa)) != JVMTI_ERROR_NONE)
+ jvmti_error (jvmti, error, "AddCapabilities");
+ else if ((error =
+ (*jvmti)->SetEventNotificationMode (jvmti, JVMTI_ENABLE,
+ JVMTI_EVENT_CLASS_PREPARE,
+ (jthread)NULL))
+ != JVMTI_ERROR_NONE)
+ jvmti_error (jvmti, error,
+ "SetEventNotificationMode (JVMTI_EVENT_CLASS_PREPARE)");
+ else if ((error =
+ (*jvmti)->SetEventNotificationMode (jvmti, JVMTI_ENABLE,
+ JVMTI_EVENT_METHOD_ENTRY,
+ (jthread)NULL))
+ != JVMTI_ERROR_NONE)
+ jvmti_error (jvmti, error,
+ "SetEventNotificationMode (JVMTI_EVENT_METHOD_ENTRY)");
+ else if ((error =
+ (*jvmti)->SetEventNotificationMode (jvmti, JVMTI_ENABLE,
+ JVMTI_EVENT_METHOD_EXIT,
+ (jthread)NULL))
+ != JVMTI_ERROR_NONE)
+ jvmti_error (jvmti, error,
+ "SetEventNotificationMode (JVMTI_EVENT_METHOD_EXIT)");
+ else if ((error =
+ (*jvmti)->SetEventNotificationMode
+ (jvmti, JVMTI_ENABLE, JVMTI_EVENT_FIELD_MODIFICATION,
+ (jthread)NULL)) != JVMTI_ERROR_NONE)
+ jvmti_error (jvmti, error,
+ "SetEventNotificationMode (JVMTI_EVENT_FIELD_MODIFICATION");
+ else if ((error = (*jvmti)->SetEventCallbacks(jvmti, &callbacks,
+ (jint)sizeof(callbacks)))
+ != JVMTI_ERROR_NONE)
+ jvmti_error (jvmti, error, "SetEventCallbacks");
+
+ return JNI_OK;
+}
diff --git a/java/method.c b/java/method.c
new file mode 100644
index 0000000..35e6022
--- /dev/null
+++ b/java/method.c
@@ -0,0 +1,111 @@
+#include <string.h>
+
+#include "method.h"
+#include "config.h"
+#include "misc.h"
+
+static bool handle_method (jvmtiEnv *jvmti, JNIEnv* jni, jthread thread,
+ jmethodID method, char **object, char **method_name,
+ char **class_name)
+{
+ jvmtiError error;
+ char *class_sig = NULL, object_buf[SIZE_OBJECT_BUF];
+ jclass klass;
+ bool success = FALSE;
+
+ *object = *method_name = *class_name = NULL;
+
+ if ((error =
+ (*jvmti)->GetMethodName (jvmti, method, method_name, NULL, NULL))
+ != JVMTI_ERROR_NONE)
+ jvmti_error (jvmti, error, "GetMethodName");
+ else if ((error =
+ (*jvmti)->GetMethodDeclaringClass (jvmti, method, &klass))
+ != JVMTI_ERROR_NONE)
+ jvmti_error (jvmti, error, "GetMethodDeclaringClass");
+ else if ((error =
+ (*jvmti)->GetClassSignature (jvmti, klass, &class_sig, NULL))
+ != JVMTI_ERROR_NONE)
+ jvmti_error (jvmti, error, "GetClassSignature");
+ else {
+ if ((*class_name = get_class_name_from_sig (class_sig, TRUE)) &&
+ include_class (*class_name)) {
+ jint numlocals;
+ jvmtiLocalVariableEntry *locals;
+ if ((error = (*jvmti)->GetLocalVariableTable (jvmti, method,
+ &numlocals, &locals))
+ != JVMTI_ERROR_NONE)
+ jvmti_error (jvmti, error, "GetLocalVariableTable");
+ else {
+ jint j, this_slot = -1;
+ for (j = 0; j < numlocals && this_slot == -1; j++)
+ if (strcmp (locals[j].name, "this") == 0)
+ this_slot = locals[j].slot;
+
+ jobject this_obj;
+
+ if (this_slot == -1) {
+ this_obj = NULL;
+ success = TRUE;
+ } else {
+ if ((error = (*jvmti)->GetLocalObject (jvmti, thread, 0,
+ this_slot, &this_obj))
+ != JVMTI_ERROR_NONE) {
+ jvmti_error (jvmti, error, "GetLocalObject");
+ } else
+ success = TRUE;
+ }
+
+ if (success) {
+ fill_object_buf (jni, object_buf, this_obj);
+ *object = strdup (object_buf);
+ }
+ }
+ }
+ }
+
+ jvmti_dealloc (jvmti, class_sig);
+
+ return success;
+}
+
+static void handle_method_free (jvmtiEnv *jvmti, char *object,
+ char *method_name, char *class_name)
+{
+ simple_free (object);
+ jvmti_dealloc (jvmti, method_name);
+ simple_free (class_name);
+}
+
+void JNICALL method_entry (jvmtiEnv *jvmti, JNIEnv* jni, jthread thread,
+ jmethodID method)
+{
+ char *object, *method_name, *class_name;
+
+ if (handle_method (jvmti, jni, thread, method, &object, &method_name,
+ &class_name)) {
+ if (strcmp (method_name, "<init>") == 0)
+ RTFL_OBJ_PRINT ("create", "s:s", object, class_name);
+ else
+ RTFL_OBJ_PRINT ("enter", "s:s:d:s:",
+ object, "", 0, method_name, class_name);
+ }
+
+ handle_method_free (jvmti, object, method_name, class_name);
+}
+
+void JNICALL method_exit (jvmtiEnv *jvmti, JNIEnv* jni, jthread thread,
+ jmethodID method, jboolean was_popped_by_exception,
+ jvalue return_value)
+{
+ char *object, *method_name, *class_name;
+
+ if (handle_method (jvmti, jni, thread, method, &object, &method_name,
+ &class_name)) {
+ if (strcmp (method_name, "<init>") != 0)
+ // Hopefully, this is the correct method.
+ RTFL_OBJ_PRINT ("leave", "s", object);
+ }
+
+ handle_method_free (jvmti, object, method_name, class_name);
+}
diff --git a/java/method.h b/java/method.h
new file mode 100644
index 0000000..e3dfc45
--- /dev/null
+++ b/java/method.h
@@ -0,0 +1,12 @@
+#ifndef __JAVA_METHOD_H__
+#define __JAVA_METHOD_H__
+
+#include <jvmti.h>
+
+void JNICALL method_entry (jvmtiEnv *jvmti, JNIEnv* jni, jthread thread,
+ jmethodID method);
+void JNICALL method_exit (jvmtiEnv *jvmti, JNIEnv* jni, jthread thread,
+ jmethodID method, jboolean was_popped_by_exception,
+ jvalue return_value);
+
+#endif /* __JAVA_METHOD_H__ */
diff --git a/java/misc.c b/java/misc.c
new file mode 100644
index 0000000..09d0668
--- /dev/null
+++ b/java/misc.c
@@ -0,0 +1,191 @@
+#include <string.h>
+#include <stdlib.h>
+
+#include "misc.h"
+
+bool str_starts_with (const char *haystack, const char *needle)
+{
+ int haystack_len = strlen (haystack), needle_len = strlen (needle);
+ if (haystack_len < needle_len)
+ return FALSE;
+ else
+ return memcmp (haystack, needle, needle_len * sizeof (char)) == 0;
+}
+
+void jvmti_error (jvmtiEnv *jvmti, jvmtiError error, const char *fmt, ...)
+{
+ char *errorname;
+ if ((*jvmti)->GetErrorName (jvmti, error, &errorname) != JVMTI_ERROR_NONE)
+ errorname = "<error getting error name>";
+
+ fprintf(stderr, "error (jvmtiError %d: %s): ", error, errorname);
+
+ va_list argp;
+ va_start(argp, fmt);
+ vfprintf(stderr, fmt, argp);
+ va_end(argp);
+
+ fprintf(stderr, "\n");
+}
+
+void other_error (const char *fmt, ...)
+{
+ fprintf(stderr, "error (other): ");
+
+ va_list argp;
+ va_start(argp, fmt);
+ vfprintf(stderr, fmt, argp);
+ va_end(argp);
+
+ fprintf(stderr, "\n");
+}
+
+void jvmti_dealloc (jvmtiEnv *jvmti, void *mem)
+{
+ if (mem) {
+ jvmtiError error;
+ if ((error = (*jvmti)->Deallocate (jvmti, mem)) != JVMTI_ERROR_NONE)
+ jvmti_error (jvmti, error, "Deallocate");
+ }
+}
+
+void simple_free (void *mem)
+{
+ if (mem)
+ free (mem);
+}
+
+char *get_class_name_from_sig (const char *class_sig, bool expect_class)
+{
+ int len_class_sig = strlen (class_sig);
+ if (!(class_sig[0] == 'L' && class_sig[len_class_sig - 1] == ';')) {
+ if (expect_class)
+ other_error ("don't know how to deal with class signature '%s'",
+ class_sig);
+ return NULL;
+ } else {
+ char *class_name =
+ (char*)malloc ((len_class_sig - 2 + 1) * sizeof (char));
+ int i;
+ for (i = 0; i < len_class_sig - 2; i++)
+ class_name[i] = class_sig[i + 1] == '/' ? '.' : class_sig[i + 1];
+ class_name[len_class_sig - 2] = 0;
+ return class_name;
+ }
+}
+
+/* -------------------------------------------------------------------
+
+ The only way to identify objects seems to be the JNI method
+ IsSameObject; although jobject is a pointer, the equality of two
+ jobject's does not imply the identity of the represented Java
+ objects.
+
+ Furthermore, since we only have one object at hand to get an
+ identifier needed for RTFL messages, we store all objects in a
+ list, after creating a global reference (NewGlobalRef); the index
+ in the list then identifies the object. This foils the garbage
+ collection, but for short debugging sessions, this should be
+ acceptable.
+
+ ---------------------------------------------------------------------- */
+
+static size_t reg_objects_size = 0, reg_objects_alloc_size;
+static jobject *reg_objects = NULL;
+
+size_t object_index (JNIEnv* jni, jobject object)
+{
+ size_t i;
+ for (i = 0; i < reg_objects_size; i++)
+ if ((*jni)->IsSameObject (jni, object, reg_objects[i]))
+ return i;
+
+ reg_objects_size++;
+ if (reg_objects == NULL) {
+ reg_objects_alloc_size = 1;
+ reg_objects =
+ (jobject*)malloc (reg_objects_alloc_size * sizeof (jobject));
+ } else {
+ reg_objects_alloc_size <<= 1;
+ reg_objects =
+ (jobject*)realloc (reg_objects,
+ reg_objects_alloc_size * sizeof (jobject));
+ }
+
+ i = reg_objects_size - 1;
+ reg_objects[i] = (*jni)->NewGlobalRef (jni, object);
+ return i;
+}
+
+void fill_object_buf (JNIEnv* jni, char *object_buf, jobject object)
+{
+ if (object)
+ snprintf (object_buf, SIZE_OBJECT_BUF, "%ld", object_index (jni, object));
+ else
+ strcpy (object_buf, "null");
+}
+
+// Copied from "debug_rtfl.hh".
+void rtfl_print (const char *module, const char *version,
+ const char *file, int line, const char *fmt, ...)
+{
+ // "\n" at the beginning just in case that the previous line is not
+ // finished yet.
+ printf ("\n[rtfl-%s-%s]%s:%d:pid(todo):", module, version, file, line);
+
+ va_list args;
+ va_start (args, fmt);
+
+ int i;
+ for (i = 0; fmt[i]; i++) {
+ int n, j;
+ void *p;
+ char *s;
+
+ switch (fmt[i]) {
+ case 'd':
+ n = va_arg(args, int);
+ printf ("%d", n);
+ break;
+
+ case 'p':
+ p = va_arg(args, void*);
+ printf ("%p", p);
+ break;
+
+ case 's':
+ s = va_arg (args, char*);
+ for (j = 0; s[j]; j++) {
+ if (s[j] == ':' || s[j] == '\\')
+ putchar ('\\');
+ putchar (s[j]);
+ }
+ break;
+
+ case 'q':
+ s = va_arg (args, char*);
+ for (j = 0; s[j]; j++) {
+ if (s[j] == ':' || s[j] == '\\')
+ putchar ('\\');
+ else if (s[j] == '\"')
+ printf ("\\\\"); // a quoted quoting character
+ putchar (s[j]);
+ }
+ break;
+
+ case 'c':
+ n = va_arg(args, int);
+ printf ("#%06x", n);
+ break;
+
+ default:
+ putchar (fmt[i]);
+ break;
+ }
+ }
+
+ va_end (args);
+
+ putchar ('\n');
+ fflush (stdout);
+}
diff --git a/java/misc.h b/java/misc.h
new file mode 100644
index 0000000..e88879e
--- /dev/null
+++ b/java/misc.h
@@ -0,0 +1,41 @@
+#ifndef __JAVA_MISC_H__
+#define __JAVA_MISC_H__
+
+#include <jvmti.h>
+
+#define MIN(a, b) ((a) < (b) ? (a) : (b))
+#define MAX(a, b) ((a) > (b) ? (a) : (b))
+
+#ifndef __GNUC__
+# define __attribute__(x) /* nothing */
+#endif
+
+typedef enum { FALSE = 0, TRUE = 1 } bool;
+enum { SIZE_OBJECT_BUF = 32 };
+
+bool str_starts_with (const char *haystack, const char *needle);
+
+void jvmti_error (jvmtiEnv *jvmti, jvmtiError error, const char *fmt, ...)
+ __attribute__((format(printf, 3, 4)));
+void other_error (const char *fmt, ...) __attribute__((format(printf, 1, 2)));
+
+void jvmti_dealloc (jvmtiEnv *jvmti, void *mem);
+void simple_free (void *mem);
+
+char *get_class_name_from_sig (const char *class_sig, bool expect_class);
+
+size_t object_index (JNIEnv* jni, jobject object);
+void fill_object_buf (JNIEnv* jni, char *object_buf, jobject object);
+
+void rtfl_print (const char *module, const char *version,
+ const char *file, int line, const char *fmt, ...);
+
+#define RTFL_PRINT(module, version, cmd, fmt, ...) \
+ rtfl_print (module, version, "", 1, "s:" fmt, cmd, __VA_ARGS__)
+
+#define RTFL_OBJ_VERSION "1.0"
+
+#define RTFL_OBJ_PRINT(cmd, fmt, ...) \
+ RTFL_PRINT ("obj", RTFL_OBJ_VERSION, cmd, fmt, __VA_ARGS__)
+
+#endif /* __JAVA_MISC_H__ */
diff --git a/lout/Makefile.am b/lout/Makefile.am
new file mode 100644
index 0000000..f221936
--- /dev/null
+++ b/lout/Makefile.am
@@ -0,0 +1,21 @@
+AM_CPPFLAGS = \
+ -I$(top_srcdir) \
+ -DCUR_WORKING_DIR='"@BASE_CUR_WORKING_DIR@/lout"'
+
+noinst_LIBRARIES = liblout.a
+
+liblout_a_SOURCES = \
+ container.cc \
+ container.hh \
+ debug.hh \
+ identity.cc \
+ identity.hh \
+ misc.cc \
+ misc.hh \
+ object.cc \
+ object.hh \
+ signal.cc \
+ signal.hh \
+ unicode.cc \
+ unicode.hh \
+ msg.h
diff --git a/lout/container.cc b/lout/container.cc
new file mode 100644
index 0000000..9ed14d8
--- /dev/null
+++ b/lout/container.cc
@@ -0,0 +1,813 @@
+/*
+ * RTFL (originally part of dillo)
+ *
+ * Copyright 2005-2007 Sebastian Geerken <sgeerken@dillo.org>
+ *
+ * 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; with the following exception:
+ *
+ * The copyright holders of RTFL give you permission to link this file
+ * statically or dynamically against all versions of the graphviz
+ * library, which are published by AT&T Corp. under one of the following
+ * licenses:
+ *
+ * - Common Public License version 1.0 as published by International
+ * Business Machines Corporation (IBM), or
+ * - Eclipse Public License version 1.0 as published by the Eclipse
+ * Foundation.
+ *
+ * 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/>.
+ */
+
+#define PRINTF(fmt, ...)
+//#define PRINTF printf
+
+#include "container.hh"
+#include "misc.hh"
+#include "debug.hh"
+
+namespace lout {
+
+using namespace object;
+
+namespace container {
+
+namespace untyped {
+
+// -------------
+// Iterator
+// -------------
+
+Iterator::Iterator()
+{
+ impl = NULL;
+}
+
+Iterator::Iterator(const Iterator &it2)
+{
+ impl = it2.impl;
+ if (impl)
+ impl->ref();
+}
+
+Iterator::Iterator(Iterator &it2)
+{
+ impl = it2.impl;
+ if (impl)
+ impl->ref();
+}
+
+Iterator &Iterator::operator=(const Iterator &it2)
+{
+ if (impl)
+ impl->unref();
+ impl = it2.impl;
+ if (impl)
+ impl->ref();
+ return *this;
+}
+
+Iterator &Iterator::operator=(Iterator &it2)
+{
+ if (impl)
+ impl->unref();
+ impl = it2.impl;
+ if (impl)
+ impl->ref();
+ return *this;
+}
+
+Iterator::~Iterator()
+{
+ if (impl)
+ impl->unref();
+}
+
+// ----------------
+// Collection
+// ----------------
+
+void Collection::intoStringBuffer(misc::StringBuffer *sb)
+{
+ sb->append("{ ");
+ bool first = true;
+ for (Iterator it = iterator(); it.hasNext(); ) {
+ if (!first)
+ sb->append(", ");
+ it.getNext()->intoStringBuffer(sb);
+ first = false;
+ }
+ sb->append(" }");
+}
+
+// ------------
+// Vector
+// ------------
+
+Vector::Vector(int initSize, bool ownerOfObjects)
+{
+ DBG_OBJ_CREATE ("lout::container::untyped::Vector");
+
+ numAlloc = initSize == 0 ? 1 : initSize;
+ this->ownerOfObjects = ownerOfObjects;
+ numElements = 0;
+ array = (Object**)malloc(numAlloc * sizeof(Object*));
+}
+
+Vector::~Vector()
+{
+ clear();
+ free(array);
+
+ DBG_OBJ_DELETE ();
+}
+
+int Vector::size ()
+{
+ return numElements;
+}
+
+void Vector::put(Object *newElement, int newPos)
+{
+ if (newPos == -1)
+ newPos = numElements;
+
+ // Old entry is overwritten.
+ if (newPos < numElements) {
+ if (ownerOfObjects && array[newPos])
+ delete array[newPos];
+ }
+
+ // Allocated memory has to be increased.
+ if (newPos >= numAlloc) {
+ while (newPos >= numAlloc)
+ numAlloc *= 2;
+ array = (Object**)realloc(array, numAlloc * sizeof(Object*));
+ }
+
+ // Insert NULL's into possible gap before new position.
+ for (int i = numElements; i < newPos; i++)
+ array[i] = NULL;
+
+ if (newPos >= numElements)
+ numElements = newPos + 1;
+
+ array[newPos] = newElement;
+}
+
+void Vector::clear()
+{
+ if (ownerOfObjects) {
+ for (int i = 0; i < numElements; i++)
+ if (array[i])
+ delete array[i];
+ }
+
+ numElements = 0;
+}
+
+void Vector::insert(Object *newElement, int pos)
+{
+ if (pos >= numElements)
+ put(newElement, pos);
+ else {
+ numElements++;
+
+ // Allocated memory has to be increased.
+ if (numElements >= numAlloc) {
+ numAlloc *= 2;
+ array = (Object**)realloc(array, numAlloc * sizeof(Object*));
+ }
+
+ for (int i = numElements - 1; i > pos; i--)
+ array[i] = array[i - 1];
+
+ array[pos] = newElement;
+ }
+}
+
+void Vector::remove(int pos)
+{
+ if (ownerOfObjects && array[pos])
+ delete array[pos];
+
+ for (int i = pos + 1; i < numElements; i++)
+ array[i - 1] = array[i];
+
+ numElements--;
+}
+
+/**
+ * Sort the elements in the vector. Assumes that all elements are Comparable's.
+ */
+void Vector::sort(Comparator *comparator)
+{
+ Comparator::compareFunComparator = comparator;
+ qsort (array, numElements, sizeof(Object*), Comparator::compareFun);
+}
+
+/**
+ * \brief Use binary search to find an element in a sorted vector.
+ *
+ * If "mustExist" is true, only exact matches are found; otherwise, -1
+ * is returned. If it is false, the position of the next greater
+ * element is returned, or, if the key is the greatest element, the
+ * size of the array. (This is the value which can be used for
+ * insertion; see insertSortet()).
+ */
+int Vector::bsearch(Object *key, bool mustExist, int start, int end,
+ Comparator *comparator)
+{
+ // The case !mustExist is not handled by bsearch(3), so here is a
+ // new implementation.
+
+ DBG_OBJ_MSGF ("container", 0,
+ "<b>bsearch</b> (<i>key</i>, %s, %d, %d, <i>comparator</i>) "
+ "[size is %d]",
+ mustExist ? "true" : "false", start, end, size ());
+ DBG_OBJ_MSG_START ();
+
+ int result = -123; // Compiler happiness: GCC 4.7 does not handle this?
+
+ if (start > end) {
+ DBG_OBJ_MSG ("container", 1, "empty");
+ result = mustExist ? -1 : start;
+ } else {
+ int low = start, high = end;
+ bool found = false;
+
+ while (!found) {
+ int index = (low + high) / 2;
+ int c = comparator->compare (key, array[index]);
+ DBG_OBJ_MSGF ("container", 1,
+ "searching within %d and %d; compare key with #%d => %d",
+ low, high, index, c);
+ if (c == 0) {
+ found = true;
+ result = index;
+ } else {
+ if (low >= high) {
+ if (mustExist) {
+ found = true;
+ result = -1;
+ } else {
+ found = true;
+ result = c > 0 ? index + 1 : index;
+ }
+ }
+
+ if (c < 0)
+ high = index - 1;
+ else
+ low = index + 1;
+ }
+ }
+ }
+
+ DBG_OBJ_MSGF ("container", 1, "result = %d", result);
+ DBG_OBJ_MSG_END ();
+ return result;
+}
+
+Object *Vector::VectorIterator::getNext()
+{
+ if (index < vector->numElements - 1)
+ index++;
+
+ return index < vector->numElements ? vector->array[index] : NULL;
+}
+
+bool Vector::VectorIterator::hasNext()
+{
+ return index < vector->numElements - 1;
+}
+
+Collection0::AbstractIterator* Vector::createIterator()
+{
+ return new VectorIterator(this);
+}
+
+// ------------
+// List
+// ------------
+
+List::List(bool ownerOfObjects)
+{
+ this->ownerOfObjects = ownerOfObjects;
+ first = last = NULL;
+ numElements = 0;
+}
+
+List::~List()
+{
+ clear();
+}
+
+int List::size ()
+{
+ return numElements;
+}
+
+bool List::equals(Object *other)
+{
+ List *otherList = (List*)other;
+ Node *node1 = first, *node2 = otherList->first;
+ while (node1 != NULL && node2 != NULL ) {
+ if (!node1->object->equals (node2->object))
+ return false;
+ node1 = node1->next;
+ node2 = node2->next;
+ }
+ return node1 == NULL && node2 == NULL;
+}
+
+int List::hashValue()
+{
+ int h = 0;
+ for (Node *node = first; node; node = node->next)
+ h = h ^ node->object->hashValue ();
+ return h;
+}
+
+void List::clear()
+{
+ while (first) {
+ if (ownerOfObjects && first->object)
+ delete first->object;
+ Node *next = first->next;
+ delete first;
+ first = next;
+ }
+
+ last = NULL;
+ numElements = 0;
+}
+
+void List::append(Object *element)
+{
+ Node *newLast = new Node;
+ newLast->next = NULL;
+ newLast->object = element;
+
+ if (last) {
+ last->next = newLast;
+ last = newLast;
+ } else
+ first = last = newLast;
+
+ numElements++;
+}
+
+bool List::insertBefore(object::Object *beforeThis, object::Object *neew)
+{
+ Node *beforeCur, *cur;
+
+ for (beforeCur = NULL, cur = first; cur; beforeCur = cur, cur = cur->next) {
+ if (cur->object == beforeThis) {
+ Node *newNode = new Node;
+ newNode->next = cur;
+ newNode->object = neew;
+
+ if (beforeCur)
+ beforeCur->next = newNode;
+ else
+ first = newNode;
+
+ numElements++;
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool List::remove0(Object *element, bool compare, bool doNotDeleteAtAll)
+{
+ Node *beforeCur, *cur;
+
+ for (beforeCur = NULL, cur = first; cur; beforeCur = cur, cur = cur->next) {
+ if (compare ?
+ (cur->object && element->equals(cur->object)) :
+ element == cur->object) {
+ if (beforeCur) {
+ beforeCur->next = cur->next;
+ if (cur->next == NULL)
+ last = beforeCur;
+ } else {
+ first = cur->next;
+ if (first == NULL)
+ last = NULL;
+ }
+
+ if (ownerOfObjects && cur->object && !doNotDeleteAtAll)
+ delete cur->object;
+ delete cur;
+
+ numElements--;
+ return true;
+ }
+ }
+
+ return false;
+}
+
+Object *List::ListIterator::getNext()
+{
+ Object *object;
+
+ if (current) {
+ object = current->object;
+ current = current->next;
+ } else
+ object = NULL;
+
+ return object;
+}
+
+bool List::ListIterator::hasNext()
+{
+ return current != NULL;
+}
+
+Collection0::AbstractIterator* List::createIterator()
+{
+ return new ListIterator(first);
+}
+
+
+// ---------------
+// HashSet
+// ---------------
+
+HashSet::HashSet(bool ownerOfObjects, int tableSize)
+{
+ this->ownerOfObjects = ownerOfObjects;
+ this->tableSize = tableSize;
+
+ table = new Node*[tableSize];
+ for (int i = 0; i < tableSize; i++)
+ table[i] = NULL;
+
+ numElements = 0;
+}
+
+HashSet::~HashSet()
+{
+ for (int i = 0; i < tableSize; i++) {
+ Node *n1 = table[i];
+ while (n1) {
+ Node *n2 = n1->next;
+
+ // It seems appropriate to call "clearNode(n1)" here instead
+ // of "delete n1->object", but since this is the destructor,
+ // the implementation of a sub class would not be called
+ // anymore. This is the reason why HashTable has an
+ // destructor.
+ if (ownerOfObjects) {
+ PRINTF ("- deleting object: %s\n", n1->object->toString());
+ delete n1->object;
+ }
+
+ delete n1;
+ n1 = n2;
+ }
+ }
+
+ delete[] table;
+}
+
+int HashSet::size ()
+{
+ return numElements;
+}
+
+HashSet::Node *HashSet::createNode()
+{
+ return new Node;
+}
+
+void HashSet::clearNode(HashSet::Node *node)
+{
+ if (ownerOfObjects) {
+ PRINTF ("- deleting object: %s\n", node->object->toString());
+ delete node->object;
+ }
+}
+
+HashSet::Node *HashSet::findNode(Object *object) const
+{
+ int h = calcHashValue(object);
+ for (Node *node = table[h]; node; node = node->next) {
+ if (object->equals(node->object))
+ return node;
+ }
+
+ return NULL;
+}
+
+HashSet::Node *HashSet::insertNode(Object *object)
+{
+ // Look whether object is already contained.
+ Node *node = findNode(object);
+ if (node) {
+ clearNode(node);
+ numElements--;
+ } else {
+ int h = calcHashValue(object);
+ node = createNode ();
+ node->next = table[h];
+ table[h] = node;
+ numElements++;
+ }
+
+ node->object = object;
+ return node;
+}
+
+
+void HashSet::put(Object *object)
+{
+ insertNode (object);
+}
+
+bool HashSet::contains(Object *object) const
+{
+ int h = calcHashValue(object);
+ for (Node *n = table[h]; n; n = n->next) {
+ if (object->equals(n->object))
+ return true;
+ }
+
+ return false;
+}
+
+bool HashSet::remove(Object *object)
+{
+ int h = calcHashValue(object);
+ Node *last, *cur;
+
+ for (last = NULL, cur = table[h]; cur; last = cur, cur = cur->next) {
+ if (object->equals(cur->object)) {
+ if (last)
+ last->next = cur->next;
+ else
+ table[h] = cur->next;
+
+ clearNode (cur);
+ delete cur;
+ numElements--;
+
+ return true;
+ }
+ }
+
+ return false;
+
+ // TODO for HashTable: also remove value.
+}
+
+// For historical reasons: this method once existed under the name
+// "getKey" in HashTable. It could be used to get the real object from
+// the table, but it was dangerous, because a change of this object
+// would also change the hash value, and so confuse the table.
+
+/*Object *HashSet::getReference (Object *object)
+{
+ int h = calcHashValue(object);
+ for (Node *n = table[h]; n; n = n->next) {
+ if (object->equals(n->object))
+ return n->object;
+ }
+
+ return NULL;
+}*/
+
+HashSet::HashSetIterator::HashSetIterator(HashSet *set)
+{
+ this->set = set;
+ node = NULL;
+ pos = -1;
+ gotoNext();
+}
+
+void HashSet::HashSetIterator::gotoNext()
+{
+ if (node)
+ node = node->next;
+
+ while (node == NULL) {
+ if (pos >= set->tableSize - 1)
+ return;
+ pos++;
+ node = set->table[pos];
+ }
+}
+
+
+Object *HashSet::HashSetIterator::getNext()
+{
+ Object *result;
+ if (node)
+ result = node->object;
+ else
+ result = NULL;
+
+ gotoNext();
+ return result;
+}
+
+bool HashSet::HashSetIterator::hasNext()
+{
+ return node != NULL;
+}
+
+Collection0::AbstractIterator* HashSet::createIterator()
+{
+ return new HashSetIterator(this);
+}
+
+// ---------------
+// HashTable
+// ---------------
+
+HashTable::HashTable(bool ownerOfKeys, bool ownerOfValues, int tableSize) :
+ HashSet (ownerOfKeys, tableSize)
+{
+ this->ownerOfValues = ownerOfValues;
+}
+
+HashTable::~HashTable()
+{
+ // See comment in the destructor of HashSet.
+ for (int i = 0; i < tableSize; i++) {
+ for (Node *n = table[i]; n; n = n->next) {
+ if (ownerOfValues) {
+ Object *value = ((KeyValuePair*)n)->value;
+ if (value) {
+ PRINTF ("- deleting value: %s\n", value->toString());
+ delete value;
+ }
+ }
+ }
+ }
+}
+
+HashSet::Node *HashTable::createNode()
+{
+ return new KeyValuePair;
+}
+
+void HashTable::clearNode(HashSet::Node *node)
+{
+ HashSet::clearNode (node);
+ if (ownerOfValues) {
+ Object *value = ((KeyValuePair*)node)->value;
+ if (value) {
+ PRINTF ("- deleting value: %s\n", value->toString());
+ delete value;
+ }
+ }
+}
+
+void HashTable::intoStringBuffer(misc::StringBuffer *sb)
+{
+ sb->append("{ ");
+
+ bool first = true;
+ for (int i = 0; i < tableSize; i++) {
+ for (Node *node = table[i]; node; node = node->next) {
+ if (!first)
+ sb->append(", ");
+ node->object->intoStringBuffer(sb);
+
+ sb->append(" => ");
+
+ Object *value = ((KeyValuePair*)node)->value;
+ if (value)
+ value->intoStringBuffer(sb);
+ else
+ sb->append ("null");
+
+ first = false;
+ }
+ }
+
+ sb->append(" }");
+}
+
+void HashTable::put(Object *key, Object *value)
+{
+ KeyValuePair *node = (KeyValuePair*)insertNode(key);
+ node->value = value;
+}
+
+Object *HashTable::get(Object *key) const
+{
+ Node *node = findNode(key);
+ if (node)
+ return ((KeyValuePair*)node)->value;
+ else
+ return NULL;
+}
+
+// -----------
+// Stack
+// -----------
+
+Stack::Stack (bool ownerOfObjects)
+{
+ this->ownerOfObjects = ownerOfObjects;
+ bottom = top = NULL;
+ numElements = 0;
+}
+
+Stack::~Stack()
+{
+ while (top)
+ pop ();
+}
+
+int Stack::size ()
+{
+ return numElements;
+}
+
+void Stack::push (object::Object *object)
+{
+ Node *newTop = new Node ();
+ newTop->object = object;
+ newTop->prev = top;
+
+ top = newTop;
+ if (bottom == NULL)
+ bottom = top;
+
+ numElements++;
+}
+
+void Stack::pushUnder (object::Object *object)
+{
+ Node *newBottom = new Node ();
+ newBottom->object = object;
+ newBottom->prev = NULL;
+ if (bottom != NULL)
+ bottom->prev = newBottom;
+
+ bottom = newBottom;
+ if (top == NULL)
+ top = bottom;
+
+ numElements++;
+}
+
+void Stack::pop ()
+{
+ Node *newTop = top->prev;
+
+ if (ownerOfObjects)
+ delete top->object;
+ delete top;
+
+ top = newTop;
+ if (top == NULL)
+ bottom = NULL;
+
+ numElements--;
+}
+
+Object *Stack::StackIterator::getNext()
+{
+ Object *object;
+
+ if (current) {
+ object = current->object;
+ current = current->prev;
+ } else
+ object = NULL;
+
+ return object;
+}
+
+bool Stack::StackIterator::hasNext()
+{
+ return current != NULL;
+}
+
+Collection0::AbstractIterator* Stack::createIterator()
+{
+ return new StackIterator(top);
+}
+
+} // namespace untyped
+
+} // namespace container
+
+} // namespace lout
diff --git a/lout/container.hh b/lout/container.hh
new file mode 100644
index 0000000..3051970
--- /dev/null
+++ b/lout/container.hh
@@ -0,0 +1,551 @@
+#ifndef __LOUT_CONTAINER_HH_
+#define __LOUT_CONTAINER_HH_
+
+#include "object.hh"
+
+namespace lout {
+
+/**
+ * \brief This namespace contains a framework for container classes, which
+ * members are instances of object::Object.
+ *
+ * A common problem in languages without garbage collection is, where the
+ * children belong to, and so, who is responsible to delete them (instantiation
+ * is always done by the caller). This information is here told to the
+ * collections, each container has a constructor with the parameter
+ * "ownerOfObjects" (HashTable has two such parameters, for keys and values).
+ *
+ * \sa container::untyped, container::typed
+ */
+namespace container {
+
+/**
+ * \brief The container classes defined here contain instances of
+ * object::Object.
+ *
+ * Different sub-classes may be mixed, and you have to care about casting,
+ * there is no type-safety.
+ */
+namespace untyped {
+
+/**
+ * \brief ...
+ */
+class Collection0: public object::Object
+{
+ friend class Iterator;
+
+protected:
+ /**
+ * \brief The base class for all iterators, as created by
+ * container::untyped::Collection::createIterator.
+ */
+ class AbstractIterator: public object::Object
+ {
+ private:
+ int refcount;
+
+ public:
+ AbstractIterator() { refcount = 1; }
+
+ void ref () { refcount++; }
+ void unref () { refcount--; if (refcount == 0) delete this; }
+
+ virtual bool hasNext () = 0;
+ virtual Object *getNext () = 0;
+ };
+
+protected:
+ virtual AbstractIterator* createIterator() = 0;
+};
+
+/**
+ * \brief This is a small wrapper for AbstractIterator, which may be used
+ * directly, not as a pointer, to makes memory management simpler.
+ */
+class Iterator
+{
+ friend class Collection;
+
+private:
+ Collection0::AbstractIterator *impl;
+
+ // Should not instantiated directly.
+ inline Iterator(Collection0::AbstractIterator *impl) { this->impl = impl; }
+
+public:
+ Iterator();
+ Iterator(const Iterator &it2);
+ Iterator(Iterator &it2);
+ ~Iterator();
+ Iterator &operator=(const Iterator &it2);
+ Iterator &operator=(Iterator &it2);
+
+ inline bool hasNext() { return impl->hasNext(); }
+ inline object::Object *getNext() { return impl->getNext(); }
+};
+
+/**
+ * \brief Abstract base class for all container objects in container::untyped.
+ */
+class Collection: public Collection0
+{
+public:
+ void intoStringBuffer(misc::StringBuffer *sb);
+ inline Iterator iterator() { Iterator it(createIterator()); return it; }
+ virtual int size() = 0;
+};
+
+
+/**
+ * \brief Container, which is implemented by an array, which is
+ * dynamically resized.
+ */
+class Vector: public Collection
+{
+ friend class VectorIterator;
+
+private:
+ object::Object **array;
+ int numAlloc, numElements;
+ bool ownerOfObjects;
+
+ class VectorIterator: public AbstractIterator
+ {
+ private:
+ Vector *vector;
+ int index;
+
+ public:
+ VectorIterator(Vector *vector) { this->vector = vector; index = -1; }
+ bool hasNext();
+ Object *getNext();
+ };
+
+protected:
+ AbstractIterator* createIterator();
+
+public:
+ Vector(int initSize, bool ownerOfObjects);
+ ~Vector();
+
+ int size();
+
+ void put(object::Object *newElement, int newPos = -1);
+ void insert(object::Object *newElement, int pos);
+
+ /**
+ * \brief Insert into an already sorted vector.
+ *
+ * Notice that insertion is not very efficient, unless the position
+ * is rather at the end.
+ */
+ inline int insertSorted(object::Object *newElement,
+ object::Comparator *comparator =
+ &object::standardComparator)
+ { int pos = bsearch (newElement, false, comparator);
+ insert (newElement, pos); return pos; }
+
+ void remove(int pos);
+ inline object::Object *get(int pos) const
+ { return (pos >= 0 && pos < numElements) ? array[pos] : NULL; }
+ void clear();
+ void sort(object::Comparator *comparator = &object::standardComparator);
+ int bsearch(Object *key, bool mustExist, int start, int end,
+ object::Comparator *comparator = &object::standardComparator);
+ inline int bsearch(Object *key, bool mustExist,
+ object::Comparator *comparator =
+ &object::standardComparator)
+ { return bsearch (key, mustExist, 0, size () - 1, comparator); }
+};
+
+
+/**
+ * \brief A single-linked list.
+ */
+class List: public Collection
+{
+ friend class ListIterator;
+
+private:
+ struct Node
+ {
+ public:
+ object::Object *object;
+ Node *next;
+ };
+
+ class ListIterator: public AbstractIterator
+ {
+ private:
+ List::Node *current;
+ public:
+ ListIterator(List::Node *node) { current = node; }
+ bool hasNext();
+ Object *getNext();
+ };
+
+ Node *first, *last;
+ bool ownerOfObjects;
+ int numElements;
+
+ bool remove0(object::Object *element, bool compare, bool doNotDeleteAtAll);
+
+protected:
+ AbstractIterator* createIterator();
+
+public:
+ List(bool ownerOfObjects);
+ ~List();
+
+ bool equals(Object *other);
+ int hashValue();
+
+ int size ();
+
+ void clear();
+ void append(object::Object *element);
+ bool insertBefore(object::Object *beforeThis, object::Object *neew);
+ inline bool removeRef(object::Object *element)
+ { return remove0(element, false, false); }
+ inline bool remove(object::Object *element)
+ { return remove0(element, true, false); }
+ inline bool detachRef(object::Object *element)
+ { return remove0(element, false, true); }
+ inline int size() const { return numElements; }
+ inline bool isEmpty() const { return numElements == 0; }
+ inline object::Object *getFirst() const { return first->object; }
+ inline object::Object *getLast() const { return last->object; }
+};
+
+
+/**
+ * \brief A hash set.
+ */
+class HashSet: public Collection
+{
+ friend class HashSetIterator;
+
+protected:
+ struct Node
+ {
+ object::Object *object;
+ Node *next;
+ };
+
+ Node **table;
+ int tableSize, numElements;
+ bool ownerOfObjects;
+
+ inline int calcHashValue(object::Object *object) const
+ {
+ return abs(object->hashValue()) % tableSize;
+ }
+
+ virtual Node *createNode();
+ virtual void clearNode(Node *node);
+
+ Node *findNode(object::Object *object) const;
+ Node *insertNode(object::Object *object);
+
+ AbstractIterator* createIterator();
+
+private:
+ class HashSetIterator: public Collection0::AbstractIterator
+ {
+ private:
+ HashSet *set;
+ HashSet::Node *node;
+ int pos;
+
+ void gotoNext();
+
+ public:
+ HashSetIterator(HashSet *set);
+ bool hasNext();
+ Object *getNext();
+ };
+
+public:
+ HashSet(bool ownerOfObjects, int tableSize = 251);
+ ~HashSet();
+
+ int size ();
+
+ void put (object::Object *object);
+ bool contains (object::Object *key) const;
+ bool remove (object::Object *key);
+ //Object *getReference (object::Object *object);
+};
+
+/**
+ * \brief A hash table.
+ */
+class HashTable: public HashSet
+{
+private:
+ bool ownerOfValues;
+
+ struct KeyValuePair: public Node
+ {
+ object::Object *value;
+ };
+
+protected:
+ Node *createNode();
+ void clearNode(Node *node);
+
+public:
+ HashTable(bool ownerOfKeys, bool ownerOfValues, int tableSize = 251);
+ ~HashTable();
+
+ void intoStringBuffer(misc::StringBuffer *sb);
+
+ void put (object::Object *key, object::Object *value);
+ object::Object *get (object::Object *key) const;
+};
+
+/**
+ * \brief A stack (LIFO). Can be used as Queue (FIFO) when pushUnder()
+ * is used instead of push().
+ *
+ * Note that the iterator returns all elements in the reversed order they have
+ * been put on the stack.
+ */
+class Stack: public Collection
+{
+ friend class StackIterator;
+
+private:
+ class Node
+ {
+ public:
+ object::Object *object;
+ Node *prev;
+ };
+
+ class StackIterator: public AbstractIterator
+ {
+ private:
+ Stack::Node *current;
+ public:
+ StackIterator(Stack::Node *node) { current = node; }
+ bool hasNext();
+ Object *getNext();
+ };
+
+ Node *bottom, *top;
+ bool ownerOfObjects;
+ int numElements;
+
+protected:
+ AbstractIterator* createIterator();
+
+public:
+ Stack (bool ownerOfObjects);
+ ~Stack();
+
+ int size ();
+
+ void push (object::Object *object);
+ void pushUnder (object::Object *object);
+ inline object::Object *getTop () const { return top ? top->object : NULL; }
+ void pop ();
+ inline int size() const { return numElements; }
+};
+
+} // namespace untyped
+
+/**
+ * \brief This namespace provides thin wrappers, implemented as C++ templates,
+ * to gain type-safety.
+ *
+ * Notice, that nevertheless, all objects still have to be instances of
+ * object::Object.
+ */
+namespace typed {
+
+template <class T> class Collection;
+
+/**
+ * \brief Typed version of container::untyped::Iterator.
+ */
+template <class T> class Iterator
+{
+ friend class Collection<T>;
+
+private:
+ untyped::Iterator base;
+
+public:
+ inline Iterator() { }
+ inline Iterator(const Iterator<T> &it2) { this->base = it2.base; }
+ inline Iterator(Iterator<T> &it2) { this->base = it2.base; }
+ ~Iterator() { }
+ inline Iterator &operator=(const Iterator<T> &it2)
+ { this->base = it2.base; return *this; }
+ inline Iterator &operator=(Iterator<T> &it2)
+ { this->base = it2.base; return *this; }
+
+ inline bool hasNext() { return this->base.hasNext(); }
+ inline T *getNext() { return (T*)this->base.getNext(); }
+};
+
+/**
+ * \brief Abstract base class template for all container objects in
+ * container::typed.
+ *
+ * Actually, a wrapper for container::untyped::Collection.
+ */
+template <class T> class Collection: public object::Object
+{
+protected:
+ untyped::Collection *base;
+
+public:
+ Collection () { this->base = NULL; }
+ ~Collection () { if (this->base) delete this->base; }
+
+ bool equals(Object *other)
+ { return this->base->equals (((Collection<T>*)other)->base); }
+
+ int hashValue() { return this->base->hashValue (); }
+
+ void intoStringBuffer(misc::StringBuffer *sb)
+ { this->base->intoStringBuffer(sb); }
+ inline Iterator<T> iterator() {
+ Iterator<T> it; it.base = this->base->iterator(); return it; }
+ inline int size() { return this->base->size (); }
+};
+
+
+/**
+ * \brief Typed version of container::untyped::Vector.
+ */
+template <class T> class Vector: public Collection <T>
+{
+public:
+ inline Vector(int initSize, bool ownerOfObjects) {
+ this->base = new untyped::Vector(initSize, ownerOfObjects); }
+
+ inline void put(T *newElement, int newPos = -1)
+ { ((untyped::Vector*)this->base)->put(newElement, newPos); }
+ inline void insert(T *newElement, int pos)
+ { ((untyped::Vector*)this->base)->insert(newElement, pos); }
+ inline int insertSorted(T *newElement,
+ object::Comparator *comparator =
+ &object::standardComparator)
+ { return ((untyped::Vector*)this->base)->insertSorted(newElement,
+ comparator); }
+ inline void remove(int pos) { ((untyped::Vector*)this->base)->remove(pos); }
+ inline T *get(int pos) const
+ { return (T*)((untyped::Vector*)this->base)->get(pos); }
+ inline void clear() { ((untyped::Vector*)this->base)->clear(); }
+ inline void sort(object::Comparator *comparator =
+ &object::standardComparator)
+ { ((untyped::Vector*)this->base)->sort(comparator); }
+ inline int bsearch(T *key, bool mustExist, int start, int end,
+ object::Comparator *comparator =
+ &object::standardComparator)
+ { return ((untyped::Vector*)this->base)->bsearch(key, mustExist, start, end,
+ comparator); }
+ inline int bsearch(T *key, bool mustExist,
+ object::Comparator *comparator =
+ &object::standardComparator)
+ { return ((untyped::Vector*)this->base)->bsearch(key, mustExist,
+ comparator); }
+};
+
+
+/**
+ * \brief Typed version of container::untyped::List.
+ */
+template <class T> class List: public Collection <T>
+{
+public:
+ inline List(bool ownerOfObjects)
+ { this->base = new untyped::List(ownerOfObjects); }
+
+ inline void clear() { ((untyped::List*)this->base)->clear(); }
+ inline void append(T *element)
+ { ((untyped::List*)this->base)->append(element); }
+ inline bool insertBefore(object::Object *beforeThis, object::Object *neew)
+ { return ((untyped::List*)this->base)->insertBefore(beforeThis, neew); }
+ inline bool removeRef(T *element) {
+ return ((untyped::List*)this->base)->removeRef(element); }
+ inline bool remove(T *element) {
+ return ((untyped::List*)this->base)->remove(element); }
+ inline bool detachRef(T *element) {
+ return ((untyped::List*)this->base)->detachRef(element); }
+
+ inline bool isEmpty() const
+ { return ((untyped::List*)this->base)->isEmpty(); }
+ inline T *getFirst() const
+ { return (T*)((untyped::List*)this->base)->getFirst(); }
+ inline T *getLast() const
+ { return (T*)((untyped::List*)this->base)->getLast(); }
+};
+
+/**
+ * \brief Typed version of container::untyped::HashSet.
+ */
+template <class T> class HashSet: public Collection <T>
+{
+protected:
+ inline HashSet() { }
+
+public:
+ inline HashSet(bool owner, int tableSize = 251)
+ { this->base = new untyped::HashSet(owner, tableSize); }
+
+ inline void put(T *object)
+ { return ((untyped::HashSet*)this->base)->put(object); }
+ inline bool contains(T *object) const
+ { return ((untyped::HashSet*)this->base)->contains(object); }
+ inline bool remove(T *object)
+ { return ((untyped::HashSet*)this->base)->remove(object); }
+ //inline T *getReference(T *object)
+ //{ return (T*)((untyped::HashSet*)this->base)->getReference(object); }
+};
+
+/**
+ * \brief Typed version of container::untyped::HashTable.
+ */
+template <class K, class V> class HashTable: public HashSet <K>
+{
+public:
+ inline HashTable(bool ownerOfKeys, bool ownerOfValues, int tableSize = 251)
+ { this->base = new untyped::HashTable(ownerOfKeys, ownerOfValues,
+ tableSize); }
+
+ inline void put(K *key, V *value)
+ { return ((untyped::HashTable*)this->base)->put(key, value); }
+ inline V *get(K *key) const
+ { return (V*)((untyped::HashTable*)this->base)->get(key); }
+};
+
+/**
+ * \brief Typed version of container::untyped::Stack.
+ */
+template <class T> class Stack: public Collection <T>
+{
+public:
+ inline Stack (bool ownerOfObjects)
+ { this->base = new untyped::Stack (ownerOfObjects); }
+
+ inline void push (T *object) {
+ ((untyped::Stack*)this->base)->push (object); }
+ inline void pushUnder (T *object)
+ { ((untyped::Stack*)this->base)->pushUnder (object); }
+ inline T *getTop () const
+ { return (T*)((untyped::Stack*)this->base)->getTop (); }
+ inline void pop () { ((untyped::Stack*)this->base)->pop (); }
+};
+
+} // namespace untyped
+
+} // namespace container
+
+} // namespace lout
+
+#endif // __LOUT_CONTAINER_HH_
diff --git a/lout/debug.hh b/lout/debug.hh
new file mode 100644
index 0000000..636d4a4
--- /dev/null
+++ b/lout/debug.hh
@@ -0,0 +1,381 @@
+#ifndef __LOUT_DEBUG_H__
+#define __LOUT_DEBUG_H__
+
+/*
+ * Simple debug messages. Add:
+ *
+ * #define DEBUG_LEVEL <n>
+ * #include "debug.h"
+ *
+ * to the file you are working on, or let DEBUG_LEVEL undefined to
+ * disable all messages. A higher level denotes a greater importance
+ * of the message.
+ */
+
+#include <stdio.h>
+
+#define D_STMT_START do
+#define D_STMT_END while (0)
+
+#define D_STMT_NOP D_STMT_START { } D_STMT_END
+
+# ifdef DEBUG_LEVEL
+# define DEBUG_MSG(level, ...) \
+ D_STMT_START { \
+ if (DEBUG_LEVEL && (level) >= DEBUG_LEVEL) \
+ printf(__VA_ARGS__); \
+ } D_STMT_END
+# else
+# define DEBUG_MSG(level, ...)
+# endif /* DEBUG_LEVEL */
+
+
+
+/*
+ * This is an old version of "debug_rtfl.hh", which has been copied
+ * from dillo (see README).
+ */
+
+#ifdef DBG_RTFL
+
+#include <unistd.h>
+#include <stdio.h>
+
+#define DBG_IF_RTFL if(1)
+
+// "\n" at the beginning just in case that the previous line is not finished
+// yet.
+#define RTFL_PREFIX_FMT "\n[rtfl]%s:%d:%d:"
+#define RTFL_PREFIX_ARGS CUR_WORKING_DIR "/" __FILE__, __LINE__, getpid()
+
+#define DBG_OBJ_MSG(aspect, prio, msg) \
+ D_STMT_START { \
+ printf (RTFL_PREFIX_FMT "obj-msg:%p:%s:%d:%s\n", \
+ RTFL_PREFIX_ARGS, this, aspect, prio, msg); \
+ fflush (stdout); \
+ } D_STMT_END
+
+// Variant which does not use "this", but an explicitly passed
+// object. Should be applied to other macros. (Also, for use in C.)
+#define DBG_OBJ_MSG_O(aspect, prio, obj, msg) \
+ D_STMT_START { \
+ printf (RTFL_PREFIX_FMT "obj-msg:%p:%s:%d:%s\n", \
+ RTFL_PREFIX_ARGS, obj, aspect, prio, msg); \
+ fflush (stdout); \
+ } D_STMT_END
+
+#define DBG_OBJ_MSGF(aspect, prio, fmt, ...) \
+ D_STMT_START { \
+ printf (RTFL_PREFIX_FMT "obj-msg:%p:%s:%d:" fmt "\n", \
+ RTFL_PREFIX_ARGS, this, aspect, prio, __VA_ARGS__); \
+ fflush (stdout); \
+ } D_STMT_END
+
+// See DBG_OBJ_MSG_O.
+#define DBG_OBJ_MSGF_O(aspect, prio, obj, fmt, ...) \
+ D_STMT_START { \
+ printf (RTFL_PREFIX_FMT "obj-msg:%p:%s:%d:" fmt "\n", \
+ RTFL_PREFIX_ARGS, obj, aspect, prio, __VA_ARGS__); \
+ fflush (stdout); \
+ } D_STMT_END
+
+#define DBG_OBJ_MSG_START() \
+ D_STMT_START { \
+ printf (RTFL_PREFIX_FMT "obj-msg-start:%p\n", \
+ RTFL_PREFIX_ARGS, this); \
+ fflush (stdout); \
+ } D_STMT_END
+
+// See DBG_OBJ_MSG_O.
+#define DBG_OBJ_MSG_START_O(obj) \
+ D_STMT_START { \
+ printf (RTFL_PREFIX_FMT "obj-msg-start:%p\n", \
+ RTFL_PREFIX_ARGS, obj); \
+ fflush (stdout); \
+ } D_STMT_END
+
+#define DBG_OBJ_MSG_END() \
+ D_STMT_START { \
+ printf (RTFL_PREFIX_FMT "obj-msg-end:%p\n", \
+ RTFL_PREFIX_ARGS, this); \
+ fflush (stdout); \
+ } D_STMT_END
+
+// See DBG_OBJ_MSG_O.
+#define DBG_OBJ_MSG_END_O(obj) \
+ D_STMT_START { \
+ printf (RTFL_PREFIX_FMT "obj-msg-end:%p\n", \
+ RTFL_PREFIX_ARGS, obj); \
+ fflush (stdout); \
+ } D_STMT_END
+
+#define DBG_OBJ_ENTER0(aspect, prio, funname) \
+ D_STMT_START { \
+ printf (RTFL_PREFIX_FMT "obj-enter:%p:%s:%d:%s:\n", \
+ RTFL_PREFIX_ARGS, this, aspect, prio, funname); \
+ fflush (stdout); \
+ } D_STMT_END
+
+#define DBG_OBJ_ENTER0_O(aspect, prio, obj, funname) \
+ D_STMT_START { \
+ printf (RTFL_PREFIX_FMT "obj-enter:%p:%s:%d:%s:\n", \
+ RTFL_PREFIX_ARGS, obj, aspect, prio, funname); \
+ fflush (stdout); \
+ } D_STMT_END
+
+#define DBG_OBJ_ENTER(aspect, prio, funname, fmt, ...) \
+ D_STMT_START { \
+ fflush (stdout); \
+ printf (RTFL_PREFIX_FMT "obj-enter:%p:%s:%d:%s:" fmt "\n", \
+ RTFL_PREFIX_ARGS, this, aspect, prio, funname, __VA_ARGS__); \
+ } D_STMT_END
+
+#define DBG_OBJ_ENTER_O(aspect, prio, obj, funname, fmt, ...) \
+ D_STMT_START { \
+ fflush (stdout); \
+ printf (RTFL_PREFIX_FMT "obj-enter:%p:%s:%d:%s:" fmt "\n", \
+ RTFL_PREFIX_ARGS, obj, aspect, prio, funname, __VA_ARGS__); \
+ } D_STMT_END
+
+#define DBG_OBJ_LEAVE() \
+ D_STMT_START { \
+ printf (RTFL_PREFIX_FMT "obj-leave:%p\n", \
+ RTFL_PREFIX_ARGS, this); \
+ fflush (stdout); \
+ } D_STMT_END
+
+#define DBG_OBJ_LEAVE_O(obj) \
+ D_STMT_START { \
+ printf (RTFL_PREFIX_FMT "obj-leave:%p\n", \
+ RTFL_PREFIX_ARGS, obj); \
+ fflush (stdout); \
+ } D_STMT_END
+
+#define DBG_OBJ_CREATE(klass) \
+ D_STMT_START { \
+ printf (RTFL_PREFIX_FMT "obj-create:%p:%s\n", \
+ RTFL_PREFIX_ARGS, this, klass); \
+ fflush (stdout); \
+ } D_STMT_END
+
+#define DBG_OBJ_DELETE() \
+ D_STMT_START { \
+ printf (RTFL_PREFIX_FMT "obj-delete:%p\n", \
+ RTFL_PREFIX_ARGS, this); \
+ fflush (stdout); \
+ } D_STMT_END
+
+#define DBG_OBJ_BASECLASS(klass) \
+ D_STMT_START { \
+ printf (RTFL_PREFIX_FMT "obj-ident:%p:%p\n", \
+ RTFL_PREFIX_ARGS, this, (klass*)this); \
+ fflush (stdout); \
+ } D_STMT_END
+
+#define DBG_OBJ_ASSOC(parent, child) \
+ D_STMT_START { \
+ if (child) { \
+ printf (RTFL_PREFIX_FMT "obj-assoc:%p:%p\n", \
+ RTFL_PREFIX_ARGS, parent, child); \
+ fflush (stdout); \
+ } \
+ } D_STMT_END
+
+#define DBG_OBJ_ASSOC_PARENT(parent) \
+ D_STMT_START { \
+ printf (RTFL_PREFIX_FMT "obj-assoc:%p:%p\n", \
+ RTFL_PREFIX_ARGS, parent, this); \
+ fflush (stdout); \
+ } D_STMT_END
+
+#define DBG_OBJ_ASSOC_CHILD(child) \
+ D_STMT_START { \
+ if (child) { \
+ printf (RTFL_PREFIX_FMT "obj-assoc:%p:%p\n", \
+ RTFL_PREFIX_ARGS, this, child); \
+ fflush (stdout); \
+ } \
+ } D_STMT_END
+
+#define DBG_OBJ_SET_NUM(var, val) \
+ D_STMT_START { \
+ printf (RTFL_PREFIX_FMT "obj-set:%p:%s:%d\n", \
+ RTFL_PREFIX_ARGS, this, var, val); \
+ fflush (stdout); \
+ } D_STMT_END
+
+#define DBG_OBJ_SET_NUM_O(obj, var, val) \
+ D_STMT_START { \
+ printf (RTFL_PREFIX_FMT "obj-set:%p:%s:%d\n", \
+ RTFL_PREFIX_ARGS, obj, var, val); \
+ fflush (stdout); \
+ } D_STMT_END
+
+#define DBG_OBJ_SET_SYM(var, val) \
+ D_STMT_START { \
+ printf (RTFL_PREFIX_FMT "obj-set:%p:%s:%s\n", \
+ RTFL_PREFIX_ARGS, this, var, val); \
+ fflush (stdout); \
+ } D_STMT_END
+
+#define DBG_OBJ_SET_STR(var, val) \
+ D_STMT_START { \
+ printf (RTFL_PREFIX_FMT "obj-set:%p:%s:\"%s\"\n", \
+ RTFL_PREFIX_ARGS, this, var, val); \
+ fflush (stdout); \
+ } D_STMT_END
+
+#define DBG_OBJ_SET_PTR(var, val) \
+ D_STMT_START { \
+ printf (RTFL_PREFIX_FMT "obj-set:%p:%s:%p\n", \
+ RTFL_PREFIX_ARGS, this, var, val); \
+ fflush (stdout); \
+ } D_STMT_END
+
+#define DBG_OBJ_SET_PTR_O(obj, var, val) \
+ D_STMT_START { \
+ printf (RTFL_PREFIX_FMT "obj-set:%p:%s:%p\n", \
+ RTFL_PREFIX_ARGS, obj, var, val); \
+ fflush (stdout); \
+ } D_STMT_END
+
+#define DBG_OBJ_SET_BOOL(var, val) \
+ D_STMT_START { \
+ printf (RTFL_PREFIX_FMT "obj-set:%p:%s:%s\n", \
+ RTFL_PREFIX_ARGS, this, var, val ? "true" : "false"); \
+ fflush (stdout); \
+ } D_STMT_END
+
+#define DBG_OBJ_SET_BOOL_O(obj, var, val) \
+ D_STMT_START { \
+ printf (RTFL_PREFIX_FMT "obj-set:%p:%s:%s\n", \
+ RTFL_PREFIX_ARGS, obj, var, val ? "true" : "false"); \
+ fflush (stdout); \
+ } D_STMT_END
+
+#define DBG_OBJ_ARRSET_NUM(var, ind, val) \
+ D_STMT_START { \
+ printf (RTFL_PREFIX_FMT "obj-set:%p:%s.%d:%d\n", \
+ RTFL_PREFIX_ARGS, this, var, ind, val); \
+ fflush (stdout); \
+ } D_STMT_END
+
+#define DBG_OBJ_ARRSET_SYM(var, ind, val) \
+ D_STMT_START { \
+ printf (RTFL_PREFIX_FMT "obj-set:%p:%s.%d:%s\n", \
+ RTFL_PREFIX_ARGS, this, var, ind, val); \
+ fflush (stdout); \
+ } D_STMT_END
+
+#define DBG_OBJ_ARRSET_BOOL(var, ind, val) \
+ D_STMT_START { \
+ printf (RTFL_PREFIX_FMT "obj-set:%p:%s.%d:%s\n", \
+ RTFL_PREFIX_ARGS, this, var, ind, val ? "true" : "false"); \
+ fflush (stdout); \
+ } D_STMT_END
+
+#define DBG_OBJ_ARRSET_STR(var, ind, val) \
+ D_STMT_START { \
+ printf (RTFL_PREFIX_FMT "obj-set:%p:%s.%d:\"%s\"\n", \
+ RTFL_PREFIX_ARGS, this, var, ind, val); \
+ fflush (stdout); \
+ } D_STMT_END
+
+#define DBG_OBJ_ARRSET_PTR(var, ind, val) \
+ D_STMT_START { \
+ printf (RTFL_PREFIX_FMT "obj-set:%p:%s.%d:%p\n", \
+ RTFL_PREFIX_ARGS, this, var, ind, val); \
+ fflush (stdout); \
+ } D_STMT_END
+
+#define DBG_OBJ_ARRATTRSET_NUM(var, ind, attr, val) \
+ D_STMT_START { \
+ printf (RTFL_PREFIX_FMT "obj-set:%p:%s.%d.%s:%d\n", \
+ RTFL_PREFIX_ARGS, this, var, ind, attr, val); \
+ fflush (stdout); \
+ } D_STMT_END
+
+#define DBG_OBJ_ARRATTRSET_SYM(var, ind, attr, val) \
+ D_STMT_START { \
+ printf (RTFL_PREFIX_FMT "obj-set:%p:%s.%d.%s:%s\n", \
+ RTFL_PREFIX_ARGS, this, var, ind, attr, val); \
+ fflush (stdout); \
+ } D_STMT_END
+
+#define DBG_OBJ_ARRATTRSET_BOOL(var, ind, attr, val) \
+ D_STMT_START { \
+ printf (RTFL_PREFIX_FMT "obj-set:%p:%s.%d.%s:%s\n", \
+ RTFL_PREFIX_ARGS, this, var, ind, attr, val ? "true" : "false"); \
+ fflush (stdout); \
+ } D_STMT_END
+
+#define DBG_OBJ_ARRATTRSET_STR(var, ind, attr, val) \
+ D_STMT_START { \
+ printf (RTFL_PREFIX_FMT "obj-set:%p:%s.%d.%s:\"%s\"\n", \
+ RTFL_PREFIX_ARGS, this, var, ind, attr, val); \
+ fflush (stdout); \
+ } D_STMT_END
+
+#define DBG_OBJ_ARRATTRSET_PTR(var, ind, attr, val) \
+ D_STMT_START { \
+ printf (RTFL_PREFIX_FMT "obj-set:%p:%s.%d.%s:%p\n", \
+ RTFL_PREFIX_ARGS, this, var, ind, attr, val); \
+ fflush (stdout); \
+ } D_STMT_END
+
+#define DBG_OBJ_COLOR(klass, color) \
+ D_STMT_START { \
+ printf (RTFL_PREFIX_FMT "obj-color:%s:%s\n", \
+ RTFL_PREFIX_ARGS, color, klass); \
+ fflush (stdout); \
+ } D_STMT_END
+
+#else /* DBG_RTFL */
+
+#define DBG_IF_RTFL if(0)
+
+#define DBG_OBJ_MSG(aspect, prio, msg) D_STMT_NOP
+#define DBG_OBJ_MSG_O(aspect, prio, obj, msg) D_STMT_NOP
+#define DBG_OBJ_MSGF(aspect, prio, fmt, ...) D_STMT_NOP
+#define DBG_OBJ_MSGF_O(aspect, prio, obj, fmt, ...) D_STMT_NOP
+#define DBG_OBJ_MSG_START() D_STMT_NOP
+#define DBG_OBJ_MSG_START_O(obj) D_STMT_NOP
+#define DBG_OBJ_MSG_END() D_STMT_NOP
+#define DBG_OBJ_MSG_END_O(obj) D_STMT_NOP
+#define DBG_OBJ_ENTER0(aspect, prio, funname) D_STMT_NOP
+#define DBG_OBJ_ENTER0_O(aspect, prio, obj, funname) D_STMT_NOP
+#define DBG_OBJ_ENTER(aspect, prio, funname, fmt, ...) D_STMT_NOP
+#define DBG_OBJ_ENTER_O(aspect, prio, obj, funname, fmt, ...) D_STMT_NOP
+#define DBG_OBJ_LEAVE() D_STMT_NOP
+#define DBG_OBJ_LEAVE_O(obj) D_STMT_NOP
+#define DBG_OBJ_CREATE(klass) D_STMT_NOP
+#define DBG_OBJ_DELETE() D_STMT_NOP
+#define DBG_OBJ_BASECLASS(klass) D_STMT_NOP
+#define DBG_OBJ_ASSOC_PARENT(parent) D_STMT_NOP
+#define DBG_OBJ_ASSOC_CHILD(child) D_STMT_NOP
+#define DBG_OBJ_ASSOC(parent, child) D_STMT_NOP
+#define DBG_OBJ_SET_NUM(var, val) D_STMT_NOP
+#define DBG_OBJ_SET_NUM_O(obj, var, val) D_STMT_NOP
+#define DBG_OBJ_SET_SYM(var, val) D_STMT_NOP
+#define DBG_OBJ_SET_STR(var, val) D_STMT_NOP
+#define DBG_OBJ_SET_PTR(var, val) D_STMT_NOP
+#define DBG_OBJ_SET_PTR_O(obj, var, val) D_STMT_NOP
+#define DBG_OBJ_SET_BOOL(var, val) D_STMT_NOP
+#define DBG_OBJ_SET_BOOL_O(obj, var, val) D_STMT_NOP
+#define DBG_OBJ_ARRSET_NUM(var, ind, val) D_STMT_NOP
+#define DBG_OBJ_ARRSET_SYM(var, ind, val) D_STMT_NOP
+#define DBG_OBJ_ARRSET_STR(var, ind, val) D_STMT_NOP
+#define DBG_OBJ_ARRSET_PTR(var, ind, val) D_STMT_NOP
+#define DBG_OBJ_ARRSET_BOOL(var, ind, val) D_STMT_NOP
+#define DBG_OBJ_ARRATTRSET_NUM(var, ind, attr, val) D_STMT_NOP
+#define DBG_OBJ_ARRATTRSET_SYM(var, ind, attr, val) D_STMT_NOP
+#define DBG_OBJ_ARRATTRSET_STR(var, ind, attr, val) D_STMT_NOP
+#define DBG_OBJ_ARRATTRSET_PTR(var, ind, attr, val) D_STMT_NOP
+#define DBG_OBJ_ARRATTRSET_BOOL(var, ind, attr, val) D_STMT_NOP
+#define DBG_OBJ_COLOR(klass, color) D_STMT_NOP
+
+#endif /* DBG_RTFL */
+
+#endif /* __LOUT_DEBUG_H__ */
+
+
diff --git a/lout/identity.cc b/lout/identity.cc
new file mode 100644
index 0000000..a1664aa
--- /dev/null
+++ b/lout/identity.cc
@@ -0,0 +1,141 @@
+/*
+ * RTFL (originally part of dillo)
+ *
+ * Copyright 2005-2007 Sebastian Geerken <sgeerken@dillo.org>
+ *
+ * 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; with the following exception:
+ *
+ * The copyright holders of RTFL give you permission to link this file
+ * statically or dynamically against all versions of the graphviz
+ * library, which are published by AT&T Corp. under one of the following
+ * licenses:
+ *
+ * - Common Public License version 1.0 as published by International
+ * Business Machines Corporation (IBM), or
+ * - Eclipse Public License version 1.0 as published by the Eclipse
+ * Foundation.
+ *
+ * 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/>.
+ */
+
+#include "identity.hh"
+
+#include <stdio.h>
+
+namespace lout {
+namespace identity {
+
+// ------------------------
+// IdentifiableObject
+// ------------------------
+
+using namespace object;
+using namespace container::typed;
+
+IdentifiableObject::Class::Class (IdentifiableObject::Class *parent, int id,
+ const char *className)
+{
+ this->parent = parent;
+ this->id = id;
+ this->className = className;
+}
+
+void IdentifiableObject::Class::intoStringBuffer(misc::StringBuffer *sb)
+{
+ sb->append ("<class ");
+ sb->append (className);
+ sb->append (" (");
+ sb->appendInt (id);
+ sb->append (")");
+
+ if (parent) {
+ sb->append (", parent: ");
+ parent->intoStringBuffer (sb);
+ }
+
+ sb->append (">");
+}
+
+HashTable <ConstString, IdentifiableObject::Class>
+ *IdentifiableObject::classesByName =
+ new HashTable<ConstString, IdentifiableObject::Class> (true, true);
+Vector <IdentifiableObject::Class> *IdentifiableObject::classesById =
+ new Vector <IdentifiableObject::Class> (16, false);
+IdentifiableObject::Class *IdentifiableObject::currentlyConstructedClass;
+
+IdentifiableObject::IdentifiableObject ()
+{
+ currentlyConstructedClass = NULL;
+}
+
+void IdentifiableObject::intoStringBuffer(misc::StringBuffer *sb)
+{
+ sb->append("<instance ");
+ sb->appendPointer(this);
+ sb->append(" of ");
+ sb->append(getClassName());
+ sb->append(">");
+}
+
+/**
+ * \brief This method must be called in the constructor for the sub class.
+ * See class comment for details.
+ */
+void IdentifiableObject::registerName (const char *className, int *classId)
+{
+ ConstString str (className);
+ Class *klass = classesByName->get (&str);
+ if (klass == NULL) {
+ klass = new Class (currentlyConstructedClass, classesById->size (),
+ className);
+ ConstString *key = new ConstString (className);
+ classesByName->put (key, klass);
+ classesById->put (klass);
+ *classId = klass->id;
+ }
+
+ this->classId = klass->id;
+ *classId = klass->id;
+ currentlyConstructedClass = klass;
+}
+
+/**
+ * \brief Returns, whether this class is an instance of the class, given by
+ * \em otherClassId, or of a sub class of this class.
+ */
+bool IdentifiableObject::instanceOf (int otherClassId)
+{
+ if (otherClassId == -1)
+ // Other class has not been registered yet, while it should have been,
+ // if this class is an instance of it or of a sub-class.
+ return false;
+
+ Class *otherClass = classesById->get (otherClassId);
+
+ if (otherClass == NULL) {
+ fprintf (stderr,
+ "WARNING: Something got wrong here, it seems that a "
+ "CLASS_ID was not initialized properly.\n");
+ return false;
+ }
+
+ for (Class *klass = classesById->get (classId); klass != NULL;
+ klass = klass->parent) {
+ if (klass == otherClass)
+ return true;
+ }
+
+ return false;
+}
+
+} // namespace identity
+} // namespace lout
diff --git a/lout/identity.hh b/lout/identity.hh
new file mode 100644
index 0000000..df42b20
--- /dev/null
+++ b/lout/identity.hh
@@ -0,0 +1,149 @@
+#ifndef __LOUT_OBJECTX_HH__
+#define __LOUT_OBJECTX_HH__
+
+#include "object.hh"
+#include "container.hh"
+#include "signal.hh"
+
+namespace lout {
+
+/**
+ * \brief Some stuff to identify classes of objects at run-time.
+ */
+namespace identity {
+
+/**
+ * \brief Instances of classes, which are sub classes of this class, may
+ * be identified at run-time.
+ *
+ * <h3>Testing the class</h3>
+ *
+ * Since e.g. dw::Textblock is a sub class of IdentifiableObject, and
+ * implemented in the correct way (as described below), for any given
+ * IdentifiableObject the following test can be done:
+ *
+ * \code
+ * identity::IdentifiableObject *o;
+ * // ...
+ * bool isATextblock = o->instanceOf(dw::Textblock::CLASS_ID);
+ * \endcode
+ *
+ * \em isATextblock is true, when \em o is an instance of dw::Textblock,
+ * or of a sub class of dw::Textblock. Otherwise, \em isATextblock is false.
+ *
+ * It is also possible to get the class identifier of an
+ * identity::IdentifiableObject, e.g.
+ *
+ * \code
+ * bool isOnlyATextblock = o->getClassId() == dw::Textblock::CLASS_ID;
+ * \endcode
+ *
+ * would result in true, if o is an instance of dw::Textblock, but not an
+ * instance of a sub class of dw::Textblock.
+ *
+ * <h3>Defining Sub Classes</h3>
+ *
+ * Each direct or indirect sub class of IdentifiableObject must
+ *
+ * <ul>
+ * <li> add a static int CLASS_ID with -1 as initial value, and
+ * <li> call registerName (\em name, &CLASS_ID) in the constructor, where
+ * \em name should be unique, e.g. the fully qualified class name.
+ * </ul>
+ *
+ * After this, <i>class</i>::CLASS_ID refers to a number, which denotes the
+ * class. (If this is still -1, since the class has not yet been instantiated,
+ * any test will fail, which is correct.)
+ *
+ * <h3>Notes on implementation</h3>
+ *
+ * If there are some classes like this:
+ *
+ * \dot
+ * digraph G {
+ * node [shape=record, fontname=Helvetica, fontsize=10];
+ * edge [arrowhead="none", arrowtail="empty", labelfontname=Helvetica,
+ * labelfontsize=10, color="#404040", labelfontcolor="#000080"];
+ * fontname=Helvetica; fontsize=10;
+ * IdentifiableObject [color="#a0a0a0"];
+ * A;
+ * B [color="#a0a0a0"];
+ * C;
+ * IdentifiableObject -> A;
+ * IdentifiableObject -> B;
+ * B -> C;
+ * }
+ * \enddot
+ *
+ * <center>[\ref uml-legend "legend"]</center>
+ *
+ * and first, an instance of A, and then an instance of C is created, there
+ * will be the following calls of functions and constructors:
+ *
+ * <ol>
+ * <li> %IdentifiableObject ();
+ * <li> %registerName ("A", &A::CLASS_ID);
+ * <li> %IdentifiableObject ();
+ * <li> %registerName ("B", &B::CLASS_ID);
+ * <li> %registerName ("C", &C::CLASS_ID);
+ * </ol>
+ *
+ * From this, the class hierarchy above can easily constructed, and stored
+ * in identity::IdentifiableObject::classesByName and
+ * in identity::IdentifiableObject::classesById. See the code for details.
+ *
+ * N.b. Multiple inheritance is not supported, the construction of the
+ * tree would become confused.
+ */
+class IdentifiableObject: public object::Object
+{
+private:
+ class Class: public object::Object
+ {
+ public:
+ Class *parent;
+ int id;
+ const char *className;
+
+ Class (Class *parent, int id, const char *className);
+
+ void intoStringBuffer(misc::StringBuffer *sb);
+ };
+
+ static container::typed::HashTable <object::ConstString,
+ Class> *classesByName;
+ static container::typed::Vector <Class> *classesById;
+ static Class *currentlyConstructedClass;
+
+ int classId;
+
+protected:
+ void registerName (const char *className, int *classId);
+
+public:
+ IdentifiableObject ();
+
+ void intoStringBuffer(misc::StringBuffer *sb);
+
+ /**
+ * \brief Returns the class identifier.
+ *
+ * This is rarely used, rather, tests with
+ * identity::IdentifiableObject::instanceOf are done.
+ */
+ int getClassId () { return classId; }
+
+ /**
+ * \brief Return the name, under which the class of this object was
+ * registered.
+ */
+ const char *getClassName() { return classesById->get(classId)->className; }
+
+ bool instanceOf (int otherClassId);
+};
+
+} // namespace identity
+
+} // namespace lout
+
+#endif // __LOUT_OBJECTX_HH__
diff --git a/lout/misc.cc b/lout/misc.cc
new file mode 100644
index 0000000..5064484
--- /dev/null
+++ b/lout/misc.cc
@@ -0,0 +1,197 @@
+/*
+ * RTFL (originally part of dillo)
+ *
+ * Copyright 2005-2007 Sebastian Geerken <sgeerken@dillo.org>
+ *
+ * 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; with the following exception:
+ *
+ * The copyright holders of RTFL give you permission to link this file
+ * statically or dynamically against all versions of the graphviz
+ * library, which are published by AT&T Corp. under one of the following
+ * licenses:
+ *
+ * - Common Public License version 1.0 as published by International
+ * Business Machines Corporation (IBM), or
+ * - Eclipse Public License version 1.0 as published by the Eclipse
+ * Foundation.
+ *
+ * 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/>.
+ */
+
+
+
+#include "misc.hh"
+
+#include <ctype.h>
+#include <config.h>
+
+#define PRGNAME PACKAGE "/" VERSION
+
+namespace lout {
+
+namespace misc {
+
+const char *prgName = PRGNAME;
+
+void init (int argc, char *argv[])
+{
+ prgName = strdup (argv[0]);
+}
+
+
+// ------------------
+// StringBuffer
+// ------------------
+
+
+StringBuffer::StringBuffer()
+{
+ firstNode = lastNode = NULL;
+ numChars = 0;
+ str = NULL;
+ strValid = false;
+}
+
+StringBuffer::~StringBuffer()
+{
+ clear ();
+ if (str)
+ delete[] str;
+}
+
+/**
+ * \brief Append a NUL-terminated string to the buffer, without copying.
+ *
+ * No copy is made, so this method should only be used in cases, where
+ * the string would otherwise be freed again. (This method may then
+ * save some CPU cycles.)
+ */
+void StringBuffer::appendNoCopy(char *str)
+{
+ Node *node = new Node();
+ node->data = str;
+ node->next = NULL;
+
+ if (firstNode == NULL) {
+ firstNode = node;
+ lastNode = node;
+ } else {
+ lastNode->next = node;
+ lastNode = node;
+ }
+
+ numChars += strlen(str);
+ strValid = false;
+}
+
+/**
+ * \brief Return a NUL-terminated strings containing all appended strings.
+ *
+ * The caller does not have to free the string, this is done in
+ * misc::StringBuffer::~StringBuffer.
+ */
+const char *StringBuffer::getChars()
+{
+ if (strValid)
+ return str;
+
+ if (str)
+ delete[] str;
+ str = new char[numChars + 1];
+ char *p = str;
+
+ for (Node *node = firstNode; node; node = node->next) {
+ int l = strlen(node->data);
+ memcpy(p, node->data, l * sizeof(char));
+ p += l;
+ }
+
+ *p = 0;
+ strValid = true;
+ return str;
+}
+
+/**
+ * \brief Remove all strings appended to the string buffer.
+ */
+void StringBuffer::clear ()
+{
+ Node *node, *nextNode;
+ for (node = firstNode; node; node = nextNode) {
+ nextNode = node->next;
+ free(node->data);
+ delete node;
+ }
+ firstNode = lastNode = NULL;
+ numChars = 0;
+ strValid = false;
+}
+
+
+// ------------
+// BitSet
+// ------------
+
+BitSet::BitSet(int initBits)
+{
+ numBytes = bytesForBits(initBits);
+ bits = (unsigned char*)malloc(numBytes * sizeof(unsigned char));
+ clear();
+}
+
+BitSet::~BitSet()
+{
+ free(bits);
+}
+
+void BitSet::intoStringBuffer(misc::StringBuffer *sb)
+{
+ sb->append("[");
+ for (int i = 0; i < numBytes; i++)
+ sb->append(get(i) ? "1" : "0");
+ sb->append("]");
+}
+
+bool BitSet::get(int i) const
+{
+ if (8 * i >= numBytes)
+ return false;
+ else
+ return bits[i / 8] & (1 << (i % 8));
+}
+
+void BitSet::set(int i, bool val)
+{
+ if (8 * i >= numBytes) {
+ int newNumBytes = numBytes;
+ while (8 * i >= newNumBytes)
+ newNumBytes *= 2;
+ bits =
+ (unsigned char*)realloc(bits, newNumBytes * sizeof(unsigned char));
+ memset(bits + numBytes, 0, newNumBytes - numBytes);
+ numBytes = newNumBytes;
+ }
+
+ if (val)
+ bits[i / 8] |= (1 << (i % 8));
+ else
+ bits[i / 8] &= ~(1 << (i % 8));
+}
+
+void BitSet::clear()
+{
+ memset(bits, 0, numBytes);
+}
+
+} // namespace misc
+
+} // namespace lout
diff --git a/lout/misc.hh b/lout/misc.hh
new file mode 100644
index 0000000..7edf83c
--- /dev/null
+++ b/lout/misc.hh
@@ -0,0 +1,652 @@
+#ifndef __LOUT_MISC_HH__
+#define __LOUT_MISC_HH__
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+namespace lout {
+
+/**
+ * \brief Miscellaneous stuff, which does not fit anywhere else.
+ *
+ * Actually, the other parts, beginning with ::object, depend on this.
+ */
+namespace misc {
+
+template <class T> inline T min (T a, T b) { return a < b ? a : b; }
+template <class T> inline T max (T a, T b) { return a > b ? a : b; }
+
+template <class T> inline T min (T a, T b, T c)
+{
+ return (min (a, min (b, c)));
+}
+template <class T> inline T max (T a, T b, T c)
+{
+ return (max (a, max (b, c)));
+}
+
+extern const char *prgName;
+
+void init (int argc, char *argv[]);
+
+inline void assertNotReached ()
+{
+ fprintf (stderr, "*** [%s] This should not happen! ***\n", prgName);
+ abort ();
+}
+
+inline int roundInt(double d)
+{
+ return (int) ((d > 0) ? (d + 0.5) : (d - 0.5));
+}
+
+inline int AsciiTolower(char c)
+{
+ return ((c >= 'A' && c <= 'Z') ? c + 0x20 : c);
+}
+
+inline int AsciiToupper(char c)
+{
+ return ((c >= 'a' && c <= 'z') ? c - 0x20 : c);
+}
+
+inline int AsciiStrcasecmp(const char *s1, const char *s2)
+{
+ int ret = 0;
+
+ while ((*s1 || *s2) && !(ret = AsciiTolower(*s1) - AsciiTolower(*s2))) {
+ s1++;
+ s2++;
+ }
+ return ret;
+}
+
+/**
+ * \brief Simple (simpler than container::untyped::Vector and
+ * container::typed::Vector) template based vector.
+ */
+template <class T> class SimpleVector
+{
+private:
+ T *array;
+ int num, numAlloc;
+
+ inline void resize ()
+ {
+ /* This algorithm was tuned for memory&speed with this huge page:
+ * http://downloads.mysql.com/docs/refman-6.0-en.html.tar.gz
+ */
+ if (array == NULL) {
+ this->numAlloc = 1;
+ this->array = (T*) malloc (sizeof (T));
+ }
+ if (this->numAlloc < this->num) {
+ this->numAlloc = (this->num < 100) ?
+ this->num : this->num + this->num/10;
+ this->array =
+ (T*) realloc(this->array, (this->numAlloc * sizeof (T)));
+ }
+ }
+
+public:
+ inline SimpleVector (int initAlloc = 1)
+ {
+ this->num = 0;
+ this->numAlloc = initAlloc;
+ this->array = NULL;
+ }
+
+ inline SimpleVector (const SimpleVector &o) {
+ this->array = NULL;
+ this->num = o.num;
+ this->numAlloc = o.numAlloc;
+ resize ();
+ memcpy (this->array, o.array, sizeof (T) * num);
+ }
+
+ inline ~SimpleVector ()
+ {
+ if (this->array)
+ free (this->array);
+ }
+
+ /**
+ * \brief Return the number of elements put into this vector.
+ */
+ inline int size() const { return this->num; }
+
+ inline T* getArray() const { return array; }
+
+ inline T* detachArray() {
+ T* arr = array;
+ array = NULL;
+ numAlloc = 0;
+ num = 0;
+ return arr;
+ }
+
+ /**
+ * \brief Increase the vector size by one.
+ *
+ * May be necessary before calling misc::SimpleVector::set.
+ */
+ inline void increase() { setSize(this->num + 1); }
+
+ /**
+ * \brief Set the size explicitly.
+ *
+ * May be necessary before calling misc::SimpleVector::set.
+ */
+ inline void setSize(int newSize) {
+ assert (newSize >= 0);
+ this->num = newSize;
+ this->resize ();
+ }
+
+ /**
+ * \brief Set the size explicitly and initialize new values.
+ *
+ * May be necessary before calling misc::SimpleVector::set.
+ */
+ inline void setSize (int newSize, T t) {
+ int oldSize = this->num;
+ setSize (newSize);
+ for (int i = oldSize; i < newSize; i++)
+ set (i, t);
+ }
+
+ /**
+ * \brief Return the reference of one element.
+ *
+ * \sa misc::SimpleVector::get
+ */
+ inline T* getRef (int i) const {
+ assert (i >= 0 && this->num - i > 0);
+ return array + i;
+ }
+
+ /**
+ * \brief Return the one element, explicitly.
+ *
+ * The element is copied, so for complex elements, you should rather used
+ * misc::SimpleVector::getRef.
+ */
+ inline T get (int i) const {
+ assert (i >= 0 && this->num - i > 0);
+ return this->array[i];
+ }
+
+ /**
+ * \brief Return the reference of the first element (convenience method).
+ */
+ inline T* getFirstRef () const {
+ assert (this->num > 0);
+ return this->array;
+ }
+
+ /**
+ * \brief Return the first element, explicitly.
+ */
+ inline T getFirst () const {
+ assert (this->num > 0);
+ return this->array[0];
+ }
+
+ /**
+ * \brief Return the reference of the last element (convenience method).
+ */
+ inline T* getLastRef () const {
+ assert (this->num > 0);
+ return this->array + this->num - 1;
+ }
+
+ /**
+ * \brief Return the last element, explicitly.
+ */
+ inline T getLast () const {
+ assert (this->num > 0);
+ return this->array[this->num - 1];
+ }
+
+ /**
+ * \brief Store an object in the vector.
+ *
+ * Unlike in container::untyped::Vector and container::typed::Vector,
+ * you have to care about the size, so a call to
+ * misc::SimpleVector::increase or misc::SimpleVector::setSize may
+ * be necessary before.
+ */
+ inline void set (int i, T t) {
+ assert (i >= 0 && this->num - i > 0);
+ this->array[i] = t;
+ }
+
+ /**
+ * \brief Store an object at the end of the vector.
+ */
+ inline void setLast (T t) {
+ assert (this->num > 0);
+ this->array[this->num - 1] = t;
+ }
+};
+
+/**
+ * \brief Container similar to lout::misc::SimpleVector, but some cases
+ * of insertion optimized (used for hyphenation).
+ *
+ * For hyphenation, words are often split, so that some space must be
+ * inserted by the method NotSoSimpleVector::insert. Typically, some
+ * elements are inserted quite at the beginning (when the word at the
+ * end of the first or at the beginning of the second line is
+ * hyphenated), then, a bit further (end of second line/beginning of
+ * third line) and so on. In the first time, nearly all words must be
+ * moved; in the second time, a bit less, etc. After all, using a
+ * simple vector would result in O(n<sup>2</sup>) number of elements
+ * moved total. With this class, however, the number can be kept at
+ * O(n).
+ *
+ * The basic idea is to keep an extra array (actually two, of which
+ * the second one is used temporarily), which is inserted in a logical
+ * way. Since there is only one extra array at max, reading is rather
+ * simple and fast (see NotSoSimpleVector::getRef): check whether the
+ * position is before, within, or after the extra array. The first
+ * insertion is also rather simple, when the extra array has to be
+ * created. The following sketch illustrates the most complex case,
+ * when an extra array exists, and something is inserted after it (the
+ * case for which this class has been optimized):
+ *
+ * \image html not-so-simple-container.png
+ *
+ * Dotted lines are used to keep the boxes aligned.
+ *
+ * As you see, only a relatively small fraction of elements has to be
+ * moved.
+ *
+ * There are some other cases, which have to be documented.
+ */
+template <class T> class NotSoSimpleVector
+{
+private:
+ T *arrayMain, *arrayExtra1, *arrayExtra2;
+ int numMain, numExtra, numAllocMain, numAllocExtra, startExtra;
+
+ inline void resizeMain ()
+ {
+ /* This algorithm was tuned for memory&speed with this huge page:
+ * http://downloads.mysql.com/docs/refman-6.0-en.html.tar.gz
+ */
+ if (arrayMain == NULL) {
+ this->numAllocMain = 1;
+ this->arrayMain = (T*) malloc (sizeof (T));
+ }
+ if (this->numAllocMain < this->numMain) {
+ this->numAllocMain = (this->numMain < 100) ?
+ this->numMain : this->numMain + this->numMain/10;
+ this->arrayMain =
+ (T*) realloc(this->arrayMain, (this->numAllocMain * sizeof (T)));
+ }
+ }
+
+ inline void resizeExtra ()
+ {
+ /* This algorithm was tuned for memory&speed with this huge page:
+ * http://downloads.mysql.com/docs/refman-6.0-en.html.tar.gz
+ */
+ if (arrayExtra1 == NULL) {
+ this->numAllocExtra = 1;
+ this->arrayExtra1 = (T*) malloc (sizeof (T));
+ this->arrayExtra2 = (T*) malloc (sizeof (T));
+ }
+ if (this->numAllocExtra < this->numExtra) {
+ this->numAllocExtra = (this->numExtra < 100) ?
+ this->numExtra : this->numExtra + this->numExtra/10;
+ this->arrayExtra1 =
+ (T*) realloc(this->arrayExtra1, (this->numAllocExtra * sizeof (T)));
+ this->arrayExtra2 =
+ (T*) realloc(this->arrayExtra2, (this->numAllocExtra * sizeof (T)));
+ }
+ }
+
+ void consolidate ()
+ {
+ if (startExtra != -1) {
+ numMain += numExtra;
+ resizeMain ();
+ memmove (arrayMain + startExtra + numExtra, arrayMain + startExtra,
+ (numMain - (startExtra + numExtra)) * sizeof (T));
+ memmove (arrayMain + startExtra, arrayExtra1, numExtra * sizeof (T));
+ startExtra = -1;
+ numExtra = 0;
+ }
+ }
+
+public:
+ inline NotSoSimpleVector (int initAlloc)
+ {
+ this->numMain = this->numExtra = 0;
+ this->numAllocMain = initAlloc;
+ this->numAllocExtra = initAlloc;
+ this->arrayMain = this->arrayExtra1 = this->arrayExtra2 = NULL;
+ this->startExtra = -1;
+ }
+
+ inline NotSoSimpleVector (const NotSoSimpleVector &o)
+ {
+ this->arrayMain = NULL;
+ this->numMain = o.numMain;
+ this->numAllocMain = o.numAllocMain;
+ resizeMain ();
+ memcpy (this->arrayMain, o.arrayMain, sizeof (T) * numMain);
+
+ this->arrayExtra = NULL;
+ this->numExtra = o.numExtra;
+ this->numAllocExtra = o.numAllocExtra;
+ resizeExtra ();
+ memcpy (this->arrayExtra, o.arrayExtra, sizeof (T) * numExtra);
+
+ this->startExtra = o.startExtra;
+ }
+
+ inline ~NotSoSimpleVector ()
+ {
+ if (this->arrayMain)
+ free (this->arrayMain);
+ if (this->arrayExtra1)
+ free (this->arrayExtra1);
+ if (this->arrayExtra2)
+ free (this->arrayExtra2);
+ }
+
+ inline int size() const { return this->numMain + this->numExtra; }
+
+ inline void increase() { setSize(size() + 1); }
+
+ inline void setSize(int newSize)
+ {
+ assert (newSize >= 0);
+ this->numMain = newSize - numExtra;
+ this->resizeMain ();
+ }
+
+ void insert (int index, int numInsert)
+ {
+ assert (numInsert >= 0);
+
+ // The following lines are a simple (but inefficient) replacement.
+ //setSize (numMain + numInsert);
+ //memmove (arrayMain + index + numInsert, arrayMain + index,
+ // (numMain - index - numInsert) * sizeof (T));
+ //return;
+
+ if (this->startExtra == -1) {
+ // simple case
+ this->numExtra = numInsert;
+ this->startExtra = index;
+ resizeExtra ();
+ } else {
+ if (index < startExtra) {
+ consolidate ();
+ insert (index, numInsert);
+ } else if (index < startExtra + numExtra) {
+ int oldNumExtra = numExtra;
+ numExtra += numInsert;
+ resizeExtra ();
+
+ int toMove = startExtra + oldNumExtra - index;
+ memmove (arrayExtra1 + numExtra - toMove,
+ arrayExtra1 + index - startExtra,
+ toMove * sizeof (T));
+ } else {
+ int oldNumExtra = numExtra;
+ numExtra += numInsert;
+ resizeExtra ();
+
+ // Note: index refers to the *logical* adress, not to the
+ // *physical* one.
+ int diff = index - this->startExtra - oldNumExtra;
+ T *arrayMainI = arrayMain + this->startExtra;
+ for (int i = diff + oldNumExtra - 1; i >= 0; i--) {
+ T *src = i < oldNumExtra ?
+ this->arrayExtra1 + i : arrayMainI + (i - oldNumExtra);
+ T *dest = i < diff ?
+ arrayMainI + i : arrayExtra2 + (i - diff);
+ *dest = *src;
+ }
+
+ memcpy (arrayExtra1, arrayExtra2, sizeof (T) * oldNumExtra);
+ startExtra = index - oldNumExtra;
+ }
+ }
+ }
+
+ /**
+ * \brief Return the reference of one element.
+ *
+ * \sa misc::SimpleVector::get
+ */
+ inline T* getRef (int i) const
+ {
+ if (this->startExtra == -1) {
+ assert (i >= 0 && i < this->numMain);
+ return this->arrayMain + i;
+ } else {
+ if (i < this->startExtra) {
+ assert (i >= 0);
+ return this->arrayMain + i;
+ } else if (i >= this->startExtra + this->numExtra) {
+ // The original assertion
+ ///
+ // "assert (i < this->numMain + this->numExtra)"
+ //
+ // causes this warnung in dw::Textblock::breakAdded:
+ //
+ // "assuming signed overflow does not occur when assuming that
+ // (X - c) > X is always false [-Wstrict-overflow]"
+ //
+ // Subtracting numExtra from both sides solves this,
+ // interrestingly.
+
+ assert (i - this->numExtra < this->numMain);
+ return this->arrayMain + i - this->numExtra;
+ } else
+ return this->arrayExtra1 + i - this->startExtra;
+ }
+ }
+
+ /**
+ * \brief Return the one element, explicitly.
+ *
+ * The element is copied, so for complex elements, you should rather used
+ * misc::SimpleVector::getRef.
+ */
+ inline T get (int i) const
+ {
+ return *(this->getRef(i));
+ }
+
+ /**
+ * \brief Return the reference of the first element (convenience method).
+ */
+ inline T* getFirstRef () const {
+ assert (size () > 0);
+ return this->getRef(0);
+ }
+
+ /**
+ * \brief Return the first element, explicitly.
+ */
+ inline T getFirst () const {
+ return *(this->getFirstRef());
+ }
+
+ /**
+ * \brief Return the reference of the last element (convenience method).
+ */
+ inline T* getLastRef () const {
+ assert (size () > 0);
+ return this->getRef(size () - 1);
+ }
+
+ /**
+ * \brief Return the last element, explicitly.
+ */
+ inline T getLast () const {
+ return *(this->getLastRef());
+ }
+
+ /**
+ * \brief Store an object in the vector.
+ *
+ * Unlike in container::untyped::Vector and container::typed::Vector,
+ * you have to care about the size, so a call to
+ * misc::SimpleVector::increase or misc::SimpleVector::setSize may
+ * be necessary before.
+ */
+ inline void set (int i, T t) {
+ *(this->getRef(i)) = t;
+ }
+
+ /**
+ * \brief Store an object at the end of the vector.
+ */
+ inline void setLast (T t) {
+ *(this->getLastRef()) = t;
+ }
+};
+
+/**
+ * \brief A class for fast concatenation of a large number of strings.
+ */
+class StringBuffer
+{
+private:
+ struct Node
+ {
+ char *data;
+ Node *next;
+ };
+
+ Node *firstNode, *lastNode;
+ int numChars;
+ char *str;
+ bool strValid;
+
+public:
+ StringBuffer();
+ ~StringBuffer();
+
+ /**
+ * \brief Append a NUL-terminated string to the buffer, with copying.
+ *
+ * A copy is kept in the buffer, so the caller does not have to care
+ * about memory management.
+ */
+ inline void append(const char *str) { appendNoCopy(strdup(str)); }
+ inline void appendInt(int n)
+ { char buf[32]; sprintf (buf, "%d", n); append (buf); }
+ inline void appendPointer(void *p)
+ { char buf[32]; sprintf (buf, "%p", p); append (buf); }
+ inline void appendBool(bool b) { append (b ? "true" : "false"); }
+ void appendNoCopy(char *str);
+ const char *getChars();
+ void clear ();
+};
+
+
+/**
+ * \brief A bit set, which automatically reallocates when needed.
+ */
+class BitSet
+{
+private:
+ unsigned char *bits;
+ int numBytes;
+
+ inline int bytesForBits(int bits) { return bits == 0 ? 1 : (bits + 7) / 8; }
+
+public:
+ BitSet(int initBits);
+ ~BitSet();
+ void intoStringBuffer(misc::StringBuffer *sb);
+ bool get(int i) const;
+ void set(int i, bool val);
+ void clear();
+};
+
+/**
+ * \brief A simple allocator optimized to handle many small chunks of memory.
+ * The chunks can not be free'd individually. Instead the whole zone must be
+ * free'd with zoneFree().
+ */
+class ZoneAllocator
+{
+private:
+ size_t poolSize, poolLimit, freeIdx;
+ SimpleVector <char*> *pools;
+ SimpleVector <char*> *bulk;
+
+public:
+ ZoneAllocator (size_t poolSize) {
+ this->poolSize = poolSize;
+ this->poolLimit = poolSize / 4;
+ this->freeIdx = poolSize;
+ this->pools = new SimpleVector <char*> (1);
+ this->bulk = new SimpleVector <char*> (1);
+ };
+
+ ~ZoneAllocator () {
+ zoneFree ();
+ delete pools;
+ delete bulk;
+ }
+
+ inline void * zoneAlloc (size_t t) {
+ void *ret;
+
+ if (t > poolLimit) {
+ bulk->increase ();
+ bulk->set (bulk->size () - 1, (char*) malloc (t));
+ return bulk->get (bulk->size () - 1);
+ }
+
+ if (t > poolSize - freeIdx) {
+ pools->increase ();
+ pools->set (pools->size () - 1, (char*) malloc (poolSize));
+ freeIdx = 0;
+ }
+
+ ret = pools->get (pools->size () - 1) + freeIdx;
+ freeIdx += t;
+ return ret;
+ }
+
+ inline void zoneFree () {
+ for (int i = 0; i < pools->size (); i++)
+ free (pools->get (i));
+ pools->setSize (0);
+ for (int i = 0; i < bulk->size (); i++)
+ free (bulk->get (i));
+ bulk->setSize (0);
+ freeIdx = poolSize;
+ }
+
+ inline const char *strndup (const char *str, size_t t) {
+ char *new_str = (char *) zoneAlloc (t + 1);
+ memcpy (new_str, str, t);
+ new_str[t] = '\0';
+ return new_str;
+ }
+
+ inline const char *strdup (const char *str) {
+ return strndup (str, strlen (str));
+ }
+};
+
+} // namespace misc
+
+} // namespace lout
+
+#endif // __LOUT_MISC_HH__
diff --git a/lout/msg.h b/lout/msg.h
new file mode 100644
index 0000000..4993c10
--- /dev/null
+++ b/lout/msg.h
@@ -0,0 +1,39 @@
+#ifndef __MSG_H__
+#define __MSG_H__
+
+#include <stdio.h>
+
+#define prefs_show_msg 1
+
+#define D_STMT_START do
+#define D_STMT_END while (0)
+
+/*
+ * You can disable any MSG* macro by adding the '_' prefix.
+ */
+#define _MSG(...)
+#define _MSG_WARN(...)
+#define _MSG_ERR(...)
+
+
+#define MSG(...) \
+ D_STMT_START { \
+ if (prefs_show_msg){ \
+ printf(__VA_ARGS__); \
+ fflush (stdout); \
+ } \
+ } D_STMT_END
+
+#define MSG_WARN(...) \
+ D_STMT_START { \
+ if (prefs_show_msg) \
+ printf("** WARNING **: " __VA_ARGS__); \
+ } D_STMT_END
+
+#define MSG_ERR(...) \
+ D_STMT_START { \
+ if (prefs_show_msg) \
+ printf("** ERROR **: " __VA_ARGS__); \
+ } D_STMT_END
+
+#endif /* __MSG_H__ */
diff --git a/lout/object.cc b/lout/object.cc
new file mode 100644
index 0000000..933e7aa
--- /dev/null
+++ b/lout/object.cc
@@ -0,0 +1,395 @@
+/*
+ * RTFL (originally part of dillo)
+ *
+ * Copyright 2005-2007 Sebastian Geerken <sgeerken@dillo.org>
+ *
+ * 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; with the following exception:
+ *
+ * The copyright holders of RTFL give you permission to link this file
+ * statically or dynamically against all versions of the graphviz
+ * library, which are published by AT&T Corp. under one of the following
+ * licenses:
+ *
+ * - Common Public License version 1.0 as published by International
+ * Business Machines Corporation (IBM), or
+ * - Eclipse Public License version 1.0 as published by the Eclipse
+ * Foundation.
+ *
+ * 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/>.
+ */
+
+
+
+#include "object.hh"
+#include <stdio.h>
+#include <stdint.h>
+#include <config.h>
+
+namespace lout {
+
+namespace object {
+
+// ------------
+// Object
+// ------------
+
+/**
+ * \brief The destructor is defined as virtual (but not abstract), so that
+ * destruction of Object's works properly.
+ */
+Object::~Object()
+{
+}
+
+/**
+ * \brief Returns, whether two objects are equal.
+ *
+ * The caller should ensure, that this and the object have the same class;
+ * this makes casting of "other" safe. Typically, an implementation should
+ * check this == other first, the caller can assume a fast implementation.
+ */
+bool Object::equals(Object *other)
+{
+ misc::assertNotReached ();
+ return false;
+}
+
+/**
+ * \brief Return a hash value for the object.
+ */
+int Object::hashValue()
+{
+ fprintf (stderr, "Object::hashValue() should be implemented.\n");
+ return 0;
+}
+
+/**
+ * \brief Return an exact copy of the object.
+ */
+Object *Object::clone()
+{
+ misc::assertNotReached ();
+ return NULL;
+}
+
+/**
+ * \brief Use object::Object::intoStringBuffer to return a textual
+ * representation of the object.
+ *
+ * The caller does not have to free the memory, object::Object is responsible
+ * for this.
+ */
+const char *Object::toString()
+{
+ /** \todo garbage! */
+ misc::StringBuffer sb;
+ intoStringBuffer(&sb);
+ char *s = strdup(sb.getChars());
+ return s;
+}
+
+/**
+ * \brief Store a textual representation of the object in a misc::StringBuffer.
+ *
+ * This is used by object::Object::toString.
+ */
+void Object::intoStringBuffer(misc::StringBuffer *sb)
+{
+ sb->append("<not further specified object ");
+ sb->appendPointer(this);
+ sb->append(">");
+}
+
+/**
+ * \brief Return the number of bytes, this object totally uses.
+ */
+size_t Object::sizeOf()
+{
+ fprintf (stderr, "Object::sizeOf() should be implemented.\n");
+ return sizeof(Object*);
+}
+
+// ----------------
+// Comparator
+// ----------------
+
+Comparator *Comparator::compareFunComparator = NULL;
+
+/**
+ * \brief This static method may be used as compare function for
+ * qsort(3) and bsearch(3), for an array of Object* (Object*[] or
+ * Object**).
+ *
+ * "compareFunComparator" should be set before.
+ *
+ * \todo Not reentrant. Consider switching to reentrant variants
+ * (qsort_r), and compare function with an additional argument.
+ */
+int Comparator::compareFun(const void *p1, const void *p2)
+{
+ return compareFunComparator->compare (*(Object**)p1, *(Object**)p2);
+}
+
+// ------------------------
+// StandardComparator
+// ------------------------
+
+int StandardComparator::compare(Object *o1, Object *o2)
+{
+ if (o1 && o2)
+ return ((Comparable*)o1)->compareTo ((Comparable*)o2);
+ else if (o1)
+ return 1;
+ else if (o2)
+ return -1;
+ else
+ return 0;
+}
+
+StandardComparator standardComparator;
+
+// -------------
+// Pointer
+// -------------
+
+bool Pointer::equals(Object *other)
+{
+ return value == ((Pointer*)other)->value;
+}
+
+int Pointer::hashValue()
+{
+/* For some unknown reason, this doesn't compile on some 64bit platforms:
+ *
+ * if (sizeof (int) == sizeof (void*))
+ * return (int)value;
+ * else
+ * return ((int*)&value)[0] ^ ((int*)&value)[1];
+ */
+#if SIZEOF_VOID_P == 4
+ // Assuming that sizeof(void*) == sizeof(int); on 32 bit systems.
+ return (int)value;
+#else
+ // Assuming that sizeof(void*) == 2 * sizeof(int); on 64 bit
+ // systems (int is still 32 bit).
+ // Combine both parts of the pointer value *itself*, not what it
+ // points to, by first referencing it (operator "&"), then
+ // dereferencing it again (operator "[]").
+ return ((intptr_t)value >> 32) ^ ((intptr_t)value);
+#endif
+}
+
+void Pointer::intoStringBuffer(misc::StringBuffer *sb)
+{
+ char buf[64];
+ snprintf(buf, sizeof(buf), "%p", value);
+ sb->append(buf);
+}
+
+// -------------
+// Integer
+// -------------
+
+bool Integer::equals(Object *other)
+{
+ return value == ((Integer*)other)->value;
+}
+
+int Integer::hashValue()
+{
+ return (int)value;
+}
+
+void Integer::intoStringBuffer(misc::StringBuffer *sb)
+{
+ char buf[64];
+ sprintf(buf, "%d", value);
+ sb->append(buf);
+}
+
+int Integer::compareTo(Comparable *other)
+{
+ return value - ((Integer*)other)->value;
+}
+
+// -------------
+// Boolean
+// -------------
+
+bool Boolean::equals(Object *other)
+{
+ bool value2 = ((Boolean*)other)->value;
+ // TODO Does "==" work?
+ return (value && value2) || (!value && value2);
+}
+
+int Boolean::hashValue()
+{
+ return value ? 1 : 0;
+}
+
+void Boolean::intoStringBuffer(misc::StringBuffer *sb)
+{
+ sb->append(value ? "true" : "false");
+}
+
+int Boolean::compareTo(Comparable *other)
+{
+ return (value ? 1 : 0) - (((Boolean*)other)->value ? 1 : 0);
+}
+
+// -----------------
+// ConstString
+// -----------------
+
+bool ConstString::equals(Object *other)
+{
+ ConstString *otherString = (ConstString*)other;
+ return
+ this == other ||
+ (str == NULL && otherString->str == NULL) ||
+ (str != NULL && otherString->str != NULL &&
+ strcmp(str, otherString->str) == 0);
+}
+
+int ConstString::hashValue()
+{
+ return hashValue(str);
+}
+
+
+int ConstString::compareTo(Comparable *other)
+{
+ String *otherString = (String*)other;
+ if (str && otherString->str)
+ return strcmp(str, otherString->str);
+ else if (str)
+ return 1;
+ else if (otherString->str)
+ return -1;
+ else
+ return 0;
+}
+
+
+int ConstString::hashValue(const char *str)
+{
+ if (str) {
+ int h = 0;
+ for (int i = 0; str[i]; i++)
+ h = (h * 256 + str[i]);
+ return h;
+ } else
+ return 0;
+}
+
+void ConstString::intoStringBuffer(misc::StringBuffer *sb)
+{
+ sb->append(str);
+}
+
+// ------------
+// String
+// ------------
+
+String::String (const char *str): ConstString (str ? strdup(str) : NULL)
+{
+}
+
+String::~String ()
+{
+ if (str)
+ free((char *)str);
+}
+
+// ------------
+// Pair
+// ------------
+
+PairBase::PairBase(Object *first, Object *second)
+{
+ this->first = first;
+ this->second = second;
+}
+
+PairBase::~PairBase()
+{
+ if (first)
+ delete first;
+ if (second)
+ delete second;
+}
+
+bool PairBase::equals(Object *other)
+{
+ PairBase *otherPair = (PairBase*)other;
+
+ return
+ // Identical?
+ this == other || (
+ (// Both first parts are NULL, ...
+ (first == NULL && otherPair->first == NULL) ||
+ // ... or both first parts are not NULL and equal
+ (first != NULL && otherPair->first != NULL
+ && first->equals (otherPair->first))) &&
+ // Same with second part.
+ ((second == NULL && otherPair->second == NULL) ||
+ (second != NULL && otherPair->second != NULL
+ && second->equals (otherPair->second))));
+}
+
+int PairBase::hashValue()
+{
+ int value = 0;
+
+ if (first)
+ value ^= first->hashValue();
+ if (second)
+ value ^= second->hashValue();
+
+ return value;
+}
+
+void PairBase::intoStringBuffer(misc::StringBuffer *sb)
+{
+ sb->append("<pair: ");
+
+ if (first)
+ first->intoStringBuffer(sb);
+ else
+ sb->append("(nil)");
+
+ sb->append(",");
+
+ if (second)
+ second->intoStringBuffer(sb);
+ else
+ sb->append("(nil)");
+
+ sb->append(">");
+}
+
+size_t PairBase::sizeOf()
+{
+ size_t size = 0;
+
+ if (first)
+ size += first->sizeOf();
+ if (second)
+ size += second->sizeOf();
+
+ return size;
+}
+
+} // namespace object
+
+} // namespace lout
diff --git a/lout/object.hh b/lout/object.hh
new file mode 100644
index 0000000..3ba7b59
--- /dev/null
+++ b/lout/object.hh
@@ -0,0 +1,238 @@
+#ifndef __LOUT_OBJECT_HH__
+#define __LOUT_OBJECT_HH__
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "misc.hh"
+
+namespace lout {
+
+/**
+ * \brief Here, some common classes (or interfaces) are defined, to standardize
+ * the access to other classes.
+ */
+namespace object {
+
+/**
+ * \brief This is the base class for many other classes, which defines very
+ * common virtual methods.
+ *
+ * For convenience, none of them are abstract, but they
+ * must be defined, when they are needed, especially for containers.
+ */
+class Object
+{
+public:
+ virtual ~Object();
+ virtual bool equals(Object *other);
+ virtual int hashValue();
+ virtual Object *clone();
+ virtual void intoStringBuffer(misc::StringBuffer *sb);
+ const char *toString();
+ virtual size_t sizeOf();
+};
+
+/**
+ * \brief Instances of a sub class of may be compared (less, greater).
+ *
+ * Used for sorting etc.
+ */
+class Comparable: public Object
+{
+public:
+ /**
+ * \brief Compare two objects, this and other.
+ *
+ * Return a value < 0, when this is less than other, a value > 0,
+ * when this is greater than other, or 0, when this and other are
+ * equal.
+ *
+ * If c1.equals(c2) (as defined in Object), c1.compareTo(c2) must
+ * be 0, but, unlike you may expect, the reversed is not
+ * necessarily true. This method returns 0, if, according to the
+ * rules for sorting, there is no difference, but there may still
+ * be differences (not relevant for sorting), which "equals" will
+ * care about.
+ */
+ virtual int compareTo(Comparable *other) = 0;
+};
+
+/**
+ * \brief Used for other orders as the one defined by Comparable.
+ *
+ * Compared objects must not neccessary be instances of Comparable.
+ */
+class Comparator: public Object
+{
+public:
+ /**
+ * \brief Compare two objects o1 and o2.
+ *
+ * Return a value < 0, when o1 is less than o2, a value > 0, when o1
+ * is greater than o2, or 0, when o1 and o2 are equal.
+ *
+ * If o1.equals(o2) (as defined in Object), compare(o1, o2) must be
+ * 0, but, unlike you may expect, the reversed is not necessarily
+ * true. This method returns 0, if, according to the rules for
+ * sorting, there is no difference, but there may still be
+ * differences (not relevant for sorting), which "equals" will care
+ * about.
+ */
+ virtual int compare(Object *o1, Object *o2) = 0;
+
+ static Comparator *compareFunComparator;
+ static int compareFun(const void *p1, const void *p2);
+};
+
+class StandardComparator: public Comparator
+{
+public:
+ int compare(Object *o1, Object *o2);
+};
+
+extern StandardComparator standardComparator;
+
+/**
+ * \brief An object::Object wrapper for void pointers.
+ */
+class Pointer: public Object
+{
+private:
+ void *value;
+
+public:
+ Pointer(void *value) { this->value = value; }
+ bool equals(Object *other);
+ int hashValue();
+ void intoStringBuffer(misc::StringBuffer *sb);
+ inline void *getValue() { return value; }
+};
+
+/**
+ * \brief A typed version of object::Pointer.
+ */
+template <class T> class TypedPointer: public Pointer
+{
+public:
+ inline TypedPointer(T *value) : Pointer ((void*)value) { }
+ inline T *getTypedValue() { return (T*)getValue(); }
+};
+
+
+/**
+ * \brief An object::Object wrapper for int's.
+ */
+class Integer: public Comparable
+{
+ int value;
+
+public:
+ Integer(int value) { this->value = value; }
+ bool equals(Object *other);
+ int hashValue();
+ void intoStringBuffer(misc::StringBuffer *sb);
+ int compareTo(Comparable *other);
+ inline int getValue() { return value; }
+};
+
+
+/**
+ * \brief An object::Object wrapper for bool's.
+ */
+class Boolean: public Comparable
+{
+ bool value;
+
+public:
+ Boolean(bool value) { this->value = value; }
+ bool equals(Object *other);
+ int hashValue();
+ void intoStringBuffer(misc::StringBuffer *sb);
+ int compareTo(Comparable *other);
+ inline bool getValue() { return value; }
+};
+
+
+/**
+ * \brief An object::Object wrapper for constant strings (char*).
+ *
+ * As opposed to object::String, the char array is not copied.
+ */
+class ConstString: public Comparable
+{
+protected:
+ const char *str;
+
+public:
+ ConstString(const char *str) { this->str = str; }
+ bool equals(Object *other);
+ int hashValue();
+ int compareTo(Comparable *other);
+ void intoStringBuffer(misc::StringBuffer *sb);
+
+ inline const char *chars() { return str; }
+
+ static int hashValue(const char *str);
+};
+
+
+/**
+ * \brief An object::Object wrapper for strings (char*).
+ *
+ * As opposed to object::ConstantString, the char array is copied.
+ */
+class String: public ConstString
+{
+public:
+ String(const char *str);
+ ~String();
+};
+
+/**
+ * \todo Comment
+ */
+class PairBase: public Object
+{
+protected:
+ Object *first, *second;
+
+public:
+ PairBase(Object *first, Object *second);
+ ~PairBase();
+
+ bool equals(Object *other);
+ int hashValue();
+ void intoStringBuffer(misc::StringBuffer *sb);
+ size_t sizeOf();
+};
+
+/**
+ * \todo Comment
+ */
+class Pair: public PairBase
+{
+public:
+ Pair(Object *first, Object *second): PairBase (first, second) { }
+
+ inline Object *getFirst () { return first; }
+ inline Object *getSecond () { return second; }
+};
+
+/**
+ * \todo Comment
+ */
+template <class F, class S> class TypedPair: public PairBase
+{
+public:
+ TypedPair(F *first, S *second): PairBase (first, second) { }
+
+ inline F *getFirst () { return first; }
+ inline S *getSecond () { return second; }
+};
+
+} // namespace object
+
+} // namespace lout
+
+#endif // __LOUT_OBJECT_HH__
diff --git a/lout/signal.cc b/lout/signal.cc
new file mode 100644
index 0000000..be92d2c
--- /dev/null
+++ b/lout/signal.cc
@@ -0,0 +1,180 @@
+/*
+ * RTFL (originally part of dillo)
+ *
+ * Copyright 2005-2007 Sebastian Geerken <sgeerken@dillo.org>
+ *
+ * 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; with the following exception:
+ *
+ * The copyright holders of RTFL give you permission to link this file
+ * statically or dynamically against all versions of the graphviz
+ * library, which are published by AT&T Corp. under one of the following
+ * licenses:
+ *
+ * - Common Public License version 1.0 as published by International
+ * Business Machines Corporation (IBM), or
+ * - Eclipse Public License version 1.0 as published by the Eclipse
+ * Foundation.
+ *
+ * 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/>.
+ */
+
+
+
+#include "signal.hh"
+
+namespace lout {
+namespace signal {
+
+using namespace container::typed;
+
+// ------------
+// Emitter
+// ------------
+
+Emitter::Emitter ()
+{
+ receivers = new List <Receiver> (false);
+}
+
+Emitter::~Emitter ()
+{
+ for (Iterator<Receiver> it = receivers->iterator (); it.hasNext (); ) {
+ Receiver *receiver = it.getNext ();
+ receiver->unconnectFrom (this);
+ }
+ delete receivers;
+}
+
+void Emitter::intoStringBuffer(misc::StringBuffer *sb)
+{
+ sb->append ("<emitter: ");
+ receivers->intoStringBuffer (sb);
+ sb->append (">");
+}
+
+void Emitter::unconnect (Receiver *receiver)
+{
+ receivers->removeRef (receiver);
+}
+
+/**
+ * \brief Connect a receiver to the emitter.
+ *
+ * This is protected, a sub class should define a wrapper, with the respective
+ * receiver as an argument, to gain type safety.
+ */
+void Emitter::connect (Receiver *receiver)
+{
+ receivers->append (receiver);
+ receiver->connectTo (this);
+}
+
+/**
+ * \brief Emit a void signal.
+ *
+ * This method should be called by a wrapper (return value void), which
+ * \em folds the signal, and delegates the emission to here.
+ */
+void Emitter::emitVoid (int signalNo, int argc, Object **argv)
+{
+ for (Iterator <Receiver> it = receivers->iterator (); it.hasNext (); ) {
+ Receiver *receiver = it.getNext();
+ emitToReceiver (receiver, signalNo, argc, argv);
+ }
+}
+
+/**
+ * \brief Emit a boolean signal.
+ *
+ * This method should be called by a wrapper, which \em folds the signal,
+ * delegates the emission to here, and returns the same boolean value.
+ */
+bool Emitter::emitBool (int signalNo, int argc, Object **argv)
+{
+ bool b = false, bt;
+
+ for (Iterator <Receiver> it = receivers->iterator (); it.hasNext (); ) {
+ Receiver *receiver = it.getNext();
+ // Note: All receivers are called, even if one returns true.
+ // Therefore, something like
+ // b = b || emitToReceiver (receiver, signalNo, argc, argv);
+ // does not work.
+ bt = emitToReceiver (receiver, signalNo, argc, argv);
+ b = b || bt;
+ }
+
+ return b;
+}
+
+
+// --------------
+// Receiver
+// --------------
+
+Receiver::Receiver()
+{
+ emitters = new List <Emitter> (false);
+}
+
+Receiver::~Receiver()
+{
+ for (Iterator<Emitter> it = emitters->iterator(); it.hasNext(); ) {
+ Emitter *emitter = it.getNext();
+ emitter->unconnect (this);
+ }
+ delete emitters;
+}
+
+void Receiver::intoStringBuffer(misc::StringBuffer *sb)
+{
+ // emitters are not listed, to prevent recursion
+ sb->append ("<receiver>");
+}
+
+void Receiver::connectTo(Emitter *emitter)
+{
+ emitters->append (emitter);
+}
+
+void Receiver::unconnectFrom(Emitter *emitter)
+{
+ emitters->removeRef (emitter);
+}
+
+// ------------------------
+// ObservedObject
+// ------------------------
+
+bool ObservedObject::DeletionEmitter::emitToReceiver (Receiver *receiver,
+ int signalNo,
+ int argc, Object **argv)
+{
+ object::TypedPointer <ObservedObject> *p =
+ (object::TypedPointer<ObservedObject>*)argv[0];
+ ((DeletionReceiver*)receiver)->deleted (p->getTypedValue ());
+ return false;
+}
+
+void ObservedObject::DeletionEmitter::emitDeletion (ObservedObject *obj)
+{
+ object::TypedPointer <ObservedObject> p(obj);
+ object::Object *argv[1] = { &p };
+ emitVoid (0, 1, argv);
+}
+
+ObservedObject::~ObservedObject()
+{
+ deletionEmitter.emitDeletion (this);
+}
+
+} // namespace signal
+} // namespace lout
diff --git a/lout/signal.hh b/lout/signal.hh
new file mode 100644
index 0000000..117779d
--- /dev/null
+++ b/lout/signal.hh
@@ -0,0 +1,310 @@
+#ifndef __LOUT_SIGNALS_HH__
+#define __LOUT_SIGNALS_HH__
+
+#include "object.hh"
+#include "container.hh"
+
+namespace lout {
+
+/**
+ * \brief This namespace provides base classes to define signals.
+ *
+ * By using signals, objects may be connected at run-time, e.g. a general
+ * button widget may be connected to another application-specific object,
+ * which reacts on the operations on the button by the user. In this case,
+ * the button e.g. defines a signal "clicked", which is "emitted" each
+ * time the user clicks on the button. After the application-specific
+ * object has been connected to this signal, a specific method of it will
+ * be called each time, this button emits the "clicked" signal.
+ *
+ * Below, we will call the level, on which signals are defined, the
+ * "general level", and the level, on which the signals are connected,
+ * the "caller level".
+ *
+ * <h3>Defining Signals</h3>
+ *
+ * Typically, signals are grouped. To define a signal group \em bar for your
+ * class \em Foo, you have to define two classes, the emitter and the
+ * receiver (BarEmitter and BarReceiver), and instantiate the emitter:
+ *
+ * \dot
+ * digraph G {
+ * node [shape=record, fontname=Helvetica, fontsize=10];
+ * edge [arrowhead="none", arrowtail="empty", labelfontname=Helvetica,
+ * labelfontsize=10, color="#404040", labelfontcolor="#000080"];
+ * fontname=Helvetica; fontsize=10;
+ *
+ * subgraph cluster_signal {
+ * style="dashed"; color="#000080"; fontname=Helvetica; fontsize=10;
+ * label="signal";
+ *
+ * Emitter [color="#a0a0a0", URL="\ref signal::Emitter"];
+ * Receiver [color="#a0a0a0", URL="\ref signal::Receiver"];
+ * }
+ *
+ * subgraph cluster_foo {
+ * style="dashed"; color="#000080"; fontname=Helvetica; fontsize=10;
+ * label="General (foo)";
+ *
+ * Foo;
+ * BarEmitter;
+ * BarReceiver [color="#a0a0a0"];
+ * }
+ *
+ * Emitter -> BarEmitter;
+ * Receiver -> BarReceiver;
+ * Foo -> BarEmitter [arrowhead="open", arrowtail="none",
+ * headlabel="1", taillabel="1"];
+ * }
+ * \enddot
+ *
+ * <center>[\ref uml-legend "legend"]</center>
+ *
+ * BarEmitter (class and instance) may be kept private, but BarReceiver must
+ * be public, since the caller of Foo must create a sub class of it. For
+ * BarEmitter, several methods must be implemented, see signal::Emitter for
+ * details. In BarReceiver, only some virtual abstract methods are defined,
+ * which the caller must implement. In this case, it is recommended to define
+ * a connectBar(BarReceiver*) method in Foo, which is delegated to the
+ * BarEmitter.
+ *
+ * <h3>Connecting to Signals</h3>
+ *
+ * A caller, which wants to connect to a signal, must define a sub class of
+ * the receiver, and implement the virtual methods. A typical design looks
+ * like this:
+ *
+ * \dot
+ * digraph G {
+ * node [shape=record, fontname=Helvetica, fontsize=10];
+ * edge [arrowhead="open", arrowtail="none", labelfontname=Helvetica,
+ * labelfontsize=10, color="#404040", labelfontcolor="#000080"];
+ * fontname=Helvetica; fontsize=10;
+ *
+ * subgraph cluster_foo {
+ * style="dashed"; color="#000080"; fontname=Helvetica; fontsize=10;
+ * label="Generall (foo)";
+ *
+ * BarReceiver [color="#a0a0a0"];
+ * }
+ *
+ * subgraph cluster_qix {
+ * style="dashed"; color="#000080"; fontname=Helvetica; fontsize=10;
+ * label="Caller (qix)";
+ *
+ * Qix;
+ * QixBarReceiver;
+ * }
+ *
+ * BarReceiver -> QixBarReceiver [arrowhead="none", arrowtail="empty"];
+ * QixBarReceiver -> Qix [headlabel="1", taillabel="*"];
+ * }
+ * \enddot
+ *
+ * <center>[\ref uml-legend "legend"]</center>
+ *
+ * (We skip "baz" in the canon, for better readability.)
+ *
+ * Here, the QixBarReceiver is connected to the Qix, so that the signals can
+ * be delegated to the Qix. Notice that the receiver gets automatically
+ * disconnected, when deleted (see signal::Receiver::~Receiver).
+ *
+ * <h3>Void and Boolean Signals</h3>
+ *
+ * In the simplest case, signal emitting involves calling a list of
+ * signal receivers (void signals). For boolean signals, the receivers return
+ * a boolean value, and the result of the signal emission (the return value of
+ * signal::Emitter::emitBool) returns the disjunction of the values returned
+ * by the receivers. Typically, a receiver states with its return value,
+ * whether the signal was used in any way, the resulting return value so
+ * indicates, whether at least one receiver has used the signal.
+ *
+ * In Dw, events are processed this way. In the simplest case, they are
+ * delegated to the parent widget, if the widget does not process them (by
+ * returning false). As an addition, signals are emitted, and if a receiver
+ * processes the event, this is handled the same way, as if the widget itself
+ * would have processed it.
+ *
+ * Notice, that also for boolean signals, all receivers are called, even
+ * after one receiver has already returned true.
+ *
+ * <h3>Memory Management</h3>
+ *
+ * <h4>Emitters</h4>
+ *
+ * Emitters are typically instantiated one, for one object emitting the
+ * signals. In the example above, the class Foo will contain a field
+ * "BarEmitter barEmitter" (not as a pointer, "BarEmitter *barEmitter").
+ *
+ * <h4>Receivers</h4>
+ *
+ * It is important, that a emitter never deletes a receiver, it just removes
+ * them from the receivers list. Likewise, when a receiver is deleted, it
+ * unconnects itself from all emitters. (The same receiver instance can indeed
+ * be connected to multiple emitters.) So, the caller has to care about
+ * deleting receivers.
+ *
+ * In the example above, something like that will work:
+ *
+ * \code
+ * class Qix
+ * {
+ * private:
+ * class QixBarReceiver
+ * {
+ * public:
+ * Qix *qix;
+ * // ...
+ * };
+ *
+ * QixBarReceiver barReceiver;
+ *
+ * // ...
+ * };
+ * \endcode
+ *
+ * The constructor of Qix should then set \em qix:
+ *
+ * \code
+ * Qix::Qix ()
+ * {
+ * barReceiver.qix = this.
+ * // ...
+ * }
+ * \endcode
+ *
+ * After this, &\em barReceiver can be connected to all instances of
+ * BarEmitter, also multiple times.
+ */
+namespace signal {
+
+class Receiver;
+
+/**
+ * \brief The base class for signal emitters.
+ *
+ * If defining a signal group, a sub class of this class must be defined,
+ * with
+ *
+ * <ul>
+ * <li> a definition of the different signals (as enumeration),
+ * <li> an implementation of signal::Emitter::emitToReceiver,
+ * <li> wrappers for signal::Emitter::emitVoid and signal::Emitter::emitBool,
+ * respectively (one for each signal), and
+ * <li> a wrapper for signal::Emitter::connect.
+ * </ul>
+ *
+ * There are two representations of signals:
+ *
+ * <ul>
+ * <li> In the \em unfolded representation, the signal itself is represented
+ * by the method itself (in the emitter or the receiver), and the
+ * arguments are represented as normal C++ types.
+ *
+ * <li> \em Folding signals means to represent the signal itself by an integer
+ * number (enumeration), and translate the arguments in an object::Object*
+ * array. (If a given argument is not an instance of object::Object*,
+ * the wrappers in ::object can be used.)
+ * </ul>
+ *
+ * \sa ::signal
+ */
+class Emitter: public object::Object
+{
+ friend class Receiver;
+
+private:
+ container::typed::List <Receiver> *receivers;
+
+ void unconnect (Receiver *receiver);
+
+protected:
+ void emitVoid (int signalNo, int argc, Object **argv);
+ bool emitBool (int signalNo, int argc, Object **argv);
+ void connect(Receiver *receiver);
+
+ /**
+ * \brief A sub class must implement this for a call to a single
+ * receiver.
+ *
+ * This methods gets the signal in a \em folded representation, it has
+ * to unfold it, and pass it to a single receiver. For boolean signals,
+ * the return value of the receiver must be returned, for void signals,
+ * the return value is discarded.
+ */
+ virtual bool emitToReceiver (Receiver *receiver, int signalNo,
+ int argc, Object **argv) = 0;
+
+public:
+ Emitter();
+ ~Emitter();
+
+ void intoStringBuffer(misc::StringBuffer *sb);
+};
+
+/**
+ * \brief The base class for signal receiver base classes.
+ *
+ * If defining a signal group, a sub class of this class must be defined,
+ * in which only the abstract signal methods must be defined.
+ *
+ * \sa ::signal
+ */
+class Receiver: public object::Object
+{
+ friend class Emitter;
+
+private:
+ container::typed::List<Emitter> *emitters;
+
+ void connectTo(Emitter *emitter);
+ void unconnectFrom(Emitter *emitter);
+
+public:
+ Receiver();
+ ~Receiver();
+
+ void intoStringBuffer(misc::StringBuffer *sb);
+};
+
+/**
+ * \brief An observed object has a signal emitter, which tells the
+ * receivers, when the object is deleted.
+ */
+class ObservedObject
+{
+public:
+ class DeletionReceiver: public signal::Receiver
+ {
+ public:
+ virtual void deleted (ObservedObject *object) = 0;
+ };
+
+private:
+ class DeletionEmitter: public signal::Emitter
+ {
+ protected:
+ bool emitToReceiver (signal::Receiver *receiver, int signalNo,
+ int argc, Object **argv);
+
+ public:
+ inline void connectDeletion (DeletionReceiver *receiver)
+ { connect (receiver); }
+
+ void emitDeletion (ObservedObject *obj);
+ };
+
+ DeletionEmitter deletionEmitter;
+
+public:
+ virtual ~ObservedObject();
+
+ inline void connectDeletion (DeletionReceiver *receiver)
+ { deletionEmitter.connectDeletion (receiver); }
+};
+
+} // namespace signal
+
+} // namespace lout
+
+#endif // __LOUT_SIGNALS_HH__
diff --git a/lout/unicode.cc b/lout/unicode.cc
new file mode 100644
index 0000000..da9c27a
--- /dev/null
+++ b/lout/unicode.cc
@@ -0,0 +1,190 @@
+/*
+ * RTFL (originally part of dillo)
+ *
+ * Copyright 2012, 2013 Sebastian Geerken <sgeerken@dillo.org>
+ *
+ * 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; with the following exception:
+ *
+ * The copyright holders of RTFL give you permission to link this file
+ * statically or dynamically against all versions of the graphviz
+ * library, which are published by AT&T Corp. under one of the following
+ * licenses:
+ *
+ * - Common Public License version 1.0 as published by International
+ * Business Machines Corporation (IBM), or
+ * - Eclipse Public License version 1.0 as published by the Eclipse
+ * Foundation.
+ *
+ * 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/>.
+ */
+
+
+#include "unicode.hh"
+#include "misc.hh"
+
+using namespace lout::misc;
+
+namespace lout {
+
+namespace unicode {
+
+static unsigned char alpha[0x500] = {
+ // 0000-007F: C0 Controls and Basic Latin
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xfe, 0xff, 0xff, 0x07, 0xfe, 0xff, 0xff, 0x07,
+ // 0080-00FF: C1 Controls and Latin-1 Supplement
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0x7f, 0xff,
+ // 0100-017F: Latin Extended-A
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ // 0180-024F: Latin Extended-B
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff,
+ // 0250–02AF: IPA Extensions
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff,
+ // 02B0–02FF: Spacing Modifier Letters
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00,
+ // 0300–036F: Combining Diacritical Marks
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ // 0370–03FF: Greek and Coptic
+ 0xcf, 0x00, 0x40, 0x7d, 0xff, 0xff, 0xfb, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff,
+ // 0400–04FF: Cyrillic
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x03, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
+};
+
+/**
+ * Returns whether a given unicode character is an alphabetic character.
+ */
+bool isAlpha (int ch)
+{
+ return ch < 0x500 && (alpha[ch / 8] & (1 << (ch & 7)));
+}
+
+int decodeUtf8 (const char *s)
+{
+ if((s[0] & 0x80) == 0)
+ return s[0];
+ else if((s[0] & 0xe0) == 0xc0 && (s[1] & 0xc0) == 0x80)
+ return ((s[0] & 0x1f) << 6) | (s[1] & 0x3f);
+ else if((s[0] & 0xf0) == 0xe0 && (s[1] & 0xc0) == 0x80
+ && (s[2] & 0xc0) == 0x80)
+ return ((s[0] & 0x0f) << 12) | ((s[1] & 0x3f) << 6) | (s[2] & 0x3f);
+ else if((s[0] & 0xf8) == 0xf0 && (s[1] & 0xc0) == 0x80
+ && (s[2] & 0xc0) == 0x80 && (s[3] & 0xc0) == 0x80)
+ return ((s[0] & 0x0f) << 18) | ((s[1] & 0x3f) << 12)
+ | ((s[2] & 0x3f) << 6) | (s[3] & 0x3f);
+ else
+ // Treat as ISO-8859-1 / ISO-8859-15 / Windows-1252
+ return s[0];
+}
+
+
+int decodeUtf8 (const char *s, int len)
+{
+ if(len >= 1 && (s[0] & 0x80) == 0)
+ return s[0];
+ else if(len >= 2 && (s[0] & 0xe0) == 0xc0 && (s[1] & 0xc0) == 0x80)
+ return ((s[0] & 0x1f) << 6) | (s[1] & 0x3f);
+ else if(len >= 3 && (s[0] & 0xf0) == 0xe0 && (s[1] & 0xc0) == 0x80
+ && (s[2] & 0xc0) == 0x80)
+ return ((s[0] & 0x0f) << 12) | ((s[1] & 0x3f) << 6) | (s[2] & 0x3f);
+ else if(len >= 4 && (s[0] & 0xf8) == 0xf0 && (s[1] & 0xc0) == 0x80
+ && (s[2] & 0xc0) == 0x80 && (s[3] & 0xc0) == 0x80)
+ return ((s[0] & 0x0f) << 18) | ((s[1] & 0x3f) << 12)
+ | ((s[2] & 0x3f) << 6) | (s[3] & 0x3f);
+ else
+ // Treat as ISO-8859-1 / ISO-8859-15 / Windows-1252
+ return s[0];
+}
+
+const char *nextUtf8Char (const char *s)
+{
+ const char *r;
+
+ if (s == NULL || s[0] == 0)
+ r = NULL;
+ else if((s[0] & 0x80) == 0)
+ r = s + 1;
+ else if((s[0] & 0xe0) == 0xc0 && (s[1] & 0xc0) == 0x80)
+ r = s + 2;
+ else if((s[0] & 0xf0) == 0xe0 && (s[1] & 0xc0) == 0x80
+ && (s[2] & 0xc0) == 0x80)
+ r = s + 3;
+ else if((s[0] & 0xf8) == 0xf0 && (s[1] & 0xc0) == 0x80
+ && (s[2] & 0xc0) == 0x80 && (s[3] & 0xc0) == 0x80)
+ r = s + 4;
+ else
+ // invalid UTF-8 sequence: treat as one byte.
+ r = s + 1;
+
+ if (r && r[0] == 0)
+ return NULL;
+ else
+ return r;
+}
+
+const char *nextUtf8Char (const char *s, int len)
+{
+ const char *r;
+
+ if (s == NULL || len <= 0)
+ r = NULL;
+ else if(len >= 1 && (s[0] & 0x80) == 0)
+ r = s + 1;
+ else if(len >= 2 && (s[0] & 0xe0) == 0xc0 && (s[1] & 0xc0) == 0x80)
+ r = s + 2;
+ else if(len >= 3 && (s[0] & 0xf0) == 0xe0 && (s[1] & 0xc0) == 0x80
+ && (s[2] & 0xc0) == 0x80)
+ r = s + 3;
+ else if(len >= 4 && (s[0] & 0xf8) == 0xf0 && (s[1] & 0xc0) == 0x80
+ && (s[2] & 0xc0) == 0x80 && (s[3] & 0xc0) == 0x80)
+ r = s + 4;
+ else
+ // invalid UTF-8 sequence: treat as one byte.
+ r = s + 1;
+
+ if (r && r - s >= len)
+ return NULL;
+ else
+ return r;
+}
+
+int numUtf8Chars (const char *s)
+{
+ int numUtf8 = 0;
+ for (const char *r = s; r; r = nextUtf8Char (r))
+ numUtf8++;
+ return numUtf8;
+}
+
+int numUtf8Chars (const char *s, int len)
+{
+ int numUtf8 = 0;
+ for (const char *r = s; len > 0 && r; r = nextUtf8Char (r, len))
+ numUtf8++;
+ return numUtf8;
+}
+
+} // namespace lout
+
+} // namespace unicode
diff --git a/lout/unicode.hh b/lout/unicode.hh
new file mode 100644
index 0000000..c74fd9b
--- /dev/null
+++ b/lout/unicode.hh
@@ -0,0 +1,30 @@
+#ifndef __UNICODE_HH__
+#define __UNICODE_HH__
+
+namespace lout {
+
+/**
+ * \brief Stuff dealing with Unicode characters: UTF-8, character classes etc.
+ *
+ */
+namespace unicode {
+
+bool isAlpha (int ch);
+
+int decodeUtf8 (const char *s);
+
+int decodeUtf8 (const char *s, int len);
+
+const char *nextUtf8Char (const char *s);
+
+const char *nextUtf8Char (const char *s, int len);
+
+int numUtf8Chars (const char *s);
+
+int numUtf8Chars (const char *s, int len);
+
+} // namespace lout
+
+} // namespace unicode
+
+#endif // __UNICODE_HH__
diff --git a/ltmain.sh b/ltmain.sh
new file mode 100644
index 0000000..147d758
--- /dev/null
+++ b/ltmain.sh
@@ -0,0 +1,11156 @@
+#! /bin/sh
+## DO NOT EDIT - This file generated from ./build-aux/ltmain.in
+## by inline-source v2014-01-03.01
+
+# libtool (GNU libtool) 2.4.6
+# Provide generalized library-building support services.
+# Written by Gordon Matzigkeit <gord@gnu.ai.mit.edu>, 1996
+
+# Copyright (C) 1996-2015 Free Software Foundation, Inc.
+# This is free software; see the source for copying conditions. There is NO
+# warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+# GNU Libtool 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.
+#
+# As a special exception to the GNU General Public License,
+# if you distribute this file as part of a program or library that
+# is built using GNU Libtool, you may include this file under the
+# same distribution terms that you use for the rest of that program.
+#
+# GNU Libtool 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/>.
+
+
+PROGRAM=libtool
+PACKAGE=libtool
+VERSION="2.4.6 Debian-2.4.6-0.1"
+package_revision=2.4.6
+
+
+## ------ ##
+## Usage. ##
+## ------ ##
+
+# Run './libtool --help' for help with using this script from the
+# command line.
+
+
+## ------------------------------- ##
+## User overridable command paths. ##
+## ------------------------------- ##
+
+# After configure completes, it has a better idea of some of the
+# shell tools we need than the defaults used by the functions shared
+# with bootstrap, so set those here where they can still be over-
+# ridden by the user, but otherwise take precedence.
+
+: ${AUTOCONF="autoconf"}
+: ${AUTOMAKE="automake"}
+
+
+## -------------------------- ##
+## Source external libraries. ##
+## -------------------------- ##
+
+# Much of our low-level functionality needs to be sourced from external
+# libraries, which are installed to $pkgauxdir.
+
+# Set a version string for this script.
+scriptversion=2015-01-20.17; # UTC
+
+# General shell script boiler plate, and helper functions.
+# Written by Gary V. Vaughan, 2004
+
+# Copyright (C) 2004-2015 Free Software Foundation, Inc.
+# This is free software; see the source for copying conditions. There is NO
+# warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+# 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.
+
+# As a special exception to the GNU General Public License, if you distribute
+# this file as part of a program or library that is built using GNU Libtool,
+# you may include this file under the same distribution terms that you use
+# for the rest of that program.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNES 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/>.
+
+# Please report bugs or propose patches to gary@gnu.org.
+
+
+## ------ ##
+## Usage. ##
+## ------ ##
+
+# Evaluate this file near the top of your script to gain access to
+# the functions and variables defined here:
+#
+# . `echo "$0" | ${SED-sed} 's|[^/]*$||'`/build-aux/funclib.sh
+#
+# If you need to override any of the default environment variable
+# settings, do that before evaluating this file.
+
+
+## -------------------- ##
+## Shell normalisation. ##
+## -------------------- ##
+
+# Some shells need a little help to be as Bourne compatible as possible.
+# Before doing anything else, make sure all that help has been provided!
+
+DUALCASE=1; export DUALCASE # for MKS sh
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
+ emulate sh
+ NULLCMD=:
+ # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '${1+"$@"}'='"$@"'
+ setopt NO_GLOB_SUBST
+else
+ case `(set -o) 2>/dev/null` in *posix*) set -o posix ;; esac
+fi
+
+# NLS nuisances: We save the old values in case they are required later.
+_G_user_locale=
+_G_safe_locale=
+for _G_var in LANG LANGUAGE LC_ALL LC_CTYPE LC_COLLATE LC_MESSAGES
+do
+ eval "if test set = \"\${$_G_var+set}\"; then
+ save_$_G_var=\$$_G_var
+ $_G_var=C
+ export $_G_var
+ _G_user_locale=\"$_G_var=\\\$save_\$_G_var; \$_G_user_locale\"
+ _G_safe_locale=\"$_G_var=C; \$_G_safe_locale\"
+ fi"
+done
+
+# CDPATH.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+# Make sure IFS has a sensible default
+sp=' '
+nl='
+'
+IFS="$sp $nl"
+
+# There are apparently some retarded systems that use ';' as a PATH separator!
+if test "${PATH_SEPARATOR+set}" != set; then
+ PATH_SEPARATOR=:
+ (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
+ (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
+ PATH_SEPARATOR=';'
+ }
+fi
+
+
+
+## ------------------------- ##
+## Locate command utilities. ##
+## ------------------------- ##
+
+
+# func_executable_p FILE
+# ----------------------
+# Check that FILE is an executable regular file.
+func_executable_p ()
+{
+ test -f "$1" && test -x "$1"
+}
+
+
+# func_path_progs PROGS_LIST CHECK_FUNC [PATH]
+# --------------------------------------------
+# Search for either a program that responds to --version with output
+# containing "GNU", or else returned by CHECK_FUNC otherwise, by
+# trying all the directories in PATH with each of the elements of
+# PROGS_LIST.
+#
+# CHECK_FUNC should accept the path to a candidate program, and
+# set $func_check_prog_result if it truncates its output less than
+# $_G_path_prog_max characters.
+func_path_progs ()
+{
+ _G_progs_list=$1
+ _G_check_func=$2
+ _G_PATH=${3-"$PATH"}
+
+ _G_path_prog_max=0
+ _G_path_prog_found=false
+ _G_save_IFS=$IFS; IFS=${PATH_SEPARATOR-:}
+ for _G_dir in $_G_PATH; do
+ IFS=$_G_save_IFS
+ test -z "$_G_dir" && _G_dir=.
+ for _G_prog_name in $_G_progs_list; do
+ for _exeext in '' .EXE; do
+ _G_path_prog=$_G_dir/$_G_prog_name$_exeext
+ func_executable_p "$_G_path_prog" || continue
+ case `"$_G_path_prog" --version 2>&1` in
+ *GNU*) func_path_progs_result=$_G_path_prog _G_path_prog_found=: ;;
+ *) $_G_check_func $_G_path_prog
+ func_path_progs_result=$func_check_prog_result
+ ;;
+ esac
+ $_G_path_prog_found && break 3
+ done
+ done
+ done
+ IFS=$_G_save_IFS
+ test -z "$func_path_progs_result" && {
+ echo "no acceptable sed could be found in \$PATH" >&2
+ exit 1
+ }
+}
+
+
+# We want to be able to use the functions in this file before configure
+# has figured out where the best binaries are kept, which means we have
+# to search for them ourselves - except when the results are already set
+# where we skip the searches.
+
+# Unless the user overrides by setting SED, search the path for either GNU
+# sed, or the sed that truncates its output the least.
+test -z "$SED" && {
+ _G_sed_script=s/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/
+ for _G_i in 1 2 3 4 5 6 7; do
+ _G_sed_script=$_G_sed_script$nl$_G_sed_script
+ done
+ echo "$_G_sed_script" 2>/dev/null | sed 99q >conftest.sed
+ _G_sed_script=
+
+ func_check_prog_sed ()
+ {
+ _G_path_prog=$1
+
+ _G_count=0
+ printf 0123456789 >conftest.in
+ while :
+ do
+ cat conftest.in conftest.in >conftest.tmp
+ mv conftest.tmp conftest.in
+ cp conftest.in conftest.nl
+ echo '' >> conftest.nl
+ "$_G_path_prog" -f conftest.sed <conftest.nl >conftest.out 2>/dev/null || break
+ diff conftest.out conftest.nl >/dev/null 2>&1 || break
+ _G_count=`expr $_G_count + 1`
+ if test "$_G_count" -gt "$_G_path_prog_max"; then
+ # Best one so far, save it but keep looking for a better one
+ func_check_prog_result=$_G_path_prog
+ _G_path_prog_max=$_G_count
+ fi
+ # 10*(2^10) chars as input seems more than enough
+ test 10 -lt "$_G_count" && break
+ done
+ rm -f conftest.in conftest.tmp conftest.nl conftest.out
+ }
+
+ func_path_progs "sed gsed" func_check_prog_sed $PATH:/usr/xpg4/bin
+ rm -f conftest.sed
+ SED=$func_path_progs_result
+}
+
+
+# Unless the user overrides by setting GREP, search the path for either GNU
+# grep, or the grep that truncates its output the least.
+test -z "$GREP" && {
+ func_check_prog_grep ()
+ {
+ _G_path_prog=$1
+
+ _G_count=0
+ _G_path_prog_max=0
+ printf 0123456789 >conftest.in
+ while :
+ do
+ cat conftest.in conftest.in >conftest.tmp
+ mv conftest.tmp conftest.in
+ cp conftest.in conftest.nl
+ echo 'GREP' >> conftest.nl
+ "$_G_path_prog" -e 'GREP$' -e '-(cannot match)-' <conftest.nl >conftest.out 2>/dev/null || break
+ diff conftest.out conftest.nl >/dev/null 2>&1 || break
+ _G_count=`expr $_G_count + 1`
+ if test "$_G_count" -gt "$_G_path_prog_max"; then
+ # Best one so far, save it but keep looking for a better one
+ func_check_prog_result=$_G_path_prog
+ _G_path_prog_max=$_G_count
+ fi
+ # 10*(2^10) chars as input seems more than enough
+ test 10 -lt "$_G_count" && break
+ done
+ rm -f conftest.in conftest.tmp conftest.nl conftest.out
+ }
+
+ func_path_progs "grep ggrep" func_check_prog_grep $PATH:/usr/xpg4/bin
+ GREP=$func_path_progs_result
+}
+
+
+## ------------------------------- ##
+## User overridable command paths. ##
+## ------------------------------- ##
+
+# All uppercase variable names are used for environment variables. These
+# variables can be overridden by the user before calling a script that
+# uses them if a suitable command of that name is not already available
+# in the command search PATH.
+
+: ${CP="cp -f"}
+: ${ECHO="printf %s\n"}
+: ${EGREP="$GREP -E"}
+: ${FGREP="$GREP -F"}
+: ${LN_S="ln -s"}
+: ${MAKE="make"}
+: ${MKDIR="mkdir"}
+: ${MV="mv -f"}
+: ${RM="rm -f"}
+: ${SHELL="${CONFIG_SHELL-/bin/sh}"}
+
+
+## -------------------- ##
+## Useful sed snippets. ##
+## -------------------- ##
+
+sed_dirname='s|/[^/]*$||'
+sed_basename='s|^.*/||'
+
+# Sed substitution that helps us do robust quoting. It backslashifies
+# metacharacters that are still active within double-quoted strings.
+sed_quote_subst='s|\([`"$\\]\)|\\\1|g'
+
+# Same as above, but do not quote variable references.
+sed_double_quote_subst='s/\(["`\\]\)/\\\1/g'
+
+# Sed substitution that turns a string into a regex matching for the
+# string literally.
+sed_make_literal_regex='s|[].[^$\\*\/]|\\&|g'
+
+# Sed substitution that converts a w32 file name or path
+# that contains forward slashes, into one that contains
+# (escaped) backslashes. A very naive implementation.
+sed_naive_backslashify='s|\\\\*|\\|g;s|/|\\|g;s|\\|\\\\|g'
+
+# Re-'\' parameter expansions in output of sed_double_quote_subst that
+# were '\'-ed in input to the same. If an odd number of '\' preceded a
+# '$' in input to sed_double_quote_subst, that '$' was protected from
+# expansion. Since each input '\' is now two '\'s, look for any number
+# of runs of four '\'s followed by two '\'s and then a '$'. '\' that '$'.
+_G_bs='\\'
+_G_bs2='\\\\'
+_G_bs4='\\\\\\\\'
+_G_dollar='\$'
+sed_double_backslash="\
+ s/$_G_bs4/&\\
+/g
+ s/^$_G_bs2$_G_dollar/$_G_bs&/
+ s/\\([^$_G_bs]\\)$_G_bs2$_G_dollar/\\1$_G_bs2$_G_bs$_G_dollar/g
+ s/\n//g"
+
+
+## ----------------- ##
+## Global variables. ##
+## ----------------- ##
+
+# Except for the global variables explicitly listed below, the following
+# functions in the '^func_' namespace, and the '^require_' namespace
+# variables initialised in the 'Resource management' section, sourcing
+# this file will not pollute your global namespace with anything
+# else. There's no portable way to scope variables in Bourne shell
+# though, so actually running these functions will sometimes place
+# results into a variable named after the function, and often use
+# temporary variables in the '^_G_' namespace. If you are careful to
+# avoid using those namespaces casually in your sourcing script, things
+# should continue to work as you expect. And, of course, you can freely
+# overwrite any of the functions or variables defined here before
+# calling anything to customize them.
+
+EXIT_SUCCESS=0
+EXIT_FAILURE=1
+EXIT_MISMATCH=63 # $? = 63 is used to indicate version mismatch to missing.
+EXIT_SKIP=77 # $? = 77 is used to indicate a skipped test to automake.
+
+# Allow overriding, eg assuming that you follow the convention of
+# putting '$debug_cmd' at the start of all your functions, you can get
+# bash to show function call trace with:
+#
+# debug_cmd='eval echo "${FUNCNAME[0]} $*" >&2' bash your-script-name
+debug_cmd=${debug_cmd-":"}
+exit_cmd=:
+
+# By convention, finish your script with:
+#
+# exit $exit_status
+#
+# so that you can set exit_status to non-zero if you want to indicate
+# something went wrong during execution without actually bailing out at
+# the point of failure.
+exit_status=$EXIT_SUCCESS
+
+# Work around backward compatibility issue on IRIX 6.5. On IRIX 6.4+, sh
+# is ksh but when the shell is invoked as "sh" and the current value of
+# the _XPG environment variable is not equal to 1 (one), the special
+# positional parameter $0, within a function call, is the name of the
+# function.
+progpath=$0
+
+# The name of this program.
+progname=`$ECHO "$progpath" |$SED "$sed_basename"`
+
+# Make sure we have an absolute progpath for reexecution:
+case $progpath in
+ [\\/]*|[A-Za-z]:\\*) ;;
+ *[\\/]*)
+ progdir=`$ECHO "$progpath" |$SED "$sed_dirname"`
+ progdir=`cd "$progdir" && pwd`
+ progpath=$progdir/$progname
+ ;;
+ *)
+ _G_IFS=$IFS
+ IFS=${PATH_SEPARATOR-:}
+ for progdir in $PATH; do
+ IFS=$_G_IFS
+ test -x "$progdir/$progname" && break
+ done
+ IFS=$_G_IFS
+ test -n "$progdir" || progdir=`pwd`
+ progpath=$progdir/$progname
+ ;;
+esac
+
+
+## ----------------- ##
+## Standard options. ##
+## ----------------- ##
+
+# The following options affect the operation of the functions defined
+# below, and should be set appropriately depending on run-time para-
+# meters passed on the command line.
+
+opt_dry_run=false
+opt_quiet=false
+opt_verbose=false
+
+# Categories 'all' and 'none' are always available. Append any others
+# you will pass as the first argument to func_warning from your own
+# code.
+warning_categories=
+
+# By default, display warnings according to 'opt_warning_types'. Set
+# 'warning_func' to ':' to elide all warnings, or func_fatal_error to
+# treat the next displayed warning as a fatal error.
+warning_func=func_warn_and_continue
+
+# Set to 'all' to display all warnings, 'none' to suppress all
+# warnings, or a space delimited list of some subset of
+# 'warning_categories' to display only the listed warnings.
+opt_warning_types=all
+
+
+## -------------------- ##
+## Resource management. ##
+## -------------------- ##
+
+# This section contains definitions for functions that each ensure a
+# particular resource (a file, or a non-empty configuration variable for
+# example) is available, and if appropriate to extract default values
+# from pertinent package files. Call them using their associated
+# 'require_*' variable to ensure that they are executed, at most, once.
+#
+# It's entirely deliberate that calling these functions can set
+# variables that don't obey the namespace limitations obeyed by the rest
+# of this file, in order that that they be as useful as possible to
+# callers.
+
+
+# require_term_colors
+# -------------------
+# Allow display of bold text on terminals that support it.
+require_term_colors=func_require_term_colors
+func_require_term_colors ()
+{
+ $debug_cmd
+
+ test -t 1 && {
+ # COLORTERM and USE_ANSI_COLORS environment variables take
+ # precedence, because most terminfo databases neglect to describe
+ # whether color sequences are supported.
+ test -n "${COLORTERM+set}" && : ${USE_ANSI_COLORS="1"}
+
+ if test 1 = "$USE_ANSI_COLORS"; then
+ # Standard ANSI escape sequences
+ tc_reset=''
+ tc_bold=''; tc_standout=''
+ tc_red=''; tc_green=''
+ tc_blue=''; tc_cyan=''
+ else
+ # Otherwise trust the terminfo database after all.
+ test -n "`tput sgr0 2>/dev/null`" && {
+ tc_reset=`tput sgr0`
+ test -n "`tput bold 2>/dev/null`" && tc_bold=`tput bold`
+ tc_standout=$tc_bold
+ test -n "`tput smso 2>/dev/null`" && tc_standout=`tput smso`
+ test -n "`tput setaf 1 2>/dev/null`" && tc_red=`tput setaf 1`
+ test -n "`tput setaf 2 2>/dev/null`" && tc_green=`tput setaf 2`
+ test -n "`tput setaf 4 2>/dev/null`" && tc_blue=`tput setaf 4`
+ test -n "`tput setaf 5 2>/dev/null`" && tc_cyan=`tput setaf 5`
+ }
+ fi
+ }
+
+ require_term_colors=:
+}
+
+
+## ----------------- ##
+## Function library. ##
+## ----------------- ##
+
+# This section contains a variety of useful functions to call in your
+# scripts. Take note of the portable wrappers for features provided by
+# some modern shells, which will fall back to slower equivalents on
+# less featureful shells.
+
+
+# func_append VAR VALUE
+# ---------------------
+# Append VALUE onto the existing contents of VAR.
+
+ # We should try to minimise forks, especially on Windows where they are
+ # unreasonably slow, so skip the feature probes when bash or zsh are
+ # being used:
+ if test set = "${BASH_VERSION+set}${ZSH_VERSION+set}"; then
+ : ${_G_HAVE_ARITH_OP="yes"}
+ : ${_G_HAVE_XSI_OPS="yes"}
+ # The += operator was introduced in bash 3.1
+ case $BASH_VERSION in
+ [12].* | 3.0 | 3.0*) ;;
+ *)
+ : ${_G_HAVE_PLUSEQ_OP="yes"}
+ ;;
+ esac
+ fi
+
+ # _G_HAVE_PLUSEQ_OP
+ # Can be empty, in which case the shell is probed, "yes" if += is
+ # useable or anything else if it does not work.
+ test -z "$_G_HAVE_PLUSEQ_OP" \
+ && (eval 'x=a; x+=" b"; test "a b" = "$x"') 2>/dev/null \
+ && _G_HAVE_PLUSEQ_OP=yes
+
+if test yes = "$_G_HAVE_PLUSEQ_OP"
+then
+ # This is an XSI compatible shell, allowing a faster implementation...
+ eval 'func_append ()
+ {
+ $debug_cmd
+
+ eval "$1+=\$2"
+ }'
+else
+ # ...otherwise fall back to using expr, which is often a shell builtin.
+ func_append ()
+ {
+ $debug_cmd
+
+ eval "$1=\$$1\$2"
+ }
+fi
+
+
+# func_append_quoted VAR VALUE
+# ----------------------------
+# Quote VALUE and append to the end of shell variable VAR, separated
+# by a space.
+if test yes = "$_G_HAVE_PLUSEQ_OP"; then
+ eval 'func_append_quoted ()
+ {
+ $debug_cmd
+
+ func_quote_for_eval "$2"
+ eval "$1+=\\ \$func_quote_for_eval_result"
+ }'
+else
+ func_append_quoted ()
+ {
+ $debug_cmd
+
+ func_quote_for_eval "$2"
+ eval "$1=\$$1\\ \$func_quote_for_eval_result"
+ }
+fi
+
+
+# func_append_uniq VAR VALUE
+# --------------------------
+# Append unique VALUE onto the existing contents of VAR, assuming
+# entries are delimited by the first character of VALUE. For example:
+#
+# func_append_uniq options " --another-option option-argument"
+#
+# will only append to $options if " --another-option option-argument "
+# is not already present somewhere in $options already (note spaces at
+# each end implied by leading space in second argument).
+func_append_uniq ()
+{
+ $debug_cmd
+
+ eval _G_current_value='`$ECHO $'$1'`'
+ _G_delim=`expr "$2" : '\(.\)'`
+
+ case $_G_delim$_G_current_value$_G_delim in
+ *"$2$_G_delim"*) ;;
+ *) func_append "$@" ;;
+ esac
+}
+
+
+# func_arith TERM...
+# ------------------
+# Set func_arith_result to the result of evaluating TERMs.
+ test -z "$_G_HAVE_ARITH_OP" \
+ && (eval 'test 2 = $(( 1 + 1 ))') 2>/dev/null \
+ && _G_HAVE_ARITH_OP=yes
+
+if test yes = "$_G_HAVE_ARITH_OP"; then
+ eval 'func_arith ()
+ {
+ $debug_cmd
+
+ func_arith_result=$(( $* ))
+ }'
+else
+ func_arith ()
+ {
+ $debug_cmd
+
+ func_arith_result=`expr "$@"`
+ }
+fi
+
+
+# func_basename FILE
+# ------------------
+# Set func_basename_result to FILE with everything up to and including
+# the last / stripped.
+if test yes = "$_G_HAVE_XSI_OPS"; then
+ # If this shell supports suffix pattern removal, then use it to avoid
+ # forking. Hide the definitions single quotes in case the shell chokes
+ # on unsupported syntax...
+ _b='func_basename_result=${1##*/}'
+ _d='case $1 in
+ */*) func_dirname_result=${1%/*}$2 ;;
+ * ) func_dirname_result=$3 ;;
+ esac'
+
+else
+ # ...otherwise fall back to using sed.
+ _b='func_basename_result=`$ECHO "$1" |$SED "$sed_basename"`'
+ _d='func_dirname_result=`$ECHO "$1" |$SED "$sed_dirname"`
+ if test "X$func_dirname_result" = "X$1"; then
+ func_dirname_result=$3
+ else
+ func_append func_dirname_result "$2"
+ fi'
+fi
+
+eval 'func_basename ()
+{
+ $debug_cmd
+
+ '"$_b"'
+}'
+
+
+# func_dirname FILE APPEND NONDIR_REPLACEMENT
+# -------------------------------------------
+# Compute the dirname of FILE. If nonempty, add APPEND to the result,
+# otherwise set result to NONDIR_REPLACEMENT.
+eval 'func_dirname ()
+{
+ $debug_cmd
+
+ '"$_d"'
+}'
+
+
+# func_dirname_and_basename FILE APPEND NONDIR_REPLACEMENT
+# --------------------------------------------------------
+# Perform func_basename and func_dirname in a single function
+# call:
+# dirname: Compute the dirname of FILE. If nonempty,
+# add APPEND to the result, otherwise set result
+# to NONDIR_REPLACEMENT.
+# value returned in "$func_dirname_result"
+# basename: Compute filename of FILE.
+# value retuned in "$func_basename_result"
+# For efficiency, we do not delegate to the functions above but instead
+# duplicate the functionality here.
+eval 'func_dirname_and_basename ()
+{
+ $debug_cmd
+
+ '"$_b"'
+ '"$_d"'
+}'
+
+
+# func_echo ARG...
+# ----------------
+# Echo program name prefixed message.
+func_echo ()
+{
+ $debug_cmd
+
+ _G_message=$*
+
+ func_echo_IFS=$IFS
+ IFS=$nl
+ for _G_line in $_G_message; do
+ IFS=$func_echo_IFS
+ $ECHO "$progname: $_G_line"
+ done
+ IFS=$func_echo_IFS
+}
+
+
+# func_echo_all ARG...
+# --------------------
+# Invoke $ECHO with all args, space-separated.
+func_echo_all ()
+{
+ $ECHO "$*"
+}
+
+
+# func_echo_infix_1 INFIX ARG...
+# ------------------------------
+# Echo program name, followed by INFIX on the first line, with any
+# additional lines not showing INFIX.
+func_echo_infix_1 ()
+{
+ $debug_cmd
+
+ $require_term_colors
+
+ _G_infix=$1; shift
+ _G_indent=$_G_infix
+ _G_prefix="$progname: $_G_infix: "
+ _G_message=$*
+
+ # Strip color escape sequences before counting printable length
+ for _G_tc in "$tc_reset" "$tc_bold" "$tc_standout" "$tc_red" "$tc_green" "$tc_blue" "$tc_cyan"
+ do
+ test -n "$_G_tc" && {
+ _G_esc_tc=`$ECHO "$_G_tc" | $SED "$sed_make_literal_regex"`
+ _G_indent=`$ECHO "$_G_indent" | $SED "s|$_G_esc_tc||g"`
+ }
+ done
+ _G_indent="$progname: "`echo "$_G_indent" | $SED 's|.| |g'`" " ## exclude from sc_prohibit_nested_quotes
+
+ func_echo_infix_1_IFS=$IFS
+ IFS=$nl
+ for _G_line in $_G_message; do
+ IFS=$func_echo_infix_1_IFS
+ $ECHO "$_G_prefix$tc_bold$_G_line$tc_reset" >&2
+ _G_prefix=$_G_indent
+ done
+ IFS=$func_echo_infix_1_IFS
+}
+
+
+# func_error ARG...
+# -----------------
+# Echo program name prefixed message to standard error.
+func_error ()
+{
+ $debug_cmd
+
+ $require_term_colors
+
+ func_echo_infix_1 " $tc_standout${tc_red}error$tc_reset" "$*" >&2
+}
+
+
+# func_fatal_error ARG...
+# -----------------------
+# Echo program name prefixed message to standard error, and exit.
+func_fatal_error ()
+{
+ $debug_cmd
+
+ func_error "$*"
+ exit $EXIT_FAILURE
+}
+
+
+# func_grep EXPRESSION FILENAME
+# -----------------------------
+# Check whether EXPRESSION matches any line of FILENAME, without output.
+func_grep ()
+{
+ $debug_cmd
+
+ $GREP "$1" "$2" >/dev/null 2>&1
+}
+
+
+# func_len STRING
+# ---------------
+# Set func_len_result to the length of STRING. STRING may not
+# start with a hyphen.
+ test -z "$_G_HAVE_XSI_OPS" \
+ && (eval 'x=a/b/c;
+ test 5aa/bb/cc = "${#x}${x%%/*}${x%/*}${x#*/}${x##*/}"') 2>/dev/null \
+ && _G_HAVE_XSI_OPS=yes
+
+if test yes = "$_G_HAVE_XSI_OPS"; then
+ eval 'func_len ()
+ {
+ $debug_cmd
+
+ func_len_result=${#1}
+ }'
+else
+ func_len ()
+ {
+ $debug_cmd
+
+ func_len_result=`expr "$1" : ".*" 2>/dev/null || echo $max_cmd_len`
+ }
+fi
+
+
+# func_mkdir_p DIRECTORY-PATH
+# ---------------------------
+# Make sure the entire path to DIRECTORY-PATH is available.
+func_mkdir_p ()
+{
+ $debug_cmd
+
+ _G_directory_path=$1
+ _G_dir_list=
+
+ if test -n "$_G_directory_path" && test : != "$opt_dry_run"; then
+
+ # Protect directory names starting with '-'
+ case $_G_directory_path in
+ -*) _G_directory_path=./$_G_directory_path ;;
+ esac
+
+ # While some portion of DIR does not yet exist...
+ while test ! -d "$_G_directory_path"; do
+ # ...make a list in topmost first order. Use a colon delimited
+ # list incase some portion of path contains whitespace.
+ _G_dir_list=$_G_directory_path:$_G_dir_list
+
+ # If the last portion added has no slash in it, the list is done
+ case $_G_directory_path in */*) ;; *) break ;; esac
+
+ # ...otherwise throw away the child directory and loop
+ _G_directory_path=`$ECHO "$_G_directory_path" | $SED -e "$sed_dirname"`
+ done
+ _G_dir_list=`$ECHO "$_G_dir_list" | $SED 's|:*$||'`
+
+ func_mkdir_p_IFS=$IFS; IFS=:
+ for _G_dir in $_G_dir_list; do
+ IFS=$func_mkdir_p_IFS
+ # mkdir can fail with a 'File exist' error if two processes
+ # try to create one of the directories concurrently. Don't
+ # stop in that case!
+ $MKDIR "$_G_dir" 2>/dev/null || :
+ done
+ IFS=$func_mkdir_p_IFS
+
+ # Bail out if we (or some other process) failed to create a directory.
+ test -d "$_G_directory_path" || \
+ func_fatal_error "Failed to create '$1'"
+ fi
+}
+
+
+# func_mktempdir [BASENAME]
+# -------------------------
+# Make a temporary directory that won't clash with other running
+# libtool processes, and avoids race conditions if possible. If
+# given, BASENAME is the basename for that directory.
+func_mktempdir ()
+{
+ $debug_cmd
+
+ _G_template=${TMPDIR-/tmp}/${1-$progname}
+
+ if test : = "$opt_dry_run"; then
+ # Return a directory name, but don't create it in dry-run mode
+ _G_tmpdir=$_G_template-$$
+ else
+
+ # If mktemp works, use that first and foremost
+ _G_tmpdir=`mktemp -d "$_G_template-XXXXXXXX" 2>/dev/null`
+
+ if test ! -d "$_G_tmpdir"; then
+ # Failing that, at least try and use $RANDOM to avoid a race
+ _G_tmpdir=$_G_template-${RANDOM-0}$$
+
+ func_mktempdir_umask=`umask`
+ umask 0077
+ $MKDIR "$_G_tmpdir"
+ umask $func_mktempdir_umask
+ fi
+
+ # If we're not in dry-run mode, bomb out on failure
+ test -d "$_G_tmpdir" || \
+ func_fatal_error "cannot create temporary directory '$_G_tmpdir'"
+ fi
+
+ $ECHO "$_G_tmpdir"
+}
+
+
+# func_normal_abspath PATH
+# ------------------------
+# Remove doubled-up and trailing slashes, "." path components,
+# and cancel out any ".." path components in PATH after making
+# it an absolute path.
+func_normal_abspath ()
+{
+ $debug_cmd
+
+ # These SED scripts presuppose an absolute path with a trailing slash.
+ _G_pathcar='s|^/\([^/]*\).*$|\1|'
+ _G_pathcdr='s|^/[^/]*||'
+ _G_removedotparts=':dotsl
+ s|/\./|/|g
+ t dotsl
+ s|/\.$|/|'
+ _G_collapseslashes='s|/\{1,\}|/|g'
+ _G_finalslash='s|/*$|/|'
+
+ # Start from root dir and reassemble the path.
+ func_normal_abspath_result=
+ func_normal_abspath_tpath=$1
+ func_normal_abspath_altnamespace=
+ case $func_normal_abspath_tpath in
+ "")
+ # Empty path, that just means $cwd.
+ func_stripname '' '/' "`pwd`"
+ func_normal_abspath_result=$func_stripname_result
+ return
+ ;;
+ # The next three entries are used to spot a run of precisely
+ # two leading slashes without using negated character classes;
+ # we take advantage of case's first-match behaviour.
+ ///*)
+ # Unusual form of absolute path, do nothing.
+ ;;
+ //*)
+ # Not necessarily an ordinary path; POSIX reserves leading '//'
+ # and for example Cygwin uses it to access remote file shares
+ # over CIFS/SMB, so we conserve a leading double slash if found.
+ func_normal_abspath_altnamespace=/
+ ;;
+ /*)
+ # Absolute path, do nothing.
+ ;;
+ *)
+ # Relative path, prepend $cwd.
+ func_normal_abspath_tpath=`pwd`/$func_normal_abspath_tpath
+ ;;
+ esac
+
+ # Cancel out all the simple stuff to save iterations. We also want
+ # the path to end with a slash for ease of parsing, so make sure
+ # there is one (and only one) here.
+ func_normal_abspath_tpath=`$ECHO "$func_normal_abspath_tpath" | $SED \
+ -e "$_G_removedotparts" -e "$_G_collapseslashes" -e "$_G_finalslash"`
+ while :; do
+ # Processed it all yet?
+ if test / = "$func_normal_abspath_tpath"; then
+ # If we ascended to the root using ".." the result may be empty now.
+ if test -z "$func_normal_abspath_result"; then
+ func_normal_abspath_result=/
+ fi
+ break
+ fi
+ func_normal_abspath_tcomponent=`$ECHO "$func_normal_abspath_tpath" | $SED \
+ -e "$_G_pathcar"`
+ func_normal_abspath_tpath=`$ECHO "$func_normal_abspath_tpath" | $SED \
+ -e "$_G_pathcdr"`
+ # Figure out what to do with it
+ case $func_normal_abspath_tcomponent in
+ "")
+ # Trailing empty path component, ignore it.
+ ;;
+ ..)
+ # Parent dir; strip last assembled component from result.
+ func_dirname "$func_normal_abspath_result"
+ func_normal_abspath_result=$func_dirname_result
+ ;;
+ *)
+ # Actual path component, append it.
+ func_append func_normal_abspath_result "/$func_normal_abspath_tcomponent"
+ ;;
+ esac
+ done
+ # Restore leading double-slash if one was found on entry.
+ func_normal_abspath_result=$func_normal_abspath_altnamespace$func_normal_abspath_result
+}
+
+
+# func_notquiet ARG...
+# --------------------
+# Echo program name prefixed message only when not in quiet mode.
+func_notquiet ()
+{
+ $debug_cmd
+
+ $opt_quiet || func_echo ${1+"$@"}
+
+ # A bug in bash halts the script if the last line of a function
+ # fails when set -e is in force, so we need another command to
+ # work around that:
+ :
+}
+
+
+# func_relative_path SRCDIR DSTDIR
+# --------------------------------
+# Set func_relative_path_result to the relative path from SRCDIR to DSTDIR.
+func_relative_path ()
+{
+ $debug_cmd
+
+ func_relative_path_result=
+ func_normal_abspath "$1"
+ func_relative_path_tlibdir=$func_normal_abspath_result
+ func_normal_abspath "$2"
+ func_relative_path_tbindir=$func_normal_abspath_result
+
+ # Ascend the tree starting from libdir
+ while :; do
+ # check if we have found a prefix of bindir
+ case $func_relative_path_tbindir in
+ $func_relative_path_tlibdir)
+ # found an exact match
+ func_relative_path_tcancelled=
+ break
+ ;;
+ $func_relative_path_tlibdir*)
+ # found a matching prefix
+ func_stripname "$func_relative_path_tlibdir" '' "$func_relative_path_tbindir"
+ func_relative_path_tcancelled=$func_stripname_result
+ if test -z "$func_relative_path_result"; then
+ func_relative_path_result=.
+ fi
+ break
+ ;;
+ *)
+ func_dirname $func_relative_path_tlibdir
+ func_relative_path_tlibdir=$func_dirname_result
+ if test -z "$func_relative_path_tlibdir"; then
+ # Have to descend all the way to the root!
+ func_relative_path_result=../$func_relative_path_result
+ func_relative_path_tcancelled=$func_relative_path_tbindir
+ break
+ fi
+ func_relative_path_result=../$func_relative_path_result
+ ;;
+ esac
+ done
+
+ # Now calculate path; take care to avoid doubling-up slashes.
+ func_stripname '' '/' "$func_relative_path_result"
+ func_relative_path_result=$func_stripname_result
+ func_stripname '/' '/' "$func_relative_path_tcancelled"
+ if test -n "$func_stripname_result"; then
+ func_append func_relative_path_result "/$func_stripname_result"
+ fi
+
+ # Normalisation. If bindir is libdir, return '.' else relative path.
+ if test -n "$func_relative_path_result"; then
+ func_stripname './' '' "$func_relative_path_result"
+ func_relative_path_result=$func_stripname_result
+ fi
+
+ test -n "$func_relative_path_result" || func_relative_path_result=.
+
+ :
+}
+
+
+# func_quote_for_eval ARG...
+# --------------------------
+# Aesthetically quote ARGs to be evaled later.
+# This function returns two values:
+# i) func_quote_for_eval_result
+# double-quoted, suitable for a subsequent eval
+# ii) func_quote_for_eval_unquoted_result
+# has all characters that are still active within double
+# quotes backslashified.
+func_quote_for_eval ()
+{
+ $debug_cmd
+
+ func_quote_for_eval_unquoted_result=
+ func_quote_for_eval_result=
+ while test 0 -lt $#; do
+ case $1 in
+ *[\\\`\"\$]*)
+ _G_unquoted_arg=`printf '%s\n' "$1" |$SED "$sed_quote_subst"` ;;
+ *)
+ _G_unquoted_arg=$1 ;;
+ esac
+ if test -n "$func_quote_for_eval_unquoted_result"; then
+ func_append func_quote_for_eval_unquoted_result " $_G_unquoted_arg"
+ else
+ func_append func_quote_for_eval_unquoted_result "$_G_unquoted_arg"
+ fi
+
+ case $_G_unquoted_arg in
+ # Double-quote args containing shell metacharacters to delay
+ # word splitting, command substitution and variable expansion
+ # for a subsequent eval.
+ # Many Bourne shells cannot handle close brackets correctly
+ # in scan sets, so we specify it separately.
+ *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"")
+ _G_quoted_arg=\"$_G_unquoted_arg\"
+ ;;
+ *)
+ _G_quoted_arg=$_G_unquoted_arg
+ ;;
+ esac
+
+ if test -n "$func_quote_for_eval_result"; then
+ func_append func_quote_for_eval_result " $_G_quoted_arg"
+ else
+ func_append func_quote_for_eval_result "$_G_quoted_arg"
+ fi
+ shift
+ done
+}
+
+
+# func_quote_for_expand ARG
+# -------------------------
+# Aesthetically quote ARG to be evaled later; same as above,
+# but do not quote variable references.
+func_quote_for_expand ()
+{
+ $debug_cmd
+
+ case $1 in
+ *[\\\`\"]*)
+ _G_arg=`$ECHO "$1" | $SED \
+ -e "$sed_double_quote_subst" -e "$sed_double_backslash"` ;;
+ *)
+ _G_arg=$1 ;;
+ esac
+
+ case $_G_arg in
+ # Double-quote args containing shell metacharacters to delay
+ # word splitting and command substitution for a subsequent eval.
+ # Many Bourne shells cannot handle close brackets correctly
+ # in scan sets, so we specify it separately.
+ *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"")
+ _G_arg=\"$_G_arg\"
+ ;;
+ esac
+
+ func_quote_for_expand_result=$_G_arg
+}
+
+
+# func_stripname PREFIX SUFFIX NAME
+# ---------------------------------
+# strip PREFIX and SUFFIX from NAME, and store in func_stripname_result.
+# PREFIX and SUFFIX must not contain globbing or regex special
+# characters, hashes, percent signs, but SUFFIX may contain a leading
+# dot (in which case that matches only a dot).
+if test yes = "$_G_HAVE_XSI_OPS"; then
+ eval 'func_stripname ()
+ {
+ $debug_cmd
+
+ # pdksh 5.2.14 does not do ${X%$Y} correctly if both X and Y are
+ # positional parameters, so assign one to ordinary variable first.
+ func_stripname_result=$3
+ func_stripname_result=${func_stripname_result#"$1"}
+ func_stripname_result=${func_stripname_result%"$2"}
+ }'
+else
+ func_stripname ()
+ {
+ $debug_cmd
+
+ case $2 in
+ .*) func_stripname_result=`$ECHO "$3" | $SED -e "s%^$1%%" -e "s%\\\\$2\$%%"`;;
+ *) func_stripname_result=`$ECHO "$3" | $SED -e "s%^$1%%" -e "s%$2\$%%"`;;
+ esac
+ }
+fi
+
+
+# func_show_eval CMD [FAIL_EXP]
+# -----------------------------
+# Unless opt_quiet is true, then output CMD. Then, if opt_dryrun is
+# not true, evaluate CMD. If the evaluation of CMD fails, and FAIL_EXP
+# is given, then evaluate it.
+func_show_eval ()
+{
+ $debug_cmd
+
+ _G_cmd=$1
+ _G_fail_exp=${2-':'}
+
+ func_quote_for_expand "$_G_cmd"
+ eval "func_notquiet $func_quote_for_expand_result"
+
+ $opt_dry_run || {
+ eval "$_G_cmd"
+ _G_status=$?
+ if test 0 -ne "$_G_status"; then
+ eval "(exit $_G_status); $_G_fail_exp"
+ fi
+ }
+}
+
+
+# func_show_eval_locale CMD [FAIL_EXP]
+# ------------------------------------
+# Unless opt_quiet is true, then output CMD. Then, if opt_dryrun is
+# not true, evaluate CMD. If the evaluation of CMD fails, and FAIL_EXP
+# is given, then evaluate it. Use the saved locale for evaluation.
+func_show_eval_locale ()
+{
+ $debug_cmd
+
+ _G_cmd=$1
+ _G_fail_exp=${2-':'}
+
+ $opt_quiet || {
+ func_quote_for_expand "$_G_cmd"
+ eval "func_echo $func_quote_for_expand_result"
+ }
+
+ $opt_dry_run || {
+ eval "$_G_user_locale
+ $_G_cmd"
+ _G_status=$?
+ eval "$_G_safe_locale"
+ if test 0 -ne "$_G_status"; then
+ eval "(exit $_G_status); $_G_fail_exp"
+ fi
+ }
+}
+
+
+# func_tr_sh
+# ----------
+# Turn $1 into a string suitable for a shell variable name.
+# Result is stored in $func_tr_sh_result. All characters
+# not in the set a-zA-Z0-9_ are replaced with '_'. Further,
+# if $1 begins with a digit, a '_' is prepended as well.
+func_tr_sh ()
+{
+ $debug_cmd
+
+ case $1 in
+ [0-9]* | *[!a-zA-Z0-9_]*)
+ func_tr_sh_result=`$ECHO "$1" | $SED -e 's/^\([0-9]\)/_\1/' -e 's/[^a-zA-Z0-9_]/_/g'`
+ ;;
+ * )
+ func_tr_sh_result=$1
+ ;;
+ esac
+}
+
+
+# func_verbose ARG...
+# -------------------
+# Echo program name prefixed message in verbose mode only.
+func_verbose ()
+{
+ $debug_cmd
+
+ $opt_verbose && func_echo "$*"
+
+ :
+}
+
+
+# func_warn_and_continue ARG...
+# -----------------------------
+# Echo program name prefixed warning message to standard error.
+func_warn_and_continue ()
+{
+ $debug_cmd
+
+ $require_term_colors
+
+ func_echo_infix_1 "${tc_red}warning$tc_reset" "$*" >&2
+}
+
+
+# func_warning CATEGORY ARG...
+# ----------------------------
+# Echo program name prefixed warning message to standard error. Warning
+# messages can be filtered according to CATEGORY, where this function
+# elides messages where CATEGORY is not listed in the global variable
+# 'opt_warning_types'.
+func_warning ()
+{
+ $debug_cmd
+
+ # CATEGORY must be in the warning_categories list!
+ case " $warning_categories " in
+ *" $1 "*) ;;
+ *) func_internal_error "invalid warning category '$1'" ;;
+ esac
+
+ _G_category=$1
+ shift
+
+ case " $opt_warning_types " in
+ *" $_G_category "*) $warning_func ${1+"$@"} ;;
+ esac
+}
+
+
+# func_sort_ver VER1 VER2
+# -----------------------
+# 'sort -V' is not generally available.
+# Note this deviates from the version comparison in automake
+# in that it treats 1.5 < 1.5.0, and treats 1.4.4a < 1.4-p3a
+# but this should suffice as we won't be specifying old
+# version formats or redundant trailing .0 in bootstrap.conf.
+# If we did want full compatibility then we should probably
+# use m4_version_compare from autoconf.
+func_sort_ver ()
+{
+ $debug_cmd
+
+ printf '%s\n%s\n' "$1" "$2" \
+ | sort -t. -k 1,1n -k 2,2n -k 3,3n -k 4,4n -k 5,5n -k 6,6n -k 7,7n -k 8,8n -k 9,9n
+}
+
+# func_lt_ver PREV CURR
+# ---------------------
+# Return true if PREV and CURR are in the correct order according to
+# func_sort_ver, otherwise false. Use it like this:
+#
+# func_lt_ver "$prev_ver" "$proposed_ver" || func_fatal_error "..."
+func_lt_ver ()
+{
+ $debug_cmd
+
+ test "x$1" = x`func_sort_ver "$1" "$2" | $SED 1q`
+}
+
+
+# Local variables:
+# mode: shell-script
+# sh-indentation: 2
+# eval: (add-hook 'before-save-hook 'time-stamp)
+# time-stamp-pattern: "10/scriptversion=%:y-%02m-%02d.%02H; # UTC"
+# time-stamp-time-zone: "UTC"
+# End:
+#! /bin/sh
+
+# Set a version string for this script.
+scriptversion=2014-01-07.03; # UTC
+
+# A portable, pluggable option parser for Bourne shell.
+# Written by Gary V. Vaughan, 2010
+
+# Copyright (C) 2010-2015 Free Software Foundation, Inc.
+# This is free software; see the source for copying conditions. There is NO
+# warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+# 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/>.
+
+# Please report bugs or propose patches to gary@gnu.org.
+
+
+## ------ ##
+## Usage. ##
+## ------ ##
+
+# This file is a library for parsing options in your shell scripts along
+# with assorted other useful supporting features that you can make use
+# of too.
+#
+# For the simplest scripts you might need only:
+#
+# #!/bin/sh
+# . relative/path/to/funclib.sh
+# . relative/path/to/options-parser
+# scriptversion=1.0
+# func_options ${1+"$@"}
+# eval set dummy "$func_options_result"; shift
+# ...rest of your script...
+#
+# In order for the '--version' option to work, you will need to have a
+# suitably formatted comment like the one at the top of this file
+# starting with '# Written by ' and ending with '# warranty; '.
+#
+# For '-h' and '--help' to work, you will also need a one line
+# description of your script's purpose in a comment directly above the
+# '# Written by ' line, like the one at the top of this file.
+#
+# The default options also support '--debug', which will turn on shell
+# execution tracing (see the comment above debug_cmd below for another
+# use), and '--verbose' and the func_verbose function to allow your script
+# to display verbose messages only when your user has specified
+# '--verbose'.
+#
+# After sourcing this file, you can plug processing for additional
+# options by amending the variables from the 'Configuration' section
+# below, and following the instructions in the 'Option parsing'
+# section further down.
+
+## -------------- ##
+## Configuration. ##
+## -------------- ##
+
+# You should override these variables in your script after sourcing this
+# file so that they reflect the customisations you have added to the
+# option parser.
+
+# The usage line for option parsing errors and the start of '-h' and
+# '--help' output messages. You can embed shell variables for delayed
+# expansion at the time the message is displayed, but you will need to
+# quote other shell meta-characters carefully to prevent them being
+# expanded when the contents are evaled.
+usage='$progpath [OPTION]...'
+
+# Short help message in response to '-h' and '--help'. Add to this or
+# override it after sourcing this library to reflect the full set of
+# options your script accepts.
+usage_message="\
+ --debug enable verbose shell tracing
+ -W, --warnings=CATEGORY
+ report the warnings falling in CATEGORY [all]
+ -v, --verbose verbosely report processing
+ --version print version information and exit
+ -h, --help print short or long help message and exit
+"
+
+# Additional text appended to 'usage_message' in response to '--help'.
+long_help_message="
+Warning categories include:
+ 'all' show all warnings
+ 'none' turn off all the warnings
+ 'error' warnings are treated as fatal errors"
+
+# Help message printed before fatal option parsing errors.
+fatal_help="Try '\$progname --help' for more information."
+
+
+
+## ------------------------- ##
+## Hook function management. ##
+## ------------------------- ##
+
+# This section contains functions for adding, removing, and running hooks
+# to the main code. A hook is just a named list of of function, that can
+# be run in order later on.
+
+# func_hookable FUNC_NAME
+# -----------------------
+# Declare that FUNC_NAME will run hooks added with
+# 'func_add_hook FUNC_NAME ...'.
+func_hookable ()
+{
+ $debug_cmd
+
+ func_append hookable_fns " $1"
+}
+
+
+# func_add_hook FUNC_NAME HOOK_FUNC
+# ---------------------------------
+# Request that FUNC_NAME call HOOK_FUNC before it returns. FUNC_NAME must
+# first have been declared "hookable" by a call to 'func_hookable'.
+func_add_hook ()
+{
+ $debug_cmd
+
+ case " $hookable_fns " in
+ *" $1 "*) ;;
+ *) func_fatal_error "'$1' does not accept hook functions." ;;
+ esac
+
+ eval func_append ${1}_hooks '" $2"'
+}
+
+
+# func_remove_hook FUNC_NAME HOOK_FUNC
+# ------------------------------------
+# Remove HOOK_FUNC from the list of functions called by FUNC_NAME.
+func_remove_hook ()
+{
+ $debug_cmd
+
+ eval ${1}_hooks='`$ECHO "\$'$1'_hooks" |$SED "s| '$2'||"`'
+}
+
+
+# func_run_hooks FUNC_NAME [ARG]...
+# ---------------------------------
+# Run all hook functions registered to FUNC_NAME.
+# It is assumed that the list of hook functions contains nothing more
+# than a whitespace-delimited list of legal shell function names, and
+# no effort is wasted trying to catch shell meta-characters or preserve
+# whitespace.
+func_run_hooks ()
+{
+ $debug_cmd
+
+ case " $hookable_fns " in
+ *" $1 "*) ;;
+ *) func_fatal_error "'$1' does not support hook funcions.n" ;;
+ esac
+
+ eval _G_hook_fns=\$$1_hooks; shift
+
+ for _G_hook in $_G_hook_fns; do
+ eval $_G_hook '"$@"'
+
+ # store returned options list back into positional
+ # parameters for next 'cmd' execution.
+ eval _G_hook_result=\$${_G_hook}_result
+ eval set dummy "$_G_hook_result"; shift
+ done
+
+ func_quote_for_eval ${1+"$@"}
+ func_run_hooks_result=$func_quote_for_eval_result
+}
+
+
+
+## --------------- ##
+## Option parsing. ##
+## --------------- ##
+
+# In order to add your own option parsing hooks, you must accept the
+# full positional parameter list in your hook function, remove any
+# options that you action, and then pass back the remaining unprocessed
+# options in '<hooked_function_name>_result', escaped suitably for
+# 'eval'. Like this:
+#
+# my_options_prep ()
+# {
+# $debug_cmd
+#
+# # Extend the existing usage message.
+# usage_message=$usage_message'
+# -s, --silent don'\''t print informational messages
+# '
+#
+# func_quote_for_eval ${1+"$@"}
+# my_options_prep_result=$func_quote_for_eval_result
+# }
+# func_add_hook func_options_prep my_options_prep
+#
+#
+# my_silent_option ()
+# {
+# $debug_cmd
+#
+# # Note that for efficiency, we parse as many options as we can
+# # recognise in a loop before passing the remainder back to the
+# # caller on the first unrecognised argument we encounter.
+# while test $# -gt 0; do
+# opt=$1; shift
+# case $opt in
+# --silent|-s) opt_silent=: ;;
+# # Separate non-argument short options:
+# -s*) func_split_short_opt "$_G_opt"
+# set dummy "$func_split_short_opt_name" \
+# "-$func_split_short_opt_arg" ${1+"$@"}
+# shift
+# ;;
+# *) set dummy "$_G_opt" "$*"; shift; break ;;
+# esac
+# done
+#
+# func_quote_for_eval ${1+"$@"}
+# my_silent_option_result=$func_quote_for_eval_result
+# }
+# func_add_hook func_parse_options my_silent_option
+#
+#
+# my_option_validation ()
+# {
+# $debug_cmd
+#
+# $opt_silent && $opt_verbose && func_fatal_help "\
+# '--silent' and '--verbose' options are mutually exclusive."
+#
+# func_quote_for_eval ${1+"$@"}
+# my_option_validation_result=$func_quote_for_eval_result
+# }
+# func_add_hook func_validate_options my_option_validation
+#
+# You'll alse need to manually amend $usage_message to reflect the extra
+# options you parse. It's preferable to append if you can, so that
+# multiple option parsing hooks can be added safely.
+
+
+# func_options [ARG]...
+# ---------------------
+# All the functions called inside func_options are hookable. See the
+# individual implementations for details.
+func_hookable func_options
+func_options ()
+{
+ $debug_cmd
+
+ func_options_prep ${1+"$@"}
+ eval func_parse_options \
+ ${func_options_prep_result+"$func_options_prep_result"}
+ eval func_validate_options \
+ ${func_parse_options_result+"$func_parse_options_result"}
+
+ eval func_run_hooks func_options \
+ ${func_validate_options_result+"$func_validate_options_result"}
+
+ # save modified positional parameters for caller
+ func_options_result=$func_run_hooks_result
+}
+
+
+# func_options_prep [ARG]...
+# --------------------------
+# All initialisations required before starting the option parse loop.
+# Note that when calling hook functions, we pass through the list of
+# positional parameters. If a hook function modifies that list, and
+# needs to propogate that back to rest of this script, then the complete
+# modified list must be put in 'func_run_hooks_result' before
+# returning.
+func_hookable func_options_prep
+func_options_prep ()
+{
+ $debug_cmd
+
+ # Option defaults:
+ opt_verbose=false
+ opt_warning_types=
+
+ func_run_hooks func_options_prep ${1+"$@"}
+
+ # save modified positional parameters for caller
+ func_options_prep_result=$func_run_hooks_result
+}
+
+
+# func_parse_options [ARG]...
+# ---------------------------
+# The main option parsing loop.
+func_hookable func_parse_options
+func_parse_options ()
+{
+ $debug_cmd
+
+ func_parse_options_result=
+
+ # this just eases exit handling
+ while test $# -gt 0; do
+ # Defer to hook functions for initial option parsing, so they
+ # get priority in the event of reusing an option name.
+ func_run_hooks func_parse_options ${1+"$@"}
+
+ # Adjust func_parse_options positional parameters to match
+ eval set dummy "$func_run_hooks_result"; shift
+
+ # Break out of the loop if we already parsed every option.
+ test $# -gt 0 || break
+
+ _G_opt=$1
+ shift
+ case $_G_opt in
+ --debug|-x) debug_cmd='set -x'
+ func_echo "enabling shell trace mode"
+ $debug_cmd
+ ;;
+
+ --no-warnings|--no-warning|--no-warn)
+ set dummy --warnings none ${1+"$@"}
+ shift
+ ;;
+
+ --warnings|--warning|-W)
+ test $# = 0 && func_missing_arg $_G_opt && break
+ case " $warning_categories $1" in
+ *" $1 "*)
+ # trailing space prevents matching last $1 above
+ func_append_uniq opt_warning_types " $1"
+ ;;
+ *all)
+ opt_warning_types=$warning_categories
+ ;;
+ *none)
+ opt_warning_types=none
+ warning_func=:
+ ;;
+ *error)
+ opt_warning_types=$warning_categories
+ warning_func=func_fatal_error
+ ;;
+ *)
+ func_fatal_error \
+ "unsupported warning category: '$1'"
+ ;;
+ esac
+ shift
+ ;;
+
+ --verbose|-v) opt_verbose=: ;;
+ --version) func_version ;;
+ -\?|-h) func_usage ;;
+ --help) func_help ;;
+
+ # Separate optargs to long options (plugins may need this):
+ --*=*) func_split_equals "$_G_opt"
+ set dummy "$func_split_equals_lhs" \
+ "$func_split_equals_rhs" ${1+"$@"}
+ shift
+ ;;
+
+ # Separate optargs to short options:
+ -W*)
+ func_split_short_opt "$_G_opt"
+ set dummy "$func_split_short_opt_name" \
+ "$func_split_short_opt_arg" ${1+"$@"}
+ shift
+ ;;
+
+ # Separate non-argument short options:
+ -\?*|-h*|-v*|-x*)
+ func_split_short_opt "$_G_opt"
+ set dummy "$func_split_short_opt_name" \
+ "-$func_split_short_opt_arg" ${1+"$@"}
+ shift
+ ;;
+
+ --) break ;;
+ -*) func_fatal_help "unrecognised option: '$_G_opt'" ;;
+ *) set dummy "$_G_opt" ${1+"$@"}; shift; break ;;
+ esac
+ done
+
+ # save modified positional parameters for caller
+ func_quote_for_eval ${1+"$@"}
+ func_parse_options_result=$func_quote_for_eval_result
+}
+
+
+# func_validate_options [ARG]...
+# ------------------------------
+# Perform any sanity checks on option settings and/or unconsumed
+# arguments.
+func_hookable func_validate_options
+func_validate_options ()
+{
+ $debug_cmd
+
+ # Display all warnings if -W was not given.
+ test -n "$opt_warning_types" || opt_warning_types=" $warning_categories"
+
+ func_run_hooks func_validate_options ${1+"$@"}
+
+ # Bail if the options were screwed!
+ $exit_cmd $EXIT_FAILURE
+
+ # save modified positional parameters for caller
+ func_validate_options_result=$func_run_hooks_result
+}
+
+
+
+## ----------------- ##
+## Helper functions. ##
+## ----------------- ##
+
+# This section contains the helper functions used by the rest of the
+# hookable option parser framework in ascii-betical order.
+
+
+# func_fatal_help ARG...
+# ----------------------
+# Echo program name prefixed message to standard error, followed by
+# a help hint, and exit.
+func_fatal_help ()
+{
+ $debug_cmd
+
+ eval \$ECHO \""Usage: $usage"\"
+ eval \$ECHO \""$fatal_help"\"
+ func_error ${1+"$@"}
+ exit $EXIT_FAILURE
+}
+
+
+# func_help
+# ---------
+# Echo long help message to standard output and exit.
+func_help ()
+{
+ $debug_cmd
+
+ func_usage_message
+ $ECHO "$long_help_message"
+ exit 0
+}
+
+
+# func_missing_arg ARGNAME
+# ------------------------
+# Echo program name prefixed message to standard error and set global
+# exit_cmd.
+func_missing_arg ()
+{
+ $debug_cmd
+
+ func_error "Missing argument for '$1'."
+ exit_cmd=exit
+}
+
+
+# func_split_equals STRING
+# ------------------------
+# Set func_split_equals_lhs and func_split_equals_rhs shell variables after
+# splitting STRING at the '=' sign.
+test -z "$_G_HAVE_XSI_OPS" \
+ && (eval 'x=a/b/c;
+ test 5aa/bb/cc = "${#x}${x%%/*}${x%/*}${x#*/}${x##*/}"') 2>/dev/null \
+ && _G_HAVE_XSI_OPS=yes
+
+if test yes = "$_G_HAVE_XSI_OPS"
+then
+ # This is an XSI compatible shell, allowing a faster implementation...
+ eval 'func_split_equals ()
+ {
+ $debug_cmd
+
+ func_split_equals_lhs=${1%%=*}
+ func_split_equals_rhs=${1#*=}
+ test "x$func_split_equals_lhs" = "x$1" \
+ && func_split_equals_rhs=
+ }'
+else
+ # ...otherwise fall back to using expr, which is often a shell builtin.
+ func_split_equals ()
+ {
+ $debug_cmd
+
+ func_split_equals_lhs=`expr "x$1" : 'x\([^=]*\)'`
+ func_split_equals_rhs=
+ test "x$func_split_equals_lhs" = "x$1" \
+ || func_split_equals_rhs=`expr "x$1" : 'x[^=]*=\(.*\)$'`
+ }
+fi #func_split_equals
+
+
+# func_split_short_opt SHORTOPT
+# -----------------------------
+# Set func_split_short_opt_name and func_split_short_opt_arg shell
+# variables after splitting SHORTOPT after the 2nd character.
+if test yes = "$_G_HAVE_XSI_OPS"
+then
+ # This is an XSI compatible shell, allowing a faster implementation...
+ eval 'func_split_short_opt ()
+ {
+ $debug_cmd
+
+ func_split_short_opt_arg=${1#??}
+ func_split_short_opt_name=${1%"$func_split_short_opt_arg"}
+ }'
+else
+ # ...otherwise fall back to using expr, which is often a shell builtin.
+ func_split_short_opt ()
+ {
+ $debug_cmd
+
+ func_split_short_opt_name=`expr "x$1" : 'x-\(.\)'`
+ func_split_short_opt_arg=`expr "x$1" : 'x-.\(.*\)$'`
+ }
+fi #func_split_short_opt
+
+
+# func_usage
+# ----------
+# Echo short help message to standard output and exit.
+func_usage ()
+{
+ $debug_cmd
+
+ func_usage_message
+ $ECHO "Run '$progname --help |${PAGER-more}' for full usage"
+ exit 0
+}
+
+
+# func_usage_message
+# ------------------
+# Echo short help message to standard output.
+func_usage_message ()
+{
+ $debug_cmd
+
+ eval \$ECHO \""Usage: $usage"\"
+ echo
+ $SED -n 's|^# ||
+ /^Written by/{
+ x;p;x
+ }
+ h
+ /^Written by/q' < "$progpath"
+ echo
+ eval \$ECHO \""$usage_message"\"
+}
+
+
+# func_version
+# ------------
+# Echo version message to standard output and exit.
+func_version ()
+{
+ $debug_cmd
+
+ printf '%s\n' "$progname $scriptversion"
+ $SED -n '
+ /(C)/!b go
+ :more
+ /\./!{
+ N
+ s|\n# | |
+ b more
+ }
+ :go
+ /^# Written by /,/# warranty; / {
+ s|^# ||
+ s|^# *$||
+ s|\((C)\)[ 0-9,-]*[ ,-]\([1-9][0-9]* \)|\1 \2|
+ p
+ }
+ /^# Written by / {
+ s|^# ||
+ p
+ }
+ /^warranty; /q' < "$progpath"
+
+ exit $?
+}
+
+
+# Local variables:
+# mode: shell-script
+# sh-indentation: 2
+# eval: (add-hook 'before-save-hook 'time-stamp)
+# time-stamp-pattern: "10/scriptversion=%:y-%02m-%02d.%02H; # UTC"
+# time-stamp-time-zone: "UTC"
+# End:
+
+# Set a version string.
+scriptversion='(GNU libtool) 2.4.6'
+
+
+# func_echo ARG...
+# ----------------
+# Libtool also displays the current mode in messages, so override
+# funclib.sh func_echo with this custom definition.
+func_echo ()
+{
+ $debug_cmd
+
+ _G_message=$*
+
+ func_echo_IFS=$IFS
+ IFS=$nl
+ for _G_line in $_G_message; do
+ IFS=$func_echo_IFS
+ $ECHO "$progname${opt_mode+: $opt_mode}: $_G_line"
+ done
+ IFS=$func_echo_IFS
+}
+
+
+# func_warning ARG...
+# -------------------
+# Libtool warnings are not categorized, so override funclib.sh
+# func_warning with this simpler definition.
+func_warning ()
+{
+ $debug_cmd
+
+ $warning_func ${1+"$@"}
+}
+
+
+## ---------------- ##
+## Options parsing. ##
+## ---------------- ##
+
+# Hook in the functions to make sure our own options are parsed during
+# the option parsing loop.
+
+usage='$progpath [OPTION]... [MODE-ARG]...'
+
+# Short help message in response to '-h'.
+usage_message="Options:
+ --config show all configuration variables
+ --debug enable verbose shell tracing
+ -n, --dry-run display commands without modifying any files
+ --features display basic configuration information and exit
+ --mode=MODE use operation mode MODE
+ --no-warnings equivalent to '-Wnone'
+ --preserve-dup-deps don't remove duplicate dependency libraries
+ --quiet, --silent don't print informational messages
+ --tag=TAG use configuration variables from tag TAG
+ -v, --verbose print more informational messages than default
+ --version print version information
+ -W, --warnings=CATEGORY report the warnings falling in CATEGORY [all]
+ -h, --help, --help-all print short, long, or detailed help message
+"
+
+# Additional text appended to 'usage_message' in response to '--help'.
+func_help ()
+{
+ $debug_cmd
+
+ func_usage_message
+ $ECHO "$long_help_message
+
+MODE must be one of the following:
+
+ clean remove files from the build directory
+ compile compile a source file into a libtool object
+ execute automatically set library path, then run a program
+ finish complete the installation of libtool libraries
+ install install libraries or executables
+ link create a library or an executable
+ uninstall remove libraries from an installed directory
+
+MODE-ARGS vary depending on the MODE. When passed as first option,
+'--mode=MODE' may be abbreviated as 'MODE' or a unique abbreviation of that.
+Try '$progname --help --mode=MODE' for a more detailed description of MODE.
+
+When reporting a bug, please describe a test case to reproduce it and
+include the following information:
+
+ host-triplet: $host
+ shell: $SHELL
+ compiler: $LTCC
+ compiler flags: $LTCFLAGS
+ linker: $LD (gnu? $with_gnu_ld)
+ version: $progname (GNU libtool) 2.4.6
+ automake: `($AUTOMAKE --version) 2>/dev/null |$SED 1q`
+ autoconf: `($AUTOCONF --version) 2>/dev/null |$SED 1q`
+
+Report bugs to <bug-libtool@gnu.org>.
+GNU libtool home page: <http://www.gnu.org/s/libtool/>.
+General help using GNU software: <http://www.gnu.org/gethelp/>."
+ exit 0
+}
+
+
+# func_lo2o OBJECT-NAME
+# ---------------------
+# Transform OBJECT-NAME from a '.lo' suffix to the platform specific
+# object suffix.
+
+lo2o=s/\\.lo\$/.$objext/
+o2lo=s/\\.$objext\$/.lo/
+
+if test yes = "$_G_HAVE_XSI_OPS"; then
+ eval 'func_lo2o ()
+ {
+ case $1 in
+ *.lo) func_lo2o_result=${1%.lo}.$objext ;;
+ * ) func_lo2o_result=$1 ;;
+ esac
+ }'
+
+ # func_xform LIBOBJ-OR-SOURCE
+ # ---------------------------
+ # Transform LIBOBJ-OR-SOURCE from a '.o' or '.c' (or otherwise)
+ # suffix to a '.lo' libtool-object suffix.
+ eval 'func_xform ()
+ {
+ func_xform_result=${1%.*}.lo
+ }'
+else
+ # ...otherwise fall back to using sed.
+ func_lo2o ()
+ {
+ func_lo2o_result=`$ECHO "$1" | $SED "$lo2o"`
+ }
+
+ func_xform ()
+ {
+ func_xform_result=`$ECHO "$1" | $SED 's|\.[^.]*$|.lo|'`
+ }
+fi
+
+
+# func_fatal_configuration ARG...
+# -------------------------------
+# Echo program name prefixed message to standard error, followed by
+# a configuration failure hint, and exit.
+func_fatal_configuration ()
+{
+ func__fatal_error ${1+"$@"} \
+ "See the $PACKAGE documentation for more information." \
+ "Fatal configuration error."
+}
+
+
+# func_config
+# -----------
+# Display the configuration for all the tags in this script.
+func_config ()
+{
+ re_begincf='^# ### BEGIN LIBTOOL'
+ re_endcf='^# ### END LIBTOOL'
+
+ # Default configuration.
+ $SED "1,/$re_begincf CONFIG/d;/$re_endcf CONFIG/,\$d" < "$progpath"
+
+ # Now print the configurations for the tags.
+ for tagname in $taglist; do
+ $SED -n "/$re_begincf TAG CONFIG: $tagname\$/,/$re_endcf TAG CONFIG: $tagname\$/p" < "$progpath"
+ done
+
+ exit $?
+}
+
+
+# func_features
+# -------------
+# Display the features supported by this script.
+func_features ()
+{
+ echo "host: $host"
+ if test yes = "$build_libtool_libs"; then
+ echo "enable shared libraries"
+ else
+ echo "disable shared libraries"
+ fi
+ if test yes = "$build_old_libs"; then
+ echo "enable static libraries"
+ else
+ echo "disable static libraries"
+ fi
+
+ exit $?
+}
+
+
+# func_enable_tag TAGNAME
+# -----------------------
+# Verify that TAGNAME is valid, and either flag an error and exit, or
+# enable the TAGNAME tag. We also add TAGNAME to the global $taglist
+# variable here.
+func_enable_tag ()
+{
+ # Global variable:
+ tagname=$1
+
+ re_begincf="^# ### BEGIN LIBTOOL TAG CONFIG: $tagname\$"
+ re_endcf="^# ### END LIBTOOL TAG CONFIG: $tagname\$"
+ sed_extractcf=/$re_begincf/,/$re_endcf/p
+
+ # Validate tagname.
+ case $tagname in
+ *[!-_A-Za-z0-9,/]*)
+ func_fatal_error "invalid tag name: $tagname"
+ ;;
+ esac
+
+ # Don't test for the "default" C tag, as we know it's
+ # there but not specially marked.
+ case $tagname in
+ CC) ;;
+ *)
+ if $GREP "$re_begincf" "$progpath" >/dev/null 2>&1; then
+ taglist="$taglist $tagname"
+
+ # Evaluate the configuration. Be careful to quote the path
+ # and the sed script, to avoid splitting on whitespace, but
+ # also don't use non-portable quotes within backquotes within
+ # quotes we have to do it in 2 steps:
+ extractedcf=`$SED -n -e "$sed_extractcf" < "$progpath"`
+ eval "$extractedcf"
+ else
+ func_error "ignoring unknown tag $tagname"
+ fi
+ ;;
+ esac
+}
+
+
+# func_check_version_match
+# ------------------------
+# Ensure that we are using m4 macros, and libtool script from the same
+# release of libtool.
+func_check_version_match ()
+{
+ if test "$package_revision" != "$macro_revision"; then
+ if test "$VERSION" != "$macro_version"; then
+ if test -z "$macro_version"; then
+ cat >&2 <<_LT_EOF
+$progname: Version mismatch error. This is $PACKAGE $VERSION, but the
+$progname: definition of this LT_INIT comes from an older release.
+$progname: You should recreate aclocal.m4 with macros from $PACKAGE $VERSION
+$progname: and run autoconf again.
+_LT_EOF
+ else
+ cat >&2 <<_LT_EOF
+$progname: Version mismatch error. This is $PACKAGE $VERSION, but the
+$progname: definition of this LT_INIT comes from $PACKAGE $macro_version.
+$progname: You should recreate aclocal.m4 with macros from $PACKAGE $VERSION
+$progname: and run autoconf again.
+_LT_EOF
+ fi
+ else
+ cat >&2 <<_LT_EOF
+$progname: Version mismatch error. This is $PACKAGE $VERSION, revision $package_revision,
+$progname: but the definition of this LT_INIT comes from revision $macro_revision.
+$progname: You should recreate aclocal.m4 with macros from revision $package_revision
+$progname: of $PACKAGE $VERSION and run autoconf again.
+_LT_EOF
+ fi
+
+ exit $EXIT_MISMATCH
+ fi
+}
+
+
+# libtool_options_prep [ARG]...
+# -----------------------------
+# Preparation for options parsed by libtool.
+libtool_options_prep ()
+{
+ $debug_mode
+
+ # Option defaults:
+ opt_config=false
+ opt_dlopen=
+ opt_dry_run=false
+ opt_help=false
+ opt_mode=
+ opt_preserve_dup_deps=false
+ opt_quiet=false
+
+ nonopt=
+ preserve_args=
+
+ # Shorthand for --mode=foo, only valid as the first argument
+ case $1 in
+ clean|clea|cle|cl)
+ shift; set dummy --mode clean ${1+"$@"}; shift
+ ;;
+ compile|compil|compi|comp|com|co|c)
+ shift; set dummy --mode compile ${1+"$@"}; shift
+ ;;
+ execute|execut|execu|exec|exe|ex|e)
+ shift; set dummy --mode execute ${1+"$@"}; shift
+ ;;
+ finish|finis|fini|fin|fi|f)
+ shift; set dummy --mode finish ${1+"$@"}; shift
+ ;;
+ install|instal|insta|inst|ins|in|i)
+ shift; set dummy --mode install ${1+"$@"}; shift
+ ;;
+ link|lin|li|l)
+ shift; set dummy --mode link ${1+"$@"}; shift
+ ;;
+ uninstall|uninstal|uninsta|uninst|unins|unin|uni|un|u)
+ shift; set dummy --mode uninstall ${1+"$@"}; shift
+ ;;
+ esac
+
+ # Pass back the list of options.
+ func_quote_for_eval ${1+"$@"}
+ libtool_options_prep_result=$func_quote_for_eval_result
+}
+func_add_hook func_options_prep libtool_options_prep
+
+
+# libtool_parse_options [ARG]...
+# ---------------------------------
+# Provide handling for libtool specific options.
+libtool_parse_options ()
+{
+ $debug_cmd
+
+ # Perform our own loop to consume as many options as possible in
+ # each iteration.
+ while test $# -gt 0; do
+ _G_opt=$1
+ shift
+ case $_G_opt in
+ --dry-run|--dryrun|-n)
+ opt_dry_run=:
+ ;;
+
+ --config) func_config ;;
+
+ --dlopen|-dlopen)
+ opt_dlopen="${opt_dlopen+$opt_dlopen
+}$1"
+ shift
+ ;;
+
+ --preserve-dup-deps)
+ opt_preserve_dup_deps=: ;;
+
+ --features) func_features ;;
+
+ --finish) set dummy --mode finish ${1+"$@"}; shift ;;
+
+ --help) opt_help=: ;;
+
+ --help-all) opt_help=': help-all' ;;
+
+ --mode) test $# = 0 && func_missing_arg $_G_opt && break
+ opt_mode=$1
+ case $1 in
+ # Valid mode arguments:
+ clean|compile|execute|finish|install|link|relink|uninstall) ;;
+
+ # Catch anything else as an error
+ *) func_error "invalid argument for $_G_opt"
+ exit_cmd=exit
+ break
+ ;;
+ esac
+ shift
+ ;;
+
+ --no-silent|--no-quiet)
+ opt_quiet=false
+ func_append preserve_args " $_G_opt"
+ ;;
+
+ --no-warnings|--no-warning|--no-warn)
+ opt_warning=false
+ func_append preserve_args " $_G_opt"
+ ;;
+
+ --no-verbose)
+ opt_verbose=false
+ func_append preserve_args " $_G_opt"
+ ;;
+
+ --silent|--quiet)
+ opt_quiet=:
+ opt_verbose=false
+ func_append preserve_args " $_G_opt"
+ ;;
+
+ --tag) test $# = 0 && func_missing_arg $_G_opt && break
+ opt_tag=$1
+ func_append preserve_args " $_G_opt $1"
+ func_enable_tag "$1"
+ shift
+ ;;
+
+ --verbose|-v) opt_quiet=false
+ opt_verbose=:
+ func_append preserve_args " $_G_opt"
+ ;;
+
+ # An option not handled by this hook function:
+ *) set dummy "$_G_opt" ${1+"$@"}; shift; break ;;
+ esac
+ done
+
+
+ # save modified positional parameters for caller
+ func_quote_for_eval ${1+"$@"}
+ libtool_parse_options_result=$func_quote_for_eval_result
+}
+func_add_hook func_parse_options libtool_parse_options
+
+
+
+# libtool_validate_options [ARG]...
+# ---------------------------------
+# Perform any sanity checks on option settings and/or unconsumed
+# arguments.
+libtool_validate_options ()
+{
+ # save first non-option argument
+ if test 0 -lt $#; then
+ nonopt=$1
+ shift
+ fi
+
+ # preserve --debug
+ test : = "$debug_cmd" || func_append preserve_args " --debug"
+
+ case $host in
+ # Solaris2 added to fix http://debbugs.gnu.org/cgi/bugreport.cgi?bug=16452
+ # see also: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=59788
+ *cygwin* | *mingw* | *pw32* | *cegcc* | *solaris2* | *os2*)
+ # don't eliminate duplications in $postdeps and $predeps
+ opt_duplicate_compiler_generated_deps=:
+ ;;
+ *)
+ opt_duplicate_compiler_generated_deps=$opt_preserve_dup_deps
+ ;;
+ esac
+
+ $opt_help || {
+ # Sanity checks first:
+ func_check_version_match
+
+ test yes != "$build_libtool_libs" \
+ && test yes != "$build_old_libs" \
+ && func_fatal_configuration "not configured to build any kind of library"
+
+ # Darwin sucks
+ eval std_shrext=\"$shrext_cmds\"
+
+ # Only execute mode is allowed to have -dlopen flags.
+ if test -n "$opt_dlopen" && test execute != "$opt_mode"; then
+ func_error "unrecognized option '-dlopen'"
+ $ECHO "$help" 1>&2
+ exit $EXIT_FAILURE
+ fi
+
+ # Change the help message to a mode-specific one.
+ generic_help=$help
+ help="Try '$progname --help --mode=$opt_mode' for more information."
+ }
+
+ # Pass back the unparsed argument list
+ func_quote_for_eval ${1+"$@"}
+ libtool_validate_options_result=$func_quote_for_eval_result
+}
+func_add_hook func_validate_options libtool_validate_options
+
+
+# Process options as early as possible so that --help and --version
+# can return quickly.
+func_options ${1+"$@"}
+eval set dummy "$func_options_result"; shift
+
+
+
+## ----------- ##
+## Main. ##
+## ----------- ##
+
+magic='%%%MAGIC variable%%%'
+magic_exe='%%%MAGIC EXE variable%%%'
+
+# Global variables.
+extracted_archives=
+extracted_serial=0
+
+# If this variable is set in any of the actions, the command in it
+# will be execed at the end. This prevents here-documents from being
+# left over by shells.
+exec_cmd=
+
+
+# A function that is used when there is no print builtin or printf.
+func_fallback_echo ()
+{
+ eval 'cat <<_LTECHO_EOF
+$1
+_LTECHO_EOF'
+}
+
+# func_generated_by_libtool
+# True iff stdin has been generated by Libtool. This function is only
+# a basic sanity check; it will hardly flush out determined imposters.
+func_generated_by_libtool_p ()
+{
+ $GREP "^# Generated by .*$PACKAGE" > /dev/null 2>&1
+}
+
+# func_lalib_p file
+# True iff FILE is a libtool '.la' library or '.lo' object file.
+# This function is only a basic sanity check; it will hardly flush out
+# determined imposters.
+func_lalib_p ()
+{
+ test -f "$1" &&
+ $SED -e 4q "$1" 2>/dev/null | func_generated_by_libtool_p
+}
+
+# func_lalib_unsafe_p file
+# True iff FILE is a libtool '.la' library or '.lo' object file.
+# This function implements the same check as func_lalib_p without
+# resorting to external programs. To this end, it redirects stdin and
+# closes it afterwards, without saving the original file descriptor.
+# As a safety measure, use it only where a negative result would be
+# fatal anyway. Works if 'file' does not exist.
+func_lalib_unsafe_p ()
+{
+ lalib_p=no
+ if test -f "$1" && test -r "$1" && exec 5<&0 <"$1"; then
+ for lalib_p_l in 1 2 3 4
+ do
+ read lalib_p_line
+ case $lalib_p_line in
+ \#\ Generated\ by\ *$PACKAGE* ) lalib_p=yes; break;;
+ esac
+ done
+ exec 0<&5 5<&-
+ fi
+ test yes = "$lalib_p"
+}
+
+# func_ltwrapper_script_p file
+# True iff FILE is a libtool wrapper script
+# This function is only a basic sanity check; it will hardly flush out
+# determined imposters.
+func_ltwrapper_script_p ()
+{
+ test -f "$1" &&
+ $lt_truncate_bin < "$1" 2>/dev/null | func_generated_by_libtool_p
+}
+
+# func_ltwrapper_executable_p file
+# True iff FILE is a libtool wrapper executable
+# This function is only a basic sanity check; it will hardly flush out
+# determined imposters.
+func_ltwrapper_executable_p ()
+{
+ func_ltwrapper_exec_suffix=
+ case $1 in
+ *.exe) ;;
+ *) func_ltwrapper_exec_suffix=.exe ;;
+ esac
+ $GREP "$magic_exe" "$1$func_ltwrapper_exec_suffix" >/dev/null 2>&1
+}
+
+# func_ltwrapper_scriptname file
+# Assumes file is an ltwrapper_executable
+# uses $file to determine the appropriate filename for a
+# temporary ltwrapper_script.
+func_ltwrapper_scriptname ()
+{
+ func_dirname_and_basename "$1" "" "."
+ func_stripname '' '.exe' "$func_basename_result"
+ func_ltwrapper_scriptname_result=$func_dirname_result/$objdir/${func_stripname_result}_ltshwrapper
+}
+
+# func_ltwrapper_p file
+# True iff FILE is a libtool wrapper script or wrapper executable
+# This function is only a basic sanity check; it will hardly flush out
+# determined imposters.
+func_ltwrapper_p ()
+{
+ func_ltwrapper_script_p "$1" || func_ltwrapper_executable_p "$1"
+}
+
+
+# func_execute_cmds commands fail_cmd
+# Execute tilde-delimited COMMANDS.
+# If FAIL_CMD is given, eval that upon failure.
+# FAIL_CMD may read-access the current command in variable CMD!
+func_execute_cmds ()
+{
+ $debug_cmd
+
+ save_ifs=$IFS; IFS='~'
+ for cmd in $1; do
+ IFS=$sp$nl
+ eval cmd=\"$cmd\"
+ IFS=$save_ifs
+ func_show_eval "$cmd" "${2-:}"
+ done
+ IFS=$save_ifs
+}
+
+
+# func_source file
+# Source FILE, adding directory component if necessary.
+# Note that it is not necessary on cygwin/mingw to append a dot to
+# FILE even if both FILE and FILE.exe exist: automatic-append-.exe
+# behavior happens only for exec(3), not for open(2)! Also, sourcing
+# 'FILE.' does not work on cygwin managed mounts.
+func_source ()
+{
+ $debug_cmd
+
+ case $1 in
+ */* | *\\*) . "$1" ;;
+ *) . "./$1" ;;
+ esac
+}
+
+
+# func_resolve_sysroot PATH
+# Replace a leading = in PATH with a sysroot. Store the result into
+# func_resolve_sysroot_result
+func_resolve_sysroot ()
+{
+ func_resolve_sysroot_result=$1
+ case $func_resolve_sysroot_result in
+ =*)
+ func_stripname '=' '' "$func_resolve_sysroot_result"
+ func_resolve_sysroot_result=$lt_sysroot$func_stripname_result
+ ;;
+ esac
+}
+
+# func_replace_sysroot PATH
+# If PATH begins with the sysroot, replace it with = and
+# store the result into func_replace_sysroot_result.
+func_replace_sysroot ()
+{
+ case $lt_sysroot:$1 in
+ ?*:"$lt_sysroot"*)
+ func_stripname "$lt_sysroot" '' "$1"
+ func_replace_sysroot_result='='$func_stripname_result
+ ;;
+ *)
+ # Including no sysroot.
+ func_replace_sysroot_result=$1
+ ;;
+ esac
+}
+
+# func_infer_tag arg
+# Infer tagged configuration to use if any are available and
+# if one wasn't chosen via the "--tag" command line option.
+# Only attempt this if the compiler in the base compile
+# command doesn't match the default compiler.
+# arg is usually of the form 'gcc ...'
+func_infer_tag ()
+{
+ $debug_cmd
+
+ if test -n "$available_tags" && test -z "$tagname"; then
+ CC_quoted=
+ for arg in $CC; do
+ func_append_quoted CC_quoted "$arg"
+ done
+ CC_expanded=`func_echo_all $CC`
+ CC_quoted_expanded=`func_echo_all $CC_quoted`
+ case $@ in
+ # Blanks in the command may have been stripped by the calling shell,
+ # but not from the CC environment variable when configure was run.
+ " $CC "* | "$CC "* | " $CC_expanded "* | "$CC_expanded "* | \
+ " $CC_quoted"* | "$CC_quoted "* | " $CC_quoted_expanded "* | "$CC_quoted_expanded "*) ;;
+ # Blanks at the start of $base_compile will cause this to fail
+ # if we don't check for them as well.
+ *)
+ for z in $available_tags; do
+ if $GREP "^# ### BEGIN LIBTOOL TAG CONFIG: $z$" < "$progpath" > /dev/null; then
+ # Evaluate the configuration.
+ eval "`$SED -n -e '/^# ### BEGIN LIBTOOL TAG CONFIG: '$z'$/,/^# ### END LIBTOOL TAG CONFIG: '$z'$/p' < $progpath`"
+ CC_quoted=
+ for arg in $CC; do
+ # Double-quote args containing other shell metacharacters.
+ func_append_quoted CC_quoted "$arg"
+ done
+ CC_expanded=`func_echo_all $CC`
+ CC_quoted_expanded=`func_echo_all $CC_quoted`
+ case "$@ " in
+ " $CC "* | "$CC "* | " $CC_expanded "* | "$CC_expanded "* | \
+ " $CC_quoted"* | "$CC_quoted "* | " $CC_quoted_expanded "* | "$CC_quoted_expanded "*)
+ # The compiler in the base compile command matches
+ # the one in the tagged configuration.
+ # Assume this is the tagged configuration we want.
+ tagname=$z
+ break
+ ;;
+ esac
+ fi
+ done
+ # If $tagname still isn't set, then no tagged configuration
+ # was found and let the user know that the "--tag" command
+ # line option must be used.
+ if test -z "$tagname"; then
+ func_echo "unable to infer tagged configuration"
+ func_fatal_error "specify a tag with '--tag'"
+# else
+# func_verbose "using $tagname tagged configuration"
+ fi
+ ;;
+ esac
+ fi
+}
+
+
+
+# func_write_libtool_object output_name pic_name nonpic_name
+# Create a libtool object file (analogous to a ".la" file),
+# but don't create it if we're doing a dry run.
+func_write_libtool_object ()
+{
+ write_libobj=$1
+ if test yes = "$build_libtool_libs"; then
+ write_lobj=\'$2\'
+ else
+ write_lobj=none
+ fi
+
+ if test yes = "$build_old_libs"; then
+ write_oldobj=\'$3\'
+ else
+ write_oldobj=none
+ fi
+
+ $opt_dry_run || {
+ cat >${write_libobj}T <<EOF
+# $write_libobj - a libtool object file
+# Generated by $PROGRAM (GNU $PACKAGE) $VERSION
+#
+# Please DO NOT delete this file!
+# It is necessary for linking the library.
+
+# Name of the PIC object.
+pic_object=$write_lobj
+
+# Name of the non-PIC object
+non_pic_object=$write_oldobj
+
+EOF
+ $MV "${write_libobj}T" "$write_libobj"
+ }
+}
+
+
+##################################################
+# FILE NAME AND PATH CONVERSION HELPER FUNCTIONS #
+##################################################
+
+# func_convert_core_file_wine_to_w32 ARG
+# Helper function used by file name conversion functions when $build is *nix,
+# and $host is mingw, cygwin, or some other w32 environment. Relies on a
+# correctly configured wine environment available, with the winepath program
+# in $build's $PATH.
+#
+# ARG is the $build file name to be converted to w32 format.
+# Result is available in $func_convert_core_file_wine_to_w32_result, and will
+# be empty on error (or when ARG is empty)
+func_convert_core_file_wine_to_w32 ()
+{
+ $debug_cmd
+
+ func_convert_core_file_wine_to_w32_result=$1
+ if test -n "$1"; then
+ # Unfortunately, winepath does not exit with a non-zero error code, so we
+ # are forced to check the contents of stdout. On the other hand, if the
+ # command is not found, the shell will set an exit code of 127 and print
+ # *an error message* to stdout. So we must check for both error code of
+ # zero AND non-empty stdout, which explains the odd construction:
+ func_convert_core_file_wine_to_w32_tmp=`winepath -w "$1" 2>/dev/null`
+ if test "$?" -eq 0 && test -n "$func_convert_core_file_wine_to_w32_tmp"; then
+ func_convert_core_file_wine_to_w32_result=`$ECHO "$func_convert_core_file_wine_to_w32_tmp" |
+ $SED -e "$sed_naive_backslashify"`
+ else
+ func_convert_core_file_wine_to_w32_result=
+ fi
+ fi
+}
+# end: func_convert_core_file_wine_to_w32
+
+
+# func_convert_core_path_wine_to_w32 ARG
+# Helper function used by path conversion functions when $build is *nix, and
+# $host is mingw, cygwin, or some other w32 environment. Relies on a correctly
+# configured wine environment available, with the winepath program in $build's
+# $PATH. Assumes ARG has no leading or trailing path separator characters.
+#
+# ARG is path to be converted from $build format to win32.
+# Result is available in $func_convert_core_path_wine_to_w32_result.
+# Unconvertible file (directory) names in ARG are skipped; if no directory names
+# are convertible, then the result may be empty.
+func_convert_core_path_wine_to_w32 ()
+{
+ $debug_cmd
+
+ # unfortunately, winepath doesn't convert paths, only file names
+ func_convert_core_path_wine_to_w32_result=
+ if test -n "$1"; then
+ oldIFS=$IFS
+ IFS=:
+ for func_convert_core_path_wine_to_w32_f in $1; do
+ IFS=$oldIFS
+ func_convert_core_file_wine_to_w32 "$func_convert_core_path_wine_to_w32_f"
+ if test -n "$func_convert_core_file_wine_to_w32_result"; then
+ if test -z "$func_convert_core_path_wine_to_w32_result"; then
+ func_convert_core_path_wine_to_w32_result=$func_convert_core_file_wine_to_w32_result
+ else
+ func_append func_convert_core_path_wine_to_w32_result ";$func_convert_core_file_wine_to_w32_result"
+ fi
+ fi
+ done
+ IFS=$oldIFS
+ fi
+}
+# end: func_convert_core_path_wine_to_w32
+
+
+# func_cygpath ARGS...
+# Wrapper around calling the cygpath program via LT_CYGPATH. This is used when
+# when (1) $build is *nix and Cygwin is hosted via a wine environment; or (2)
+# $build is MSYS and $host is Cygwin, or (3) $build is Cygwin. In case (1) or
+# (2), returns the Cygwin file name or path in func_cygpath_result (input
+# file name or path is assumed to be in w32 format, as previously converted
+# from $build's *nix or MSYS format). In case (3), returns the w32 file name
+# or path in func_cygpath_result (input file name or path is assumed to be in
+# Cygwin format). Returns an empty string on error.
+#
+# ARGS are passed to cygpath, with the last one being the file name or path to
+# be converted.
+#
+# Specify the absolute *nix (or w32) name to cygpath in the LT_CYGPATH
+# environment variable; do not put it in $PATH.
+func_cygpath ()
+{
+ $debug_cmd
+
+ if test -n "$LT_CYGPATH" && test -f "$LT_CYGPATH"; then
+ func_cygpath_result=`$LT_CYGPATH "$@" 2>/dev/null`
+ if test "$?" -ne 0; then
+ # on failure, ensure result is empty
+ func_cygpath_result=
+ fi
+ else
+ func_cygpath_result=
+ func_error "LT_CYGPATH is empty or specifies non-existent file: '$LT_CYGPATH'"
+ fi
+}
+#end: func_cygpath
+
+
+# func_convert_core_msys_to_w32 ARG
+# Convert file name or path ARG from MSYS format to w32 format. Return
+# result in func_convert_core_msys_to_w32_result.
+func_convert_core_msys_to_w32 ()
+{
+ $debug_cmd
+
+ # awkward: cmd appends spaces to result
+ func_convert_core_msys_to_w32_result=`( cmd //c echo "$1" ) 2>/dev/null |
+ $SED -e 's/[ ]*$//' -e "$sed_naive_backslashify"`
+}
+#end: func_convert_core_msys_to_w32
+
+
+# func_convert_file_check ARG1 ARG2
+# Verify that ARG1 (a file name in $build format) was converted to $host
+# format in ARG2. Otherwise, emit an error message, but continue (resetting
+# func_to_host_file_result to ARG1).
+func_convert_file_check ()
+{
+ $debug_cmd
+
+ if test -z "$2" && test -n "$1"; then
+ func_error "Could not determine host file name corresponding to"
+ func_error " '$1'"
+ func_error "Continuing, but uninstalled executables may not work."
+ # Fallback:
+ func_to_host_file_result=$1
+ fi
+}
+# end func_convert_file_check
+
+
+# func_convert_path_check FROM_PATHSEP TO_PATHSEP FROM_PATH TO_PATH
+# Verify that FROM_PATH (a path in $build format) was converted to $host
+# format in TO_PATH. Otherwise, emit an error message, but continue, resetting
+# func_to_host_file_result to a simplistic fallback value (see below).
+func_convert_path_check ()
+{
+ $debug_cmd
+
+ if test -z "$4" && test -n "$3"; then
+ func_error "Could not determine the host path corresponding to"
+ func_error " '$3'"
+ func_error "Continuing, but uninstalled executables may not work."
+ # Fallback. This is a deliberately simplistic "conversion" and
+ # should not be "improved". See libtool.info.
+ if test "x$1" != "x$2"; then
+ lt_replace_pathsep_chars="s|$1|$2|g"
+ func_to_host_path_result=`echo "$3" |
+ $SED -e "$lt_replace_pathsep_chars"`
+ else
+ func_to_host_path_result=$3
+ fi
+ fi
+}
+# end func_convert_path_check
+
+
+# func_convert_path_front_back_pathsep FRONTPAT BACKPAT REPL ORIG
+# Modifies func_to_host_path_result by prepending REPL if ORIG matches FRONTPAT
+# and appending REPL if ORIG matches BACKPAT.
+func_convert_path_front_back_pathsep ()
+{
+ $debug_cmd
+
+ case $4 in
+ $1 ) func_to_host_path_result=$3$func_to_host_path_result
+ ;;
+ esac
+ case $4 in
+ $2 ) func_append func_to_host_path_result "$3"
+ ;;
+ esac
+}
+# end func_convert_path_front_back_pathsep
+
+
+##################################################
+# $build to $host FILE NAME CONVERSION FUNCTIONS #
+##################################################
+# invoked via '$to_host_file_cmd ARG'
+#
+# In each case, ARG is the path to be converted from $build to $host format.
+# Result will be available in $func_to_host_file_result.
+
+
+# func_to_host_file ARG
+# Converts the file name ARG from $build format to $host format. Return result
+# in func_to_host_file_result.
+func_to_host_file ()
+{
+ $debug_cmd
+
+ $to_host_file_cmd "$1"
+}
+# end func_to_host_file
+
+
+# func_to_tool_file ARG LAZY
+# converts the file name ARG from $build format to toolchain format. Return
+# result in func_to_tool_file_result. If the conversion in use is listed
+# in (the comma separated) LAZY, no conversion takes place.
+func_to_tool_file ()
+{
+ $debug_cmd
+
+ case ,$2, in
+ *,"$to_tool_file_cmd",*)
+ func_to_tool_file_result=$1
+ ;;
+ *)
+ $to_tool_file_cmd "$1"
+ func_to_tool_file_result=$func_to_host_file_result
+ ;;
+ esac
+}
+# end func_to_tool_file
+
+
+# func_convert_file_noop ARG
+# Copy ARG to func_to_host_file_result.
+func_convert_file_noop ()
+{
+ func_to_host_file_result=$1
+}
+# end func_convert_file_noop
+
+
+# func_convert_file_msys_to_w32 ARG
+# Convert file name ARG from (mingw) MSYS to (mingw) w32 format; automatic
+# conversion to w32 is not available inside the cwrapper. Returns result in
+# func_to_host_file_result.
+func_convert_file_msys_to_w32 ()
+{
+ $debug_cmd
+
+ func_to_host_file_result=$1
+ if test -n "$1"; then
+ func_convert_core_msys_to_w32 "$1"
+ func_to_host_file_result=$func_convert_core_msys_to_w32_result
+ fi
+ func_convert_file_check "$1" "$func_to_host_file_result"
+}
+# end func_convert_file_msys_to_w32
+
+
+# func_convert_file_cygwin_to_w32 ARG
+# Convert file name ARG from Cygwin to w32 format. Returns result in
+# func_to_host_file_result.
+func_convert_file_cygwin_to_w32 ()
+{
+ $debug_cmd
+
+ func_to_host_file_result=$1
+ if test -n "$1"; then
+ # because $build is cygwin, we call "the" cygpath in $PATH; no need to use
+ # LT_CYGPATH in this case.
+ func_to_host_file_result=`cygpath -m "$1"`
+ fi
+ func_convert_file_check "$1" "$func_to_host_file_result"
+}
+# end func_convert_file_cygwin_to_w32
+
+
+# func_convert_file_nix_to_w32 ARG
+# Convert file name ARG from *nix to w32 format. Requires a wine environment
+# and a working winepath. Returns result in func_to_host_file_result.
+func_convert_file_nix_to_w32 ()
+{
+ $debug_cmd
+
+ func_to_host_file_result=$1
+ if test -n "$1"; then
+ func_convert_core_file_wine_to_w32 "$1"
+ func_to_host_file_result=$func_convert_core_file_wine_to_w32_result
+ fi
+ func_convert_file_check "$1" "$func_to_host_file_result"
+}
+# end func_convert_file_nix_to_w32
+
+
+# func_convert_file_msys_to_cygwin ARG
+# Convert file name ARG from MSYS to Cygwin format. Requires LT_CYGPATH set.
+# Returns result in func_to_host_file_result.
+func_convert_file_msys_to_cygwin ()
+{
+ $debug_cmd
+
+ func_to_host_file_result=$1
+ if test -n "$1"; then
+ func_convert_core_msys_to_w32 "$1"
+ func_cygpath -u "$func_convert_core_msys_to_w32_result"
+ func_to_host_file_result=$func_cygpath_result
+ fi
+ func_convert_file_check "$1" "$func_to_host_file_result"
+}
+# end func_convert_file_msys_to_cygwin
+
+
+# func_convert_file_nix_to_cygwin ARG
+# Convert file name ARG from *nix to Cygwin format. Requires Cygwin installed
+# in a wine environment, working winepath, and LT_CYGPATH set. Returns result
+# in func_to_host_file_result.
+func_convert_file_nix_to_cygwin ()
+{
+ $debug_cmd
+
+ func_to_host_file_result=$1
+ if test -n "$1"; then
+ # convert from *nix to w32, then use cygpath to convert from w32 to cygwin.
+ func_convert_core_file_wine_to_w32 "$1"
+ func_cygpath -u "$func_convert_core_file_wine_to_w32_result"
+ func_to_host_file_result=$func_cygpath_result
+ fi
+ func_convert_file_check "$1" "$func_to_host_file_result"
+}
+# end func_convert_file_nix_to_cygwin
+
+
+#############################################
+# $build to $host PATH CONVERSION FUNCTIONS #
+#############################################
+# invoked via '$to_host_path_cmd ARG'
+#
+# In each case, ARG is the path to be converted from $build to $host format.
+# The result will be available in $func_to_host_path_result.
+#
+# Path separators are also converted from $build format to $host format. If
+# ARG begins or ends with a path separator character, it is preserved (but
+# converted to $host format) on output.
+#
+# All path conversion functions are named using the following convention:
+# file name conversion function : func_convert_file_X_to_Y ()
+# path conversion function : func_convert_path_X_to_Y ()
+# where, for any given $build/$host combination the 'X_to_Y' value is the
+# same. If conversion functions are added for new $build/$host combinations,
+# the two new functions must follow this pattern, or func_init_to_host_path_cmd
+# will break.
+
+
+# func_init_to_host_path_cmd
+# Ensures that function "pointer" variable $to_host_path_cmd is set to the
+# appropriate value, based on the value of $to_host_file_cmd.
+to_host_path_cmd=
+func_init_to_host_path_cmd ()
+{
+ $debug_cmd
+
+ if test -z "$to_host_path_cmd"; then
+ func_stripname 'func_convert_file_' '' "$to_host_file_cmd"
+ to_host_path_cmd=func_convert_path_$func_stripname_result
+ fi
+}
+
+
+# func_to_host_path ARG
+# Converts the path ARG from $build format to $host format. Return result
+# in func_to_host_path_result.
+func_to_host_path ()
+{
+ $debug_cmd
+
+ func_init_to_host_path_cmd
+ $to_host_path_cmd "$1"
+}
+# end func_to_host_path
+
+
+# func_convert_path_noop ARG
+# Copy ARG to func_to_host_path_result.
+func_convert_path_noop ()
+{
+ func_to_host_path_result=$1
+}
+# end func_convert_path_noop
+
+
+# func_convert_path_msys_to_w32 ARG
+# Convert path ARG from (mingw) MSYS to (mingw) w32 format; automatic
+# conversion to w32 is not available inside the cwrapper. Returns result in
+# func_to_host_path_result.
+func_convert_path_msys_to_w32 ()
+{
+ $debug_cmd
+
+ func_to_host_path_result=$1
+ if test -n "$1"; then
+ # Remove leading and trailing path separator characters from ARG. MSYS
+ # behavior is inconsistent here; cygpath turns them into '.;' and ';.';
+ # and winepath ignores them completely.
+ func_stripname : : "$1"
+ func_to_host_path_tmp1=$func_stripname_result
+ func_convert_core_msys_to_w32 "$func_to_host_path_tmp1"
+ func_to_host_path_result=$func_convert_core_msys_to_w32_result
+ func_convert_path_check : ";" \
+ "$func_to_host_path_tmp1" "$func_to_host_path_result"
+ func_convert_path_front_back_pathsep ":*" "*:" ";" "$1"
+ fi
+}
+# end func_convert_path_msys_to_w32
+
+
+# func_convert_path_cygwin_to_w32 ARG
+# Convert path ARG from Cygwin to w32 format. Returns result in
+# func_to_host_file_result.
+func_convert_path_cygwin_to_w32 ()
+{
+ $debug_cmd
+
+ func_to_host_path_result=$1
+ if test -n "$1"; then
+ # See func_convert_path_msys_to_w32:
+ func_stripname : : "$1"
+ func_to_host_path_tmp1=$func_stripname_result
+ func_to_host_path_result=`cygpath -m -p "$func_to_host_path_tmp1"`
+ func_convert_path_check : ";" \
+ "$func_to_host_path_tmp1" "$func_to_host_path_result"
+ func_convert_path_front_back_pathsep ":*" "*:" ";" "$1"
+ fi
+}
+# end func_convert_path_cygwin_to_w32
+
+
+# func_convert_path_nix_to_w32 ARG
+# Convert path ARG from *nix to w32 format. Requires a wine environment and
+# a working winepath. Returns result in func_to_host_file_result.
+func_convert_path_nix_to_w32 ()
+{
+ $debug_cmd
+
+ func_to_host_path_result=$1
+ if test -n "$1"; then
+ # See func_convert_path_msys_to_w32:
+ func_stripname : : "$1"
+ func_to_host_path_tmp1=$func_stripname_result
+ func_convert_core_path_wine_to_w32 "$func_to_host_path_tmp1"
+ func_to_host_path_result=$func_convert_core_path_wine_to_w32_result
+ func_convert_path_check : ";" \
+ "$func_to_host_path_tmp1" "$func_to_host_path_result"
+ func_convert_path_front_back_pathsep ":*" "*:" ";" "$1"
+ fi
+}
+# end func_convert_path_nix_to_w32
+
+
+# func_convert_path_msys_to_cygwin ARG
+# Convert path ARG from MSYS to Cygwin format. Requires LT_CYGPATH set.
+# Returns result in func_to_host_file_result.
+func_convert_path_msys_to_cygwin ()
+{
+ $debug_cmd
+
+ func_to_host_path_result=$1
+ if test -n "$1"; then
+ # See func_convert_path_msys_to_w32:
+ func_stripname : : "$1"
+ func_to_host_path_tmp1=$func_stripname_result
+ func_convert_core_msys_to_w32 "$func_to_host_path_tmp1"
+ func_cygpath -u -p "$func_convert_core_msys_to_w32_result"
+ func_to_host_path_result=$func_cygpath_result
+ func_convert_path_check : : \
+ "$func_to_host_path_tmp1" "$func_to_host_path_result"
+ func_convert_path_front_back_pathsep ":*" "*:" : "$1"
+ fi
+}
+# end func_convert_path_msys_to_cygwin
+
+
+# func_convert_path_nix_to_cygwin ARG
+# Convert path ARG from *nix to Cygwin format. Requires Cygwin installed in a
+# a wine environment, working winepath, and LT_CYGPATH set. Returns result in
+# func_to_host_file_result.
+func_convert_path_nix_to_cygwin ()
+{
+ $debug_cmd
+
+ func_to_host_path_result=$1
+ if test -n "$1"; then
+ # Remove leading and trailing path separator characters from
+ # ARG. msys behavior is inconsistent here, cygpath turns them
+ # into '.;' and ';.', and winepath ignores them completely.
+ func_stripname : : "$1"
+ func_to_host_path_tmp1=$func_stripname_result
+ func_convert_core_path_wine_to_w32 "$func_to_host_path_tmp1"
+ func_cygpath -u -p "$func_convert_core_path_wine_to_w32_result"
+ func_to_host_path_result=$func_cygpath_result
+ func_convert_path_check : : \
+ "$func_to_host_path_tmp1" "$func_to_host_path_result"
+ func_convert_path_front_back_pathsep ":*" "*:" : "$1"
+ fi
+}
+# end func_convert_path_nix_to_cygwin
+
+
+# func_dll_def_p FILE
+# True iff FILE is a Windows DLL '.def' file.
+# Keep in sync with _LT_DLL_DEF_P in libtool.m4
+func_dll_def_p ()
+{
+ $debug_cmd
+
+ func_dll_def_p_tmp=`$SED -n \
+ -e 's/^[ ]*//' \
+ -e '/^\(;.*\)*$/d' \
+ -e 's/^\(EXPORTS\|LIBRARY\)\([ ].*\)*$/DEF/p' \
+ -e q \
+ "$1"`
+ test DEF = "$func_dll_def_p_tmp"
+}
+
+
+# func_mode_compile arg...
+func_mode_compile ()
+{
+ $debug_cmd
+
+ # Get the compilation command and the source file.
+ base_compile=
+ srcfile=$nonopt # always keep a non-empty value in "srcfile"
+ suppress_opt=yes
+ suppress_output=
+ arg_mode=normal
+ libobj=
+ later=
+ pie_flag=
+
+ for arg
+ do
+ case $arg_mode in
+ arg )
+ # do not "continue". Instead, add this to base_compile
+ lastarg=$arg
+ arg_mode=normal
+ ;;
+
+ target )
+ libobj=$arg
+ arg_mode=normal
+ continue
+ ;;
+
+ normal )
+ # Accept any command-line options.
+ case $arg in
+ -o)
+ test -n "$libobj" && \
+ func_fatal_error "you cannot specify '-o' more than once"
+ arg_mode=target
+ continue
+ ;;
+
+ -pie | -fpie | -fPIE)
+ func_append pie_flag " $arg"
+ continue
+ ;;
+
+ -shared | -static | -prefer-pic | -prefer-non-pic)
+ func_append later " $arg"
+ continue
+ ;;
+
+ -no-suppress)
+ suppress_opt=no
+ continue
+ ;;
+
+ -Xcompiler)
+ arg_mode=arg # the next one goes into the "base_compile" arg list
+ continue # The current "srcfile" will either be retained or
+ ;; # replaced later. I would guess that would be a bug.
+
+ -Wc,*)
+ func_stripname '-Wc,' '' "$arg"
+ args=$func_stripname_result
+ lastarg=
+ save_ifs=$IFS; IFS=,
+ for arg in $args; do
+ IFS=$save_ifs
+ func_append_quoted lastarg "$arg"
+ done
+ IFS=$save_ifs
+ func_stripname ' ' '' "$lastarg"
+ lastarg=$func_stripname_result
+
+ # Add the arguments to base_compile.
+ func_append base_compile " $lastarg"
+ continue
+ ;;
+
+ *)
+ # Accept the current argument as the source file.
+ # The previous "srcfile" becomes the current argument.
+ #
+ lastarg=$srcfile
+ srcfile=$arg
+ ;;
+ esac # case $arg
+ ;;
+ esac # case $arg_mode
+
+ # Aesthetically quote the previous argument.
+ func_append_quoted base_compile "$lastarg"
+ done # for arg
+
+ case $arg_mode in
+ arg)
+ func_fatal_error "you must specify an argument for -Xcompile"
+ ;;
+ target)
+ func_fatal_error "you must specify a target with '-o'"
+ ;;
+ *)
+ # Get the name of the library object.
+ test -z "$libobj" && {
+ func_basename "$srcfile"
+ libobj=$func_basename_result
+ }
+ ;;
+ esac
+
+ # Recognize several different file suffixes.
+ # If the user specifies -o file.o, it is replaced with file.lo
+ case $libobj in
+ *.[cCFSifmso] | \
+ *.ada | *.adb | *.ads | *.asm | \
+ *.c++ | *.cc | *.ii | *.class | *.cpp | *.cxx | \
+ *.[fF][09]? | *.for | *.java | *.go | *.obj | *.sx | *.cu | *.cup)
+ func_xform "$libobj"
+ libobj=$func_xform_result
+ ;;
+ esac
+
+ case $libobj in
+ *.lo) func_lo2o "$libobj"; obj=$func_lo2o_result ;;
+ *)
+ func_fatal_error "cannot determine name of library object from '$libobj'"
+ ;;
+ esac
+
+ func_infer_tag $base_compile
+
+ for arg in $later; do
+ case $arg in
+ -shared)
+ test yes = "$build_libtool_libs" \
+ || func_fatal_configuration "cannot build a shared library"
+ build_old_libs=no
+ continue
+ ;;
+
+ -static)
+ build_libtool_libs=no
+ build_old_libs=yes
+ continue
+ ;;
+
+ -prefer-pic)
+ pic_mode=yes
+ continue
+ ;;
+
+ -prefer-non-pic)
+ pic_mode=no
+ continue
+ ;;
+ esac
+ done
+
+ func_quote_for_eval "$libobj"
+ test "X$libobj" != "X$func_quote_for_eval_result" \
+ && $ECHO "X$libobj" | $GREP '[]~#^*{};<>?"'"'"' &()|`$[]' \
+ && func_warning "libobj name '$libobj' may not contain shell special characters."
+ func_dirname_and_basename "$obj" "/" ""
+ objname=$func_basename_result
+ xdir=$func_dirname_result
+ lobj=$xdir$objdir/$objname
+
+ test -z "$base_compile" && \
+ func_fatal_help "you must specify a compilation command"
+
+ # Delete any leftover library objects.
+ if test yes = "$build_old_libs"; then
+ removelist="$obj $lobj $libobj ${libobj}T"
+ else
+ removelist="$lobj $libobj ${libobj}T"
+ fi
+
+ # On Cygwin there's no "real" PIC flag so we must build both object types
+ case $host_os in
+ cygwin* | mingw* | pw32* | os2* | cegcc*)
+ pic_mode=default
+ ;;
+ esac
+ if test no = "$pic_mode" && test pass_all != "$deplibs_check_method"; then
+ # non-PIC code in shared libraries is not supported
+ pic_mode=default
+ fi
+
+ # Calculate the filename of the output object if compiler does
+ # not support -o with -c
+ if test no = "$compiler_c_o"; then
+ output_obj=`$ECHO "$srcfile" | $SED 's%^.*/%%; s%\.[^.]*$%%'`.$objext
+ lockfile=$output_obj.lock
+ else
+ output_obj=
+ need_locks=no
+ lockfile=
+ fi
+
+ # Lock this critical section if it is needed
+ # We use this script file to make the link, it avoids creating a new file
+ if test yes = "$need_locks"; then
+ until $opt_dry_run || ln "$progpath" "$lockfile" 2>/dev/null; do
+ func_echo "Waiting for $lockfile to be removed"
+ sleep 2
+ done
+ elif test warn = "$need_locks"; then
+ if test -f "$lockfile"; then
+ $ECHO "\
+*** ERROR, $lockfile exists and contains:
+`cat $lockfile 2>/dev/null`
+
+This indicates that another process is trying to use the same
+temporary object file, and libtool could not work around it because
+your compiler does not support '-c' and '-o' together. If you
+repeat this compilation, it may succeed, by chance, but you had better
+avoid parallel builds (make -j) in this platform, or get a better
+compiler."
+
+ $opt_dry_run || $RM $removelist
+ exit $EXIT_FAILURE
+ fi
+ func_append removelist " $output_obj"
+ $ECHO "$srcfile" > "$lockfile"
+ fi
+
+ $opt_dry_run || $RM $removelist
+ func_append removelist " $lockfile"
+ trap '$opt_dry_run || $RM $removelist; exit $EXIT_FAILURE' 1 2 15
+
+ func_to_tool_file "$srcfile" func_convert_file_msys_to_w32
+ srcfile=$func_to_tool_file_result
+ func_quote_for_eval "$srcfile"
+ qsrcfile=$func_quote_for_eval_result
+
+ # Only build a PIC object if we are building libtool libraries.
+ if test yes = "$build_libtool_libs"; then
+ # Without this assignment, base_compile gets emptied.
+ fbsd_hideous_sh_bug=$base_compile
+
+ if test no != "$pic_mode"; then
+ command="$base_compile $qsrcfile $pic_flag"
+ else
+ # Don't build PIC code
+ command="$base_compile $qsrcfile"
+ fi
+
+ func_mkdir_p "$xdir$objdir"
+
+ if test -z "$output_obj"; then
+ # Place PIC objects in $objdir
+ func_append command " -o $lobj"
+ fi
+
+ func_show_eval_locale "$command" \
+ 'test -n "$output_obj" && $RM $removelist; exit $EXIT_FAILURE'
+
+ if test warn = "$need_locks" &&
+ test "X`cat $lockfile 2>/dev/null`" != "X$srcfile"; then
+ $ECHO "\
+*** ERROR, $lockfile contains:
+`cat $lockfile 2>/dev/null`
+
+but it should contain:
+$srcfile
+
+This indicates that another process is trying to use the same
+temporary object file, and libtool could not work around it because
+your compiler does not support '-c' and '-o' together. If you
+repeat this compilation, it may succeed, by chance, but you had better
+avoid parallel builds (make -j) in this platform, or get a better
+compiler."
+
+ $opt_dry_run || $RM $removelist
+ exit $EXIT_FAILURE
+ fi
+
+ # Just move the object if needed, then go on to compile the next one
+ if test -n "$output_obj" && test "X$output_obj" != "X$lobj"; then
+ func_show_eval '$MV "$output_obj" "$lobj"' \
+ 'error=$?; $opt_dry_run || $RM $removelist; exit $error'
+ fi
+
+ # Allow error messages only from the first compilation.
+ if test yes = "$suppress_opt"; then
+ suppress_output=' >/dev/null 2>&1'
+ fi
+ fi
+
+ # Only build a position-dependent object if we build old libraries.
+ if test yes = "$build_old_libs"; then
+ if test yes != "$pic_mode"; then
+ # Don't build PIC code
+ command="$base_compile $qsrcfile$pie_flag"
+ else
+ command="$base_compile $qsrcfile $pic_flag"
+ fi
+ if test yes = "$compiler_c_o"; then
+ func_append command " -o $obj"
+ fi
+
+ # Suppress compiler output if we already did a PIC compilation.
+ func_append command "$suppress_output"
+ func_show_eval_locale "$command" \
+ '$opt_dry_run || $RM $removelist; exit $EXIT_FAILURE'
+
+ if test warn = "$need_locks" &&
+ test "X`cat $lockfile 2>/dev/null`" != "X$srcfile"; then
+ $ECHO "\
+*** ERROR, $lockfile contains:
+`cat $lockfile 2>/dev/null`
+
+but it should contain:
+$srcfile
+
+This indicates that another process is trying to use the same
+temporary object file, and libtool could not work around it because
+your compiler does not support '-c' and '-o' together. If you
+repeat this compilation, it may succeed, by chance, but you had better
+avoid parallel builds (make -j) in this platform, or get a better
+compiler."
+
+ $opt_dry_run || $RM $removelist
+ exit $EXIT_FAILURE
+ fi
+
+ # Just move the object if needed
+ if test -n "$output_obj" && test "X$output_obj" != "X$obj"; then
+ func_show_eval '$MV "$output_obj" "$obj"' \
+ 'error=$?; $opt_dry_run || $RM $removelist; exit $error'
+ fi
+ fi
+
+ $opt_dry_run || {
+ func_write_libtool_object "$libobj" "$objdir/$objname" "$objname"
+
+ # Unlock the critical section if it was locked
+ if test no != "$need_locks"; then
+ removelist=$lockfile
+ $RM "$lockfile"
+ fi
+ }
+
+ exit $EXIT_SUCCESS
+}
+
+$opt_help || {
+ test compile = "$opt_mode" && func_mode_compile ${1+"$@"}
+}
+
+func_mode_help ()
+{
+ # We need to display help for each of the modes.
+ case $opt_mode in
+ "")
+ # Generic help is extracted from the usage comments
+ # at the start of this file.
+ func_help
+ ;;
+
+ clean)
+ $ECHO \
+"Usage: $progname [OPTION]... --mode=clean RM [RM-OPTION]... FILE...
+
+Remove files from the build directory.
+
+RM is the name of the program to use to delete files associated with each FILE
+(typically '/bin/rm'). RM-OPTIONS are options (such as '-f') to be passed
+to RM.
+
+If FILE is a libtool library, object or program, all the files associated
+with it are deleted. Otherwise, only FILE itself is deleted using RM."
+ ;;
+
+ compile)
+ $ECHO \
+"Usage: $progname [OPTION]... --mode=compile COMPILE-COMMAND... SOURCEFILE
+
+Compile a source file into a libtool library object.
+
+This mode accepts the following additional options:
+
+ -o OUTPUT-FILE set the output file name to OUTPUT-FILE
+ -no-suppress do not suppress compiler output for multiple passes
+ -prefer-pic try to build PIC objects only
+ -prefer-non-pic try to build non-PIC objects only
+ -shared do not build a '.o' file suitable for static linking
+ -static only build a '.o' file suitable for static linking
+ -Wc,FLAG pass FLAG directly to the compiler
+
+COMPILE-COMMAND is a command to be used in creating a 'standard' object file
+from the given SOURCEFILE.
+
+The output file name is determined by removing the directory component from
+SOURCEFILE, then substituting the C source code suffix '.c' with the
+library object suffix, '.lo'."
+ ;;
+
+ execute)
+ $ECHO \
+"Usage: $progname [OPTION]... --mode=execute COMMAND [ARGS]...
+
+Automatically set library path, then run a program.
+
+This mode accepts the following additional options:
+
+ -dlopen FILE add the directory containing FILE to the library path
+
+This mode sets the library path environment variable according to '-dlopen'
+flags.
+
+If any of the ARGS are libtool executable wrappers, then they are translated
+into their corresponding uninstalled binary, and any of their required library
+directories are added to the library path.
+
+Then, COMMAND is executed, with ARGS as arguments."
+ ;;
+
+ finish)
+ $ECHO \
+"Usage: $progname [OPTION]... --mode=finish [LIBDIR]...
+
+Complete the installation of libtool libraries.
+
+Each LIBDIR is a directory that contains libtool libraries.
+
+The commands that this mode executes may require superuser privileges. Use
+the '--dry-run' option if you just want to see what would be executed."
+ ;;
+
+ install)
+ $ECHO \
+"Usage: $progname [OPTION]... --mode=install INSTALL-COMMAND...
+
+Install executables or libraries.
+
+INSTALL-COMMAND is the installation command. The first component should be
+either the 'install' or 'cp' program.
+
+The following components of INSTALL-COMMAND are treated specially:
+
+ -inst-prefix-dir PREFIX-DIR Use PREFIX-DIR as a staging area for installation
+
+The rest of the components are interpreted as arguments to that command (only
+BSD-compatible install options are recognized)."
+ ;;
+
+ link)
+ $ECHO \
+"Usage: $progname [OPTION]... --mode=link LINK-COMMAND...
+
+Link object files or libraries together to form another library, or to
+create an executable program.
+
+LINK-COMMAND is a command using the C compiler that you would use to create
+a program from several object files.
+
+The following components of LINK-COMMAND are treated specially:
+
+ -all-static do not do any dynamic linking at all
+ -avoid-version do not add a version suffix if possible
+ -bindir BINDIR specify path to binaries directory (for systems where
+ libraries must be found in the PATH setting at runtime)
+ -dlopen FILE '-dlpreopen' FILE if it cannot be dlopened at runtime
+ -dlpreopen FILE link in FILE and add its symbols to lt_preloaded_symbols
+ -export-dynamic allow symbols from OUTPUT-FILE to be resolved with dlsym(3)
+ -export-symbols SYMFILE
+ try to export only the symbols listed in SYMFILE
+ -export-symbols-regex REGEX
+ try to export only the symbols matching REGEX
+ -LLIBDIR search LIBDIR for required installed libraries
+ -lNAME OUTPUT-FILE requires the installed library libNAME
+ -module build a library that can dlopened
+ -no-fast-install disable the fast-install mode
+ -no-install link a not-installable executable
+ -no-undefined declare that a library does not refer to external symbols
+ -o OUTPUT-FILE create OUTPUT-FILE from the specified objects
+ -objectlist FILE use a list of object files found in FILE to specify objects
+ -os2dllname NAME force a short DLL name on OS/2 (no effect on other OSes)
+ -precious-files-regex REGEX
+ don't remove output files matching REGEX
+ -release RELEASE specify package release information
+ -rpath LIBDIR the created library will eventually be installed in LIBDIR
+ -R[ ]LIBDIR add LIBDIR to the runtime path of programs and libraries
+ -shared only do dynamic linking of libtool libraries
+ -shrext SUFFIX override the standard shared library file extension
+ -static do not do any dynamic linking of uninstalled libtool libraries
+ -static-libtool-libs
+ do not do any dynamic linking of libtool libraries
+ -version-info CURRENT[:REVISION[:AGE]]
+ specify library version info [each variable defaults to 0]
+ -weak LIBNAME declare that the target provides the LIBNAME interface
+ -Wc,FLAG
+ -Xcompiler FLAG pass linker-specific FLAG directly to the compiler
+ -Wl,FLAG
+ -Xlinker FLAG pass linker-specific FLAG directly to the linker
+ -XCClinker FLAG pass link-specific FLAG to the compiler driver (CC)
+
+All other options (arguments beginning with '-') are ignored.
+
+Every other argument is treated as a filename. Files ending in '.la' are
+treated as uninstalled libtool libraries, other files are standard or library
+object files.
+
+If the OUTPUT-FILE ends in '.la', then a libtool library is created,
+only library objects ('.lo' files) may be specified, and '-rpath' is
+required, except when creating a convenience library.
+
+If OUTPUT-FILE ends in '.a' or '.lib', then a standard library is created
+using 'ar' and 'ranlib', or on Windows using 'lib'.
+
+If OUTPUT-FILE ends in '.lo' or '.$objext', then a reloadable object file
+is created, otherwise an executable program is created."
+ ;;
+
+ uninstall)
+ $ECHO \
+"Usage: $progname [OPTION]... --mode=uninstall RM [RM-OPTION]... FILE...
+
+Remove libraries from an installation directory.
+
+RM is the name of the program to use to delete files associated with each FILE
+(typically '/bin/rm'). RM-OPTIONS are options (such as '-f') to be passed
+to RM.
+
+If FILE is a libtool library, all the files associated with it are deleted.
+Otherwise, only FILE itself is deleted using RM."
+ ;;
+
+ *)
+ func_fatal_help "invalid operation mode '$opt_mode'"
+ ;;
+ esac
+
+ echo
+ $ECHO "Try '$progname --help' for more information about other modes."
+}
+
+# Now that we've collected a possible --mode arg, show help if necessary
+if $opt_help; then
+ if test : = "$opt_help"; then
+ func_mode_help
+ else
+ {
+ func_help noexit
+ for opt_mode in compile link execute install finish uninstall clean; do
+ func_mode_help
+ done
+ } | $SED -n '1p; 2,$s/^Usage:/ or: /p'
+ {
+ func_help noexit
+ for opt_mode in compile link execute install finish uninstall clean; do
+ echo
+ func_mode_help
+ done
+ } |
+ $SED '1d
+ /^When reporting/,/^Report/{
+ H
+ d
+ }
+ $x
+ /information about other modes/d
+ /more detailed .*MODE/d
+ s/^Usage:.*--mode=\([^ ]*\) .*/Description of \1 mode:/'
+ fi
+ exit $?
+fi
+
+
+# func_mode_execute arg...
+func_mode_execute ()
+{
+ $debug_cmd
+
+ # The first argument is the command name.
+ cmd=$nonopt
+ test -z "$cmd" && \
+ func_fatal_help "you must specify a COMMAND"
+
+ # Handle -dlopen flags immediately.
+ for file in $opt_dlopen; do
+ test -f "$file" \
+ || func_fatal_help "'$file' is not a file"
+
+ dir=
+ case $file in
+ *.la)
+ func_resolve_sysroot "$file"
+ file=$func_resolve_sysroot_result
+
+ # Check to see that this really is a libtool archive.
+ func_lalib_unsafe_p "$file" \
+ || func_fatal_help "'$lib' is not a valid libtool archive"
+
+ # Read the libtool library.
+ dlname=
+ library_names=
+ func_source "$file"
+
+ # Skip this library if it cannot be dlopened.
+ if test -z "$dlname"; then
+ # Warn if it was a shared library.
+ test -n "$library_names" && \
+ func_warning "'$file' was not linked with '-export-dynamic'"
+ continue
+ fi
+
+ func_dirname "$file" "" "."
+ dir=$func_dirname_result
+
+ if test -f "$dir/$objdir/$dlname"; then
+ func_append dir "/$objdir"
+ else
+ if test ! -f "$dir/$dlname"; then
+ func_fatal_error "cannot find '$dlname' in '$dir' or '$dir/$objdir'"
+ fi
+ fi
+ ;;
+
+ *.lo)
+ # Just add the directory containing the .lo file.
+ func_dirname "$file" "" "."
+ dir=$func_dirname_result
+ ;;
+
+ *)
+ func_warning "'-dlopen' is ignored for non-libtool libraries and objects"
+ continue
+ ;;
+ esac
+
+ # Get the absolute pathname.
+ absdir=`cd "$dir" && pwd`
+ test -n "$absdir" && dir=$absdir
+
+ # Now add the directory to shlibpath_var.
+ if eval "test -z \"\$$shlibpath_var\""; then
+ eval "$shlibpath_var=\"\$dir\""
+ else
+ eval "$shlibpath_var=\"\$dir:\$$shlibpath_var\""
+ fi
+ done
+
+ # This variable tells wrapper scripts just to set shlibpath_var
+ # rather than running their programs.
+ libtool_execute_magic=$magic
+
+ # Check if any of the arguments is a wrapper script.
+ args=
+ for file
+ do
+ case $file in
+ -* | *.la | *.lo ) ;;
+ *)
+ # Do a test to see if this is really a libtool program.
+ if func_ltwrapper_script_p "$file"; then
+ func_source "$file"
+ # Transform arg to wrapped name.
+ file=$progdir/$program
+ elif func_ltwrapper_executable_p "$file"; then
+ func_ltwrapper_scriptname "$file"
+ func_source "$func_ltwrapper_scriptname_result"
+ # Transform arg to wrapped name.
+ file=$progdir/$program
+ fi
+ ;;
+ esac
+ # Quote arguments (to preserve shell metacharacters).
+ func_append_quoted args "$file"
+ done
+
+ if $opt_dry_run; then
+ # Display what would be done.
+ if test -n "$shlibpath_var"; then
+ eval "\$ECHO \"\$shlibpath_var=\$$shlibpath_var\""
+ echo "export $shlibpath_var"
+ fi
+ $ECHO "$cmd$args"
+ exit $EXIT_SUCCESS
+ else
+ if test -n "$shlibpath_var"; then
+ # Export the shlibpath_var.
+ eval "export $shlibpath_var"
+ fi
+
+ # Restore saved environment variables
+ for lt_var in LANG LANGUAGE LC_ALL LC_CTYPE LC_COLLATE LC_MESSAGES
+ do
+ eval "if test \"\${save_$lt_var+set}\" = set; then
+ $lt_var=\$save_$lt_var; export $lt_var
+ else
+ $lt_unset $lt_var
+ fi"
+ done
+
+ # Now prepare to actually exec the command.
+ exec_cmd=\$cmd$args
+ fi
+}
+
+test execute = "$opt_mode" && func_mode_execute ${1+"$@"}
+
+
+# func_mode_finish arg...
+func_mode_finish ()
+{
+ $debug_cmd
+
+ libs=
+ libdirs=
+ admincmds=
+
+ for opt in "$nonopt" ${1+"$@"}
+ do
+ if test -d "$opt"; then
+ func_append libdirs " $opt"
+
+ elif test -f "$opt"; then
+ if func_lalib_unsafe_p "$opt"; then
+ func_append libs " $opt"
+ else
+ func_warning "'$opt' is not a valid libtool archive"
+ fi
+
+ else
+ func_fatal_error "invalid argument '$opt'"
+ fi
+ done
+
+ if test -n "$libs"; then
+ if test -n "$lt_sysroot"; then
+ sysroot_regex=`$ECHO "$lt_sysroot" | $SED "$sed_make_literal_regex"`
+ sysroot_cmd="s/\([ ']\)$sysroot_regex/\1/g;"
+ else
+ sysroot_cmd=
+ fi
+
+ # Remove sysroot references
+ if $opt_dry_run; then
+ for lib in $libs; do
+ echo "removing references to $lt_sysroot and '=' prefixes from $lib"
+ done
+ else
+ tmpdir=`func_mktempdir`
+ for lib in $libs; do
+ $SED -e "$sysroot_cmd s/\([ ']-[LR]\)=/\1/g; s/\([ ']\)=/\1/g" $lib \
+ > $tmpdir/tmp-la
+ mv -f $tmpdir/tmp-la $lib
+ done
+ ${RM}r "$tmpdir"
+ fi
+ fi
+
+ if test -n "$finish_cmds$finish_eval" && test -n "$libdirs"; then
+ for libdir in $libdirs; do
+ if test -n "$finish_cmds"; then
+ # Do each command in the finish commands.
+ func_execute_cmds "$finish_cmds" 'admincmds="$admincmds
+'"$cmd"'"'
+ fi
+ if test -n "$finish_eval"; then
+ # Do the single finish_eval.
+ eval cmds=\"$finish_eval\"
+ $opt_dry_run || eval "$cmds" || func_append admincmds "
+ $cmds"
+ fi
+ done
+ fi
+
+ # Exit here if they wanted silent mode.
+ $opt_quiet && exit $EXIT_SUCCESS
+
+ if test -n "$finish_cmds$finish_eval" && test -n "$libdirs"; then
+ echo "----------------------------------------------------------------------"
+ echo "Libraries have been installed in:"
+ for libdir in $libdirs; do
+ $ECHO " $libdir"
+ done
+ echo
+ echo "If you ever happen to want to link against installed libraries"
+ echo "in a given directory, LIBDIR, you must either use libtool, and"
+ echo "specify the full pathname of the library, or use the '-LLIBDIR'"
+ echo "flag during linking and do at least one of the following:"
+ if test -n "$shlibpath_var"; then
+ echo " - add LIBDIR to the '$shlibpath_var' environment variable"
+ echo " during execution"
+ fi
+ if test -n "$runpath_var"; then
+ echo " - add LIBDIR to the '$runpath_var' environment variable"
+ echo " during linking"
+ fi
+ if test -n "$hardcode_libdir_flag_spec"; then
+ libdir=LIBDIR
+ eval flag=\"$hardcode_libdir_flag_spec\"
+
+ $ECHO " - use the '$flag' linker flag"
+ fi
+ if test -n "$admincmds"; then
+ $ECHO " - have your system administrator run these commands:$admincmds"
+ fi
+ if test -f /etc/ld.so.conf; then
+ echo " - have your system administrator add LIBDIR to '/etc/ld.so.conf'"
+ fi
+ echo
+
+ echo "See any operating system documentation about shared libraries for"
+ case $host in
+ solaris2.[6789]|solaris2.1[0-9])
+ echo "more information, such as the ld(1), crle(1) and ld.so(8) manual"
+ echo "pages."
+ ;;
+ *)
+ echo "more information, such as the ld(1) and ld.so(8) manual pages."
+ ;;
+ esac
+ echo "----------------------------------------------------------------------"
+ fi
+ exit $EXIT_SUCCESS
+}
+
+test finish = "$opt_mode" && func_mode_finish ${1+"$@"}
+
+
+# func_mode_install arg...
+func_mode_install ()
+{
+ $debug_cmd
+
+ # There may be an optional sh(1) argument at the beginning of
+ # install_prog (especially on Windows NT).
+ if test "$SHELL" = "$nonopt" || test /bin/sh = "$nonopt" ||
+ # Allow the use of GNU shtool's install command.
+ case $nonopt in *shtool*) :;; *) false;; esac
+ then
+ # Aesthetically quote it.
+ func_quote_for_eval "$nonopt"
+ install_prog="$func_quote_for_eval_result "
+ arg=$1
+ shift
+ else
+ install_prog=
+ arg=$nonopt
+ fi
+
+ # The real first argument should be the name of the installation program.
+ # Aesthetically quote it.
+ func_quote_for_eval "$arg"
+ func_append install_prog "$func_quote_for_eval_result"
+ install_shared_prog=$install_prog
+ case " $install_prog " in
+ *[\\\ /]cp\ *) install_cp=: ;;
+ *) install_cp=false ;;
+ esac
+
+ # We need to accept at least all the BSD install flags.
+ dest=
+ files=
+ opts=
+ prev=
+ install_type=
+ isdir=false
+ stripme=
+ no_mode=:
+ for arg
+ do
+ arg2=
+ if test -n "$dest"; then
+ func_append files " $dest"
+ dest=$arg
+ continue
+ fi
+
+ case $arg in
+ -d) isdir=: ;;
+ -f)
+ if $install_cp; then :; else
+ prev=$arg
+ fi
+ ;;
+ -g | -m | -o)
+ prev=$arg
+ ;;
+ -s)
+ stripme=" -s"
+ continue
+ ;;
+ -*)
+ ;;
+ *)
+ # If the previous option needed an argument, then skip it.
+ if test -n "$prev"; then
+ if test X-m = "X$prev" && test -n "$install_override_mode"; then
+ arg2=$install_override_mode
+ no_mode=false
+ fi
+ prev=
+ else
+ dest=$arg
+ continue
+ fi
+ ;;
+ esac
+
+ # Aesthetically quote the argument.
+ func_quote_for_eval "$arg"
+ func_append install_prog " $func_quote_for_eval_result"
+ if test -n "$arg2"; then
+ func_quote_for_eval "$arg2"
+ fi
+ func_append install_shared_prog " $func_quote_for_eval_result"
+ done
+
+ test -z "$install_prog" && \
+ func_fatal_help "you must specify an install program"
+
+ test -n "$prev" && \
+ func_fatal_help "the '$prev' option requires an argument"
+
+ if test -n "$install_override_mode" && $no_mode; then
+ if $install_cp; then :; else
+ func_quote_for_eval "$install_override_mode"
+ func_append install_shared_prog " -m $func_quote_for_eval_result"
+ fi
+ fi
+
+ if test -z "$files"; then
+ if test -z "$dest"; then
+ func_fatal_help "no file or destination specified"
+ else
+ func_fatal_help "you must specify a destination"
+ fi
+ fi
+
+ # Strip any trailing slash from the destination.
+ func_stripname '' '/' "$dest"
+ dest=$func_stripname_result
+
+ # Check to see that the destination is a directory.
+ test -d "$dest" && isdir=:
+ if $isdir; then
+ destdir=$dest
+ destname=
+ else
+ func_dirname_and_basename "$dest" "" "."
+ destdir=$func_dirname_result
+ destname=$func_basename_result
+
+ # Not a directory, so check to see that there is only one file specified.
+ set dummy $files; shift
+ test "$#" -gt 1 && \
+ func_fatal_help "'$dest' is not a directory"
+ fi
+ case $destdir in
+ [\\/]* | [A-Za-z]:[\\/]*) ;;
+ *)
+ for file in $files; do
+ case $file in
+ *.lo) ;;
+ *)
+ func_fatal_help "'$destdir' must be an absolute directory name"
+ ;;
+ esac
+ done
+ ;;
+ esac
+
+ # This variable tells wrapper scripts just to set variables rather
+ # than running their programs.
+ libtool_install_magic=$magic
+
+ staticlibs=
+ future_libdirs=
+ current_libdirs=
+ for file in $files; do
+
+ # Do each installation.
+ case $file in
+ *.$libext)
+ # Do the static libraries later.
+ func_append staticlibs " $file"
+ ;;
+
+ *.la)
+ func_resolve_sysroot "$file"
+ file=$func_resolve_sysroot_result
+
+ # Check to see that this really is a libtool archive.
+ func_lalib_unsafe_p "$file" \
+ || func_fatal_help "'$file' is not a valid libtool archive"
+
+ library_names=
+ old_library=
+ relink_command=
+ func_source "$file"
+
+ # Add the libdir to current_libdirs if it is the destination.
+ if test "X$destdir" = "X$libdir"; then
+ case "$current_libdirs " in
+ *" $libdir "*) ;;
+ *) func_append current_libdirs " $libdir" ;;
+ esac
+ else
+ # Note the libdir as a future libdir.
+ case "$future_libdirs " in
+ *" $libdir "*) ;;
+ *) func_append future_libdirs " $libdir" ;;
+ esac
+ fi
+
+ func_dirname "$file" "/" ""
+ dir=$func_dirname_result
+ func_append dir "$objdir"
+
+ if test -n "$relink_command"; then
+ # Determine the prefix the user has applied to our future dir.
+ inst_prefix_dir=`$ECHO "$destdir" | $SED -e "s%$libdir\$%%"`
+
+ # Don't allow the user to place us outside of our expected
+ # location b/c this prevents finding dependent libraries that
+ # are installed to the same prefix.
+ # At present, this check doesn't affect windows .dll's that
+ # are installed into $libdir/../bin (currently, that works fine)
+ # but it's something to keep an eye on.
+ test "$inst_prefix_dir" = "$destdir" && \
+ func_fatal_error "error: cannot install '$file' to a directory not ending in $libdir"
+
+ if test -n "$inst_prefix_dir"; then
+ # Stick the inst_prefix_dir data into the link command.
+ relink_command=`$ECHO "$relink_command" | $SED "s%@inst_prefix_dir@%-inst-prefix-dir $inst_prefix_dir%"`
+ else
+ relink_command=`$ECHO "$relink_command" | $SED "s%@inst_prefix_dir@%%"`
+ fi
+
+ func_warning "relinking '$file'"
+ func_show_eval "$relink_command" \
+ 'func_fatal_error "error: relink '\''$file'\'' with the above command before installing it"'
+ fi
+
+ # See the names of the shared library.
+ set dummy $library_names; shift
+ if test -n "$1"; then
+ realname=$1
+ shift
+
+ srcname=$realname
+ test -n "$relink_command" && srcname=${realname}T
+
+ # Install the shared library and build the symlinks.
+ func_show_eval "$install_shared_prog $dir/$srcname $destdir/$realname" \
+ 'exit $?'
+ tstripme=$stripme
+ case $host_os in
+ cygwin* | mingw* | pw32* | cegcc*)
+ case $realname in
+ *.dll.a)
+ tstripme=
+ ;;
+ esac
+ ;;
+ os2*)
+ case $realname in
+ *_dll.a)
+ tstripme=
+ ;;
+ esac
+ ;;
+ esac
+ if test -n "$tstripme" && test -n "$striplib"; then
+ func_show_eval "$striplib $destdir/$realname" 'exit $?'
+ fi
+
+ if test "$#" -gt 0; then
+ # Delete the old symlinks, and create new ones.
+ # Try 'ln -sf' first, because the 'ln' binary might depend on
+ # the symlink we replace! Solaris /bin/ln does not understand -f,
+ # so we also need to try rm && ln -s.
+ for linkname
+ do
+ test "$linkname" != "$realname" \
+ && func_show_eval "(cd $destdir && { $LN_S -f $realname $linkname || { $RM $linkname && $LN_S $realname $linkname; }; })"
+ done
+ fi
+
+ # Do each command in the postinstall commands.
+ lib=$destdir/$realname
+ func_execute_cmds "$postinstall_cmds" 'exit $?'
+ fi
+
+ # Install the pseudo-library for information purposes.
+ func_basename "$file"
+ name=$func_basename_result
+ instname=$dir/${name}i
+ func_show_eval "$install_prog $instname $destdir/$name" 'exit $?'
+
+ # Maybe install the static library, too.
+ test -n "$old_library" && func_append staticlibs " $dir/$old_library"
+ ;;
+
+ *.lo)
+ # Install (i.e. copy) a libtool object.
+
+ # Figure out destination file name, if it wasn't already specified.
+ if test -n "$destname"; then
+ destfile=$destdir/$destname
+ else
+ func_basename "$file"
+ destfile=$func_basename_result
+ destfile=$destdir/$destfile
+ fi
+
+ # Deduce the name of the destination old-style object file.
+ case $destfile in
+ *.lo)
+ func_lo2o "$destfile"
+ staticdest=$func_lo2o_result
+ ;;
+ *.$objext)
+ staticdest=$destfile
+ destfile=
+ ;;
+ *)
+ func_fatal_help "cannot copy a libtool object to '$destfile'"
+ ;;
+ esac
+
+ # Install the libtool object if requested.
+ test -n "$destfile" && \
+ func_show_eval "$install_prog $file $destfile" 'exit $?'
+
+ # Install the old object if enabled.
+ if test yes = "$build_old_libs"; then
+ # Deduce the name of the old-style object file.
+ func_lo2o "$file"
+ staticobj=$func_lo2o_result
+ func_show_eval "$install_prog \$staticobj \$staticdest" 'exit $?'
+ fi
+ exit $EXIT_SUCCESS
+ ;;
+
+ *)
+ # Figure out destination file name, if it wasn't already specified.
+ if test -n "$destname"; then
+ destfile=$destdir/$destname
+ else
+ func_basename "$file"
+ destfile=$func_basename_result
+ destfile=$destdir/$destfile
+ fi
+
+ # If the file is missing, and there is a .exe on the end, strip it
+ # because it is most likely a libtool script we actually want to
+ # install
+ stripped_ext=
+ case $file in
+ *.exe)
+ if test ! -f "$file"; then
+ func_stripname '' '.exe' "$file"
+ file=$func_stripname_result
+ stripped_ext=.exe
+ fi
+ ;;
+ esac
+
+ # Do a test to see if this is really a libtool program.
+ case $host in
+ *cygwin* | *mingw*)
+ if func_ltwrapper_executable_p "$file"; then
+ func_ltwrapper_scriptname "$file"
+ wrapper=$func_ltwrapper_scriptname_result
+ else
+ func_stripname '' '.exe' "$file"
+ wrapper=$func_stripname_result
+ fi
+ ;;
+ *)
+ wrapper=$file
+ ;;
+ esac
+ if func_ltwrapper_script_p "$wrapper"; then
+ notinst_deplibs=
+ relink_command=
+
+ func_source "$wrapper"
+
+ # Check the variables that should have been set.
+ test -z "$generated_by_libtool_version" && \
+ func_fatal_error "invalid libtool wrapper script '$wrapper'"
+
+ finalize=:
+ for lib in $notinst_deplibs; do
+ # Check to see that each library is installed.
+ libdir=
+ if test -f "$lib"; then
+ func_source "$lib"
+ fi
+ libfile=$libdir/`$ECHO "$lib" | $SED 's%^.*/%%g'`
+ if test -n "$libdir" && test ! -f "$libfile"; then
+ func_warning "'$lib' has not been installed in '$libdir'"
+ finalize=false
+ fi
+ done
+
+ relink_command=
+ func_source "$wrapper"
+
+ outputname=
+ if test no = "$fast_install" && test -n "$relink_command"; then
+ $opt_dry_run || {
+ if $finalize; then
+ tmpdir=`func_mktempdir`
+ func_basename "$file$stripped_ext"
+ file=$func_basename_result
+ outputname=$tmpdir/$file
+ # Replace the output file specification.
+ relink_command=`$ECHO "$relink_command" | $SED 's%@OUTPUT@%'"$outputname"'%g'`
+
+ $opt_quiet || {
+ func_quote_for_expand "$relink_command"
+ eval "func_echo $func_quote_for_expand_result"
+ }
+ if eval "$relink_command"; then :
+ else
+ func_error "error: relink '$file' with the above command before installing it"
+ $opt_dry_run || ${RM}r "$tmpdir"
+ continue
+ fi
+ file=$outputname
+ else
+ func_warning "cannot relink '$file'"
+ fi
+ }
+ else
+ # Install the binary that we compiled earlier.
+ file=`$ECHO "$file$stripped_ext" | $SED "s%\([^/]*\)$%$objdir/\1%"`
+ fi
+ fi
+
+ # remove .exe since cygwin /usr/bin/install will append another
+ # one anyway
+ case $install_prog,$host in
+ */usr/bin/install*,*cygwin*)
+ case $file:$destfile in
+ *.exe:*.exe)
+ # this is ok
+ ;;
+ *.exe:*)
+ destfile=$destfile.exe
+ ;;
+ *:*.exe)
+ func_stripname '' '.exe' "$destfile"
+ destfile=$func_stripname_result
+ ;;
+ esac
+ ;;
+ esac
+ func_show_eval "$install_prog\$stripme \$file \$destfile" 'exit $?'
+ $opt_dry_run || if test -n "$outputname"; then
+ ${RM}r "$tmpdir"
+ fi
+ ;;
+ esac
+ done
+
+ for file in $staticlibs; do
+ func_basename "$file"
+ name=$func_basename_result
+
+ # Set up the ranlib parameters.
+ oldlib=$destdir/$name
+ func_to_tool_file "$oldlib" func_convert_file_msys_to_w32
+ tool_oldlib=$func_to_tool_file_result
+
+ func_show_eval "$install_prog \$file \$oldlib" 'exit $?'
+
+ if test -n "$stripme" && test -n "$old_striplib"; then
+ func_show_eval "$old_striplib $tool_oldlib" 'exit $?'
+ fi
+
+ # Do each command in the postinstall commands.
+ func_execute_cmds "$old_postinstall_cmds" 'exit $?'
+ done
+
+ test -n "$future_libdirs" && \
+ func_warning "remember to run '$progname --finish$future_libdirs'"
+
+ if test -n "$current_libdirs"; then
+ # Maybe just do a dry run.
+ $opt_dry_run && current_libdirs=" -n$current_libdirs"
+ exec_cmd='$SHELL "$progpath" $preserve_args --finish$current_libdirs'
+ else
+ exit $EXIT_SUCCESS
+ fi
+}
+
+test install = "$opt_mode" && func_mode_install ${1+"$@"}
+
+
+# func_generate_dlsyms outputname originator pic_p
+# Extract symbols from dlprefiles and create ${outputname}S.o with
+# a dlpreopen symbol table.
+func_generate_dlsyms ()
+{
+ $debug_cmd
+
+ my_outputname=$1
+ my_originator=$2
+ my_pic_p=${3-false}
+ my_prefix=`$ECHO "$my_originator" | $SED 's%[^a-zA-Z0-9]%_%g'`
+ my_dlsyms=
+
+ if test -n "$dlfiles$dlprefiles" || test no != "$dlself"; then
+ if test -n "$NM" && test -n "$global_symbol_pipe"; then
+ my_dlsyms=${my_outputname}S.c
+ else
+ func_error "not configured to extract global symbols from dlpreopened files"
+ fi
+ fi
+
+ if test -n "$my_dlsyms"; then
+ case $my_dlsyms in
+ "") ;;
+ *.c)
+ # Discover the nlist of each of the dlfiles.
+ nlist=$output_objdir/$my_outputname.nm
+
+ func_show_eval "$RM $nlist ${nlist}S ${nlist}T"
+
+ # Parse the name list into a source file.
+ func_verbose "creating $output_objdir/$my_dlsyms"
+
+ $opt_dry_run || $ECHO > "$output_objdir/$my_dlsyms" "\
+/* $my_dlsyms - symbol resolution table for '$my_outputname' dlsym emulation. */
+/* Generated by $PROGRAM (GNU $PACKAGE) $VERSION */
+
+#ifdef __cplusplus
+extern \"C\" {
+#endif
+
+#if defined __GNUC__ && (((__GNUC__ == 4) && (__GNUC_MINOR__ >= 4)) || (__GNUC__ > 4))
+#pragma GCC diagnostic ignored \"-Wstrict-prototypes\"
+#endif
+
+/* Keep this code in sync between libtool.m4, ltmain, lt_system.h, and tests. */
+#if defined _WIN32 || defined __CYGWIN__ || defined _WIN32_WCE
+/* DATA imports from DLLs on WIN32 can't be const, because runtime
+ relocations are performed -- see ld's documentation on pseudo-relocs. */
+# define LT_DLSYM_CONST
+#elif defined __osf__
+/* This system does not cope well with relocations in const data. */
+# define LT_DLSYM_CONST
+#else
+# define LT_DLSYM_CONST const
+#endif
+
+#define STREQ(s1, s2) (strcmp ((s1), (s2)) == 0)
+
+/* External symbol declarations for the compiler. */\
+"
+
+ if test yes = "$dlself"; then
+ func_verbose "generating symbol list for '$output'"
+
+ $opt_dry_run || echo ': @PROGRAM@ ' > "$nlist"
+
+ # Add our own program objects to the symbol list.
+ progfiles=`$ECHO "$objs$old_deplibs" | $SP2NL | $SED "$lo2o" | $NL2SP`
+ for progfile in $progfiles; do
+ func_to_tool_file "$progfile" func_convert_file_msys_to_w32
+ func_verbose "extracting global C symbols from '$func_to_tool_file_result'"
+ $opt_dry_run || eval "$NM $func_to_tool_file_result | $global_symbol_pipe >> '$nlist'"
+ done
+
+ if test -n "$exclude_expsyms"; then
+ $opt_dry_run || {
+ eval '$EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T'
+ eval '$MV "$nlist"T "$nlist"'
+ }
+ fi
+
+ if test -n "$export_symbols_regex"; then
+ $opt_dry_run || {
+ eval '$EGREP -e "$export_symbols_regex" "$nlist" > "$nlist"T'
+ eval '$MV "$nlist"T "$nlist"'
+ }
+ fi
+
+ # Prepare the list of exported symbols
+ if test -z "$export_symbols"; then
+ export_symbols=$output_objdir/$outputname.exp
+ $opt_dry_run || {
+ $RM $export_symbols
+ eval "$SED -n -e '/^: @PROGRAM@ $/d' -e 's/^.* \(.*\)$/\1/p' "'< "$nlist" > "$export_symbols"'
+ case $host in
+ *cygwin* | *mingw* | *cegcc* )
+ eval "echo EXPORTS "'> "$output_objdir/$outputname.def"'
+ eval 'cat "$export_symbols" >> "$output_objdir/$outputname.def"'
+ ;;
+ esac
+ }
+ else
+ $opt_dry_run || {
+ eval "$SED -e 's/\([].[*^$]\)/\\\\\1/g' -e 's/^/ /' -e 's/$/$/'"' < "$export_symbols" > "$output_objdir/$outputname.exp"'
+ eval '$GREP -f "$output_objdir/$outputname.exp" < "$nlist" > "$nlist"T'
+ eval '$MV "$nlist"T "$nlist"'
+ case $host in
+ *cygwin* | *mingw* | *cegcc* )
+ eval "echo EXPORTS "'> "$output_objdir/$outputname.def"'
+ eval 'cat "$nlist" >> "$output_objdir/$outputname.def"'
+ ;;
+ esac
+ }
+ fi
+ fi
+
+ for dlprefile in $dlprefiles; do
+ func_verbose "extracting global C symbols from '$dlprefile'"
+ func_basename "$dlprefile"
+ name=$func_basename_result
+ case $host in
+ *cygwin* | *mingw* | *cegcc* )
+ # if an import library, we need to obtain dlname
+ if func_win32_import_lib_p "$dlprefile"; then
+ func_tr_sh "$dlprefile"
+ eval "curr_lafile=\$libfile_$func_tr_sh_result"
+ dlprefile_dlbasename=
+ if test -n "$curr_lafile" && func_lalib_p "$curr_lafile"; then
+ # Use subshell, to avoid clobbering current variable values
+ dlprefile_dlname=`source "$curr_lafile" && echo "$dlname"`
+ if test -n "$dlprefile_dlname"; then
+ func_basename "$dlprefile_dlname"
+ dlprefile_dlbasename=$func_basename_result
+ else
+ # no lafile. user explicitly requested -dlpreopen <import library>.
+ $sharedlib_from_linklib_cmd "$dlprefile"
+ dlprefile_dlbasename=$sharedlib_from_linklib_result
+ fi
+ fi
+ $opt_dry_run || {
+ if test -n "$dlprefile_dlbasename"; then
+ eval '$ECHO ": $dlprefile_dlbasename" >> "$nlist"'
+ else
+ func_warning "Could not compute DLL name from $name"
+ eval '$ECHO ": $name " >> "$nlist"'
+ fi
+ func_to_tool_file "$dlprefile" func_convert_file_msys_to_w32
+ eval "$NM \"$func_to_tool_file_result\" 2>/dev/null | $global_symbol_pipe |
+ $SED -e '/I __imp/d' -e 's/I __nm_/D /;s/_nm__//' >> '$nlist'"
+ }
+ else # not an import lib
+ $opt_dry_run || {
+ eval '$ECHO ": $name " >> "$nlist"'
+ func_to_tool_file "$dlprefile" func_convert_file_msys_to_w32
+ eval "$NM \"$func_to_tool_file_result\" 2>/dev/null | $global_symbol_pipe >> '$nlist'"
+ }
+ fi
+ ;;
+ *)
+ $opt_dry_run || {
+ eval '$ECHO ": $name " >> "$nlist"'
+ func_to_tool_file "$dlprefile" func_convert_file_msys_to_w32
+ eval "$NM \"$func_to_tool_file_result\" 2>/dev/null | $global_symbol_pipe >> '$nlist'"
+ }
+ ;;
+ esac
+ done
+
+ $opt_dry_run || {
+ # Make sure we have at least an empty file.
+ test -f "$nlist" || : > "$nlist"
+
+ if test -n "$exclude_expsyms"; then
+ $EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T
+ $MV "$nlist"T "$nlist"
+ fi
+
+ # Try sorting and uniquifying the output.
+ if $GREP -v "^: " < "$nlist" |
+ if sort -k 3 </dev/null >/dev/null 2>&1; then
+ sort -k 3
+ else
+ sort +2
+ fi |
+ uniq > "$nlist"S; then
+ :
+ else
+ $GREP -v "^: " < "$nlist" > "$nlist"S
+ fi
+
+ if test -f "$nlist"S; then
+ eval "$global_symbol_to_cdecl"' < "$nlist"S >> "$output_objdir/$my_dlsyms"'
+ else
+ echo '/* NONE */' >> "$output_objdir/$my_dlsyms"
+ fi
+
+ func_show_eval '$RM "${nlist}I"'
+ if test -n "$global_symbol_to_import"; then
+ eval "$global_symbol_to_import"' < "$nlist"S > "$nlist"I'
+ fi
+
+ echo >> "$output_objdir/$my_dlsyms" "\
+
+/* The mapping between symbol names and symbols. */
+typedef struct {
+ const char *name;
+ void *address;
+} lt_dlsymlist;
+extern LT_DLSYM_CONST lt_dlsymlist
+lt_${my_prefix}_LTX_preloaded_symbols[];\
+"
+
+ if test -s "$nlist"I; then
+ echo >> "$output_objdir/$my_dlsyms" "\
+static void lt_syminit(void)
+{
+ LT_DLSYM_CONST lt_dlsymlist *symbol = lt_${my_prefix}_LTX_preloaded_symbols;
+ for (; symbol->name; ++symbol)
+ {"
+ $SED 's/.*/ if (STREQ (symbol->name, \"&\")) symbol->address = (void *) \&&;/' < "$nlist"I >> "$output_objdir/$my_dlsyms"
+ echo >> "$output_objdir/$my_dlsyms" "\
+ }
+}"
+ fi
+ echo >> "$output_objdir/$my_dlsyms" "\
+LT_DLSYM_CONST lt_dlsymlist
+lt_${my_prefix}_LTX_preloaded_symbols[] =
+{ {\"$my_originator\", (void *) 0},"
+
+ if test -s "$nlist"I; then
+ echo >> "$output_objdir/$my_dlsyms" "\
+ {\"@INIT@\", (void *) &lt_syminit},"
+ fi
+
+ case $need_lib_prefix in
+ no)
+ eval "$global_symbol_to_c_name_address" < "$nlist" >> "$output_objdir/$my_dlsyms"
+ ;;
+ *)
+ eval "$global_symbol_to_c_name_address_lib_prefix" < "$nlist" >> "$output_objdir/$my_dlsyms"
+ ;;
+ esac
+ echo >> "$output_objdir/$my_dlsyms" "\
+ {0, (void *) 0}
+};
+
+/* This works around a problem in FreeBSD linker */
+#ifdef FREEBSD_WORKAROUND
+static const void *lt_preloaded_setup() {
+ return lt_${my_prefix}_LTX_preloaded_symbols;
+}
+#endif
+
+#ifdef __cplusplus
+}
+#endif\
+"
+ } # !$opt_dry_run
+
+ pic_flag_for_symtable=
+ case "$compile_command " in
+ *" -static "*) ;;
+ *)
+ case $host in
+ # compiling the symbol table file with pic_flag works around
+ # a FreeBSD bug that causes programs to crash when -lm is
+ # linked before any other PIC object. But we must not use
+ # pic_flag when linking with -static. The problem exists in
+ # FreeBSD 2.2.6 and is fixed in FreeBSD 3.1.
+ *-*-freebsd2.*|*-*-freebsd3.0*|*-*-freebsdelf3.0*)
+ pic_flag_for_symtable=" $pic_flag -DFREEBSD_WORKAROUND" ;;
+ *-*-hpux*)
+ pic_flag_for_symtable=" $pic_flag" ;;
+ *)
+ $my_pic_p && pic_flag_for_symtable=" $pic_flag"
+ ;;
+ esac
+ ;;
+ esac
+ symtab_cflags=
+ for arg in $LTCFLAGS; do
+ case $arg in
+ -pie | -fpie | -fPIE) ;;
+ *) func_append symtab_cflags " $arg" ;;
+ esac
+ done
+
+ # Now compile the dynamic symbol file.
+ func_show_eval '(cd $output_objdir && $LTCC$symtab_cflags -c$no_builtin_flag$pic_flag_for_symtable "$my_dlsyms")' 'exit $?'
+
+ # Clean up the generated files.
+ func_show_eval '$RM "$output_objdir/$my_dlsyms" "$nlist" "${nlist}S" "${nlist}T" "${nlist}I"'
+
+ # Transform the symbol file into the correct name.
+ symfileobj=$output_objdir/${my_outputname}S.$objext
+ case $host in
+ *cygwin* | *mingw* | *cegcc* )
+ if test -f "$output_objdir/$my_outputname.def"; then
+ compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$output_objdir/$my_outputname.def $symfileobj%"`
+ finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$output_objdir/$my_outputname.def $symfileobj%"`
+ else
+ compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$symfileobj%"`
+ finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$symfileobj%"`
+ fi
+ ;;
+ *)
+ compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$symfileobj%"`
+ finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$symfileobj%"`
+ ;;
+ esac
+ ;;
+ *)
+ func_fatal_error "unknown suffix for '$my_dlsyms'"
+ ;;
+ esac
+ else
+ # We keep going just in case the user didn't refer to
+ # lt_preloaded_symbols. The linker will fail if global_symbol_pipe
+ # really was required.
+
+ # Nullify the symbol file.
+ compile_command=`$ECHO "$compile_command" | $SED "s% @SYMFILE@%%"`
+ finalize_command=`$ECHO "$finalize_command" | $SED "s% @SYMFILE@%%"`
+ fi
+}
+
+# func_cygming_gnu_implib_p ARG
+# This predicate returns with zero status (TRUE) if
+# ARG is a GNU/binutils-style import library. Returns
+# with nonzero status (FALSE) otherwise.
+func_cygming_gnu_implib_p ()
+{
+ $debug_cmd
+
+ func_to_tool_file "$1" func_convert_file_msys_to_w32
+ func_cygming_gnu_implib_tmp=`$NM "$func_to_tool_file_result" | eval "$global_symbol_pipe" | $EGREP ' (_head_[A-Za-z0-9_]+_[ad]l*|[A-Za-z0-9_]+_[ad]l*_iname)$'`
+ test -n "$func_cygming_gnu_implib_tmp"
+}
+
+# func_cygming_ms_implib_p ARG
+# This predicate returns with zero status (TRUE) if
+# ARG is an MS-style import library. Returns
+# with nonzero status (FALSE) otherwise.
+func_cygming_ms_implib_p ()
+{
+ $debug_cmd
+
+ func_to_tool_file "$1" func_convert_file_msys_to_w32
+ func_cygming_ms_implib_tmp=`$NM "$func_to_tool_file_result" | eval "$global_symbol_pipe" | $GREP '_NULL_IMPORT_DESCRIPTOR'`
+ test -n "$func_cygming_ms_implib_tmp"
+}
+
+# func_win32_libid arg
+# return the library type of file 'arg'
+#
+# Need a lot of goo to handle *both* DLLs and import libs
+# Has to be a shell function in order to 'eat' the argument
+# that is supplied when $file_magic_command is called.
+# Despite the name, also deal with 64 bit binaries.
+func_win32_libid ()
+{
+ $debug_cmd
+
+ win32_libid_type=unknown
+ win32_fileres=`file -L $1 2>/dev/null`
+ case $win32_fileres in
+ *ar\ archive\ import\ library*) # definitely import
+ win32_libid_type="x86 archive import"
+ ;;
+ *ar\ archive*) # could be an import, or static
+ # Keep the egrep pattern in sync with the one in _LT_CHECK_MAGIC_METHOD.
+ if eval $OBJDUMP -f $1 | $SED -e '10q' 2>/dev/null |
+ $EGREP 'file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64)' >/dev/null; then
+ case $nm_interface in
+ "MS dumpbin")
+ if func_cygming_ms_implib_p "$1" ||
+ func_cygming_gnu_implib_p "$1"
+ then
+ win32_nmres=import
+ else
+ win32_nmres=
+ fi
+ ;;
+ *)
+ func_to_tool_file "$1" func_convert_file_msys_to_w32
+ win32_nmres=`eval $NM -f posix -A \"$func_to_tool_file_result\" |
+ $SED -n -e '
+ 1,100{
+ / I /{
+ s|.*|import|
+ p
+ q
+ }
+ }'`
+ ;;
+ esac
+ case $win32_nmres in
+ import*) win32_libid_type="x86 archive import";;
+ *) win32_libid_type="x86 archive static";;
+ esac
+ fi
+ ;;
+ *DLL*)
+ win32_libid_type="x86 DLL"
+ ;;
+ *executable*) # but shell scripts are "executable" too...
+ case $win32_fileres in
+ *MS\ Windows\ PE\ Intel*)
+ win32_libid_type="x86 DLL"
+ ;;
+ esac
+ ;;
+ esac
+ $ECHO "$win32_libid_type"
+}
+
+# func_cygming_dll_for_implib ARG
+#
+# Platform-specific function to extract the
+# name of the DLL associated with the specified
+# import library ARG.
+# Invoked by eval'ing the libtool variable
+# $sharedlib_from_linklib_cmd
+# Result is available in the variable
+# $sharedlib_from_linklib_result
+func_cygming_dll_for_implib ()
+{
+ $debug_cmd
+
+ sharedlib_from_linklib_result=`$DLLTOOL --identify-strict --identify "$1"`
+}
+
+# func_cygming_dll_for_implib_fallback_core SECTION_NAME LIBNAMEs
+#
+# The is the core of a fallback implementation of a
+# platform-specific function to extract the name of the
+# DLL associated with the specified import library LIBNAME.
+#
+# SECTION_NAME is either .idata$6 or .idata$7, depending
+# on the platform and compiler that created the implib.
+#
+# Echos the name of the DLL associated with the
+# specified import library.
+func_cygming_dll_for_implib_fallback_core ()
+{
+ $debug_cmd
+
+ match_literal=`$ECHO "$1" | $SED "$sed_make_literal_regex"`
+ $OBJDUMP -s --section "$1" "$2" 2>/dev/null |
+ $SED '/^Contents of section '"$match_literal"':/{
+ # Place marker at beginning of archive member dllname section
+ s/.*/====MARK====/
+ p
+ d
+ }
+ # These lines can sometimes be longer than 43 characters, but
+ # are always uninteresting
+ /:[ ]*file format pe[i]\{,1\}-/d
+ /^In archive [^:]*:/d
+ # Ensure marker is printed
+ /^====MARK====/p
+ # Remove all lines with less than 43 characters
+ /^.\{43\}/!d
+ # From remaining lines, remove first 43 characters
+ s/^.\{43\}//' |
+ $SED -n '
+ # Join marker and all lines until next marker into a single line
+ /^====MARK====/ b para
+ H
+ $ b para
+ b
+ :para
+ x
+ s/\n//g
+ # Remove the marker
+ s/^====MARK====//
+ # Remove trailing dots and whitespace
+ s/[\. \t]*$//
+ # Print
+ /./p' |
+ # we now have a list, one entry per line, of the stringified
+ # contents of the appropriate section of all members of the
+ # archive that possess that section. Heuristic: eliminate
+ # all those that have a first or second character that is
+ # a '.' (that is, objdump's representation of an unprintable
+ # character.) This should work for all archives with less than
+ # 0x302f exports -- but will fail for DLLs whose name actually
+ # begins with a literal '.' or a single character followed by
+ # a '.'.
+ #
+ # Of those that remain, print the first one.
+ $SED -e '/^\./d;/^.\./d;q'
+}
+
+# func_cygming_dll_for_implib_fallback ARG
+# Platform-specific function to extract the
+# name of the DLL associated with the specified
+# import library ARG.
+#
+# This fallback implementation is for use when $DLLTOOL
+# does not support the --identify-strict option.
+# Invoked by eval'ing the libtool variable
+# $sharedlib_from_linklib_cmd
+# Result is available in the variable
+# $sharedlib_from_linklib_result
+func_cygming_dll_for_implib_fallback ()
+{
+ $debug_cmd
+
+ if func_cygming_gnu_implib_p "$1"; then
+ # binutils import library
+ sharedlib_from_linklib_result=`func_cygming_dll_for_implib_fallback_core '.idata$7' "$1"`
+ elif func_cygming_ms_implib_p "$1"; then
+ # ms-generated import library
+ sharedlib_from_linklib_result=`func_cygming_dll_for_implib_fallback_core '.idata$6' "$1"`
+ else
+ # unknown
+ sharedlib_from_linklib_result=
+ fi
+}
+
+
+# func_extract_an_archive dir oldlib
+func_extract_an_archive ()
+{
+ $debug_cmd
+
+ f_ex_an_ar_dir=$1; shift
+ f_ex_an_ar_oldlib=$1
+ if test yes = "$lock_old_archive_extraction"; then
+ lockfile=$f_ex_an_ar_oldlib.lock
+ until $opt_dry_run || ln "$progpath" "$lockfile" 2>/dev/null; do
+ func_echo "Waiting for $lockfile to be removed"
+ sleep 2
+ done
+ fi
+ func_show_eval "(cd \$f_ex_an_ar_dir && $AR x \"\$f_ex_an_ar_oldlib\")" \
+ 'stat=$?; rm -f "$lockfile"; exit $stat'
+ if test yes = "$lock_old_archive_extraction"; then
+ $opt_dry_run || rm -f "$lockfile"
+ fi
+ if ($AR t "$f_ex_an_ar_oldlib" | sort | sort -uc >/dev/null 2>&1); then
+ :
+ else
+ func_fatal_error "object name conflicts in archive: $f_ex_an_ar_dir/$f_ex_an_ar_oldlib"
+ fi
+}
+
+
+# func_extract_archives gentop oldlib ...
+func_extract_archives ()
+{
+ $debug_cmd
+
+ my_gentop=$1; shift
+ my_oldlibs=${1+"$@"}
+ my_oldobjs=
+ my_xlib=
+ my_xabs=
+ my_xdir=
+
+ for my_xlib in $my_oldlibs; do
+ # Extract the objects.
+ case $my_xlib in
+ [\\/]* | [A-Za-z]:[\\/]*) my_xabs=$my_xlib ;;
+ *) my_xabs=`pwd`"/$my_xlib" ;;
+ esac
+ func_basename "$my_xlib"
+ my_xlib=$func_basename_result
+ my_xlib_u=$my_xlib
+ while :; do
+ case " $extracted_archives " in
+ *" $my_xlib_u "*)
+ func_arith $extracted_serial + 1
+ extracted_serial=$func_arith_result
+ my_xlib_u=lt$extracted_serial-$my_xlib ;;
+ *) break ;;
+ esac
+ done
+ extracted_archives="$extracted_archives $my_xlib_u"
+ my_xdir=$my_gentop/$my_xlib_u
+
+ func_mkdir_p "$my_xdir"
+
+ case $host in
+ *-darwin*)
+ func_verbose "Extracting $my_xabs"
+ # Do not bother doing anything if just a dry run
+ $opt_dry_run || {
+ darwin_orig_dir=`pwd`
+ cd $my_xdir || exit $?
+ darwin_archive=$my_xabs
+ darwin_curdir=`pwd`
+ func_basename "$darwin_archive"
+ darwin_base_archive=$func_basename_result
+ darwin_arches=`$LIPO -info "$darwin_archive" 2>/dev/null | $GREP Architectures 2>/dev/null || true`
+ if test -n "$darwin_arches"; then
+ darwin_arches=`$ECHO "$darwin_arches" | $SED -e 's/.*are://'`
+ darwin_arch=
+ func_verbose "$darwin_base_archive has multiple architectures $darwin_arches"
+ for darwin_arch in $darwin_arches; do
+ func_mkdir_p "unfat-$$/$darwin_base_archive-$darwin_arch"
+ $LIPO -thin $darwin_arch -output "unfat-$$/$darwin_base_archive-$darwin_arch/$darwin_base_archive" "$darwin_archive"
+ cd "unfat-$$/$darwin_base_archive-$darwin_arch"
+ func_extract_an_archive "`pwd`" "$darwin_base_archive"
+ cd "$darwin_curdir"
+ $RM "unfat-$$/$darwin_base_archive-$darwin_arch/$darwin_base_archive"
+ done # $darwin_arches
+ ## Okay now we've a bunch of thin objects, gotta fatten them up :)
+ darwin_filelist=`find unfat-$$ -type f -name \*.o -print -o -name \*.lo -print | $SED -e "$sed_basename" | sort -u`
+ darwin_file=
+ darwin_files=
+ for darwin_file in $darwin_filelist; do
+ darwin_files=`find unfat-$$ -name $darwin_file -print | sort | $NL2SP`
+ $LIPO -create -output "$darwin_file" $darwin_files
+ done # $darwin_filelist
+ $RM -rf unfat-$$
+ cd "$darwin_orig_dir"
+ else
+ cd $darwin_orig_dir
+ func_extract_an_archive "$my_xdir" "$my_xabs"
+ fi # $darwin_arches
+ } # !$opt_dry_run
+ ;;
+ *)
+ func_extract_an_archive "$my_xdir" "$my_xabs"
+ ;;
+ esac
+ my_oldobjs="$my_oldobjs "`find $my_xdir -name \*.$objext -print -o -name \*.lo -print | sort | $NL2SP`
+ done
+
+ func_extract_archives_result=$my_oldobjs
+}
+
+
+# func_emit_wrapper [arg=no]
+#
+# Emit a libtool wrapper script on stdout.
+# Don't directly open a file because we may want to
+# incorporate the script contents within a cygwin/mingw
+# wrapper executable. Must ONLY be called from within
+# func_mode_link because it depends on a number of variables
+# set therein.
+#
+# ARG is the value that the WRAPPER_SCRIPT_BELONGS_IN_OBJDIR
+# variable will take. If 'yes', then the emitted script
+# will assume that the directory where it is stored is
+# the $objdir directory. This is a cygwin/mingw-specific
+# behavior.
+func_emit_wrapper ()
+{
+ func_emit_wrapper_arg1=${1-no}
+
+ $ECHO "\
+#! $SHELL
+
+# $output - temporary wrapper script for $objdir/$outputname
+# Generated by $PROGRAM (GNU $PACKAGE) $VERSION
+#
+# The $output program cannot be directly executed until all the libtool
+# libraries that it depends on are installed.
+#
+# This wrapper script should never be moved out of the build directory.
+# If it is, it will not operate correctly.
+
+# Sed substitution that helps us do robust quoting. It backslashifies
+# metacharacters that are still active within double-quoted strings.
+sed_quote_subst='$sed_quote_subst'
+
+# Be Bourne compatible
+if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then
+ emulate sh
+ NULLCMD=:
+ # Zsh 3.x and 4.x performs word splitting on \${1+\"\$@\"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '\${1+\"\$@\"}'='\"\$@\"'
+ setopt NO_GLOB_SUBST
+else
+ case \`(set -o) 2>/dev/null\` in *posix*) set -o posix;; esac
+fi
+BIN_SH=xpg4; export BIN_SH # for Tru64
+DUALCASE=1; export DUALCASE # for MKS sh
+
+# The HP-UX ksh and POSIX shell print the target directory to stdout
+# if CDPATH is set.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+relink_command=\"$relink_command\"
+
+# This environment variable determines our operation mode.
+if test \"\$libtool_install_magic\" = \"$magic\"; then
+ # install mode needs the following variables:
+ generated_by_libtool_version='$macro_version'
+ notinst_deplibs='$notinst_deplibs'
+else
+ # When we are sourced in execute mode, \$file and \$ECHO are already set.
+ if test \"\$libtool_execute_magic\" != \"$magic\"; then
+ file=\"\$0\""
+
+ qECHO=`$ECHO "$ECHO" | $SED "$sed_quote_subst"`
+ $ECHO "\
+
+# A function that is used when there is no print builtin or printf.
+func_fallback_echo ()
+{
+ eval 'cat <<_LTECHO_EOF
+\$1
+_LTECHO_EOF'
+}
+ ECHO=\"$qECHO\"
+ fi
+
+# Very basic option parsing. These options are (a) specific to
+# the libtool wrapper, (b) are identical between the wrapper
+# /script/ and the wrapper /executable/ that is used only on
+# windows platforms, and (c) all begin with the string "--lt-"
+# (application programs are unlikely to have options that match
+# this pattern).
+#
+# There are only two supported options: --lt-debug and
+# --lt-dump-script. There is, deliberately, no --lt-help.
+#
+# The first argument to this parsing function should be the
+# script's $0 value, followed by "$@".
+lt_option_debug=
+func_parse_lt_options ()
+{
+ lt_script_arg0=\$0
+ shift
+ for lt_opt
+ do
+ case \"\$lt_opt\" in
+ --lt-debug) lt_option_debug=1 ;;
+ --lt-dump-script)
+ lt_dump_D=\`\$ECHO \"X\$lt_script_arg0\" | $SED -e 's/^X//' -e 's%/[^/]*$%%'\`
+ test \"X\$lt_dump_D\" = \"X\$lt_script_arg0\" && lt_dump_D=.
+ lt_dump_F=\`\$ECHO \"X\$lt_script_arg0\" | $SED -e 's/^X//' -e 's%^.*/%%'\`
+ cat \"\$lt_dump_D/\$lt_dump_F\"
+ exit 0
+ ;;
+ --lt-*)
+ \$ECHO \"Unrecognized --lt- option: '\$lt_opt'\" 1>&2
+ exit 1
+ ;;
+ esac
+ done
+
+ # Print the debug banner immediately:
+ if test -n \"\$lt_option_debug\"; then
+ echo \"$outputname:$output:\$LINENO: libtool wrapper (GNU $PACKAGE) $VERSION\" 1>&2
+ fi
+}
+
+# Used when --lt-debug. Prints its arguments to stdout
+# (redirection is the responsibility of the caller)
+func_lt_dump_args ()
+{
+ lt_dump_args_N=1;
+ for lt_arg
+ do
+ \$ECHO \"$outputname:$output:\$LINENO: newargv[\$lt_dump_args_N]: \$lt_arg\"
+ lt_dump_args_N=\`expr \$lt_dump_args_N + 1\`
+ done
+}
+
+# Core function for launching the target application
+func_exec_program_core ()
+{
+"
+ case $host in
+ # Backslashes separate directories on plain windows
+ *-*-mingw | *-*-os2* | *-cegcc*)
+ $ECHO "\
+ if test -n \"\$lt_option_debug\"; then
+ \$ECHO \"$outputname:$output:\$LINENO: newargv[0]: \$progdir\\\\\$program\" 1>&2
+ func_lt_dump_args \${1+\"\$@\"} 1>&2
+ fi
+ exec \"\$progdir\\\\\$program\" \${1+\"\$@\"}
+"
+ ;;
+
+ *)
+ $ECHO "\
+ if test -n \"\$lt_option_debug\"; then
+ \$ECHO \"$outputname:$output:\$LINENO: newargv[0]: \$progdir/\$program\" 1>&2
+ func_lt_dump_args \${1+\"\$@\"} 1>&2
+ fi
+ exec \"\$progdir/\$program\" \${1+\"\$@\"}
+"
+ ;;
+ esac
+ $ECHO "\
+ \$ECHO \"\$0: cannot exec \$program \$*\" 1>&2
+ exit 1
+}
+
+# A function to encapsulate launching the target application
+# Strips options in the --lt-* namespace from \$@ and
+# launches target application with the remaining arguments.
+func_exec_program ()
+{
+ case \" \$* \" in
+ *\\ --lt-*)
+ for lt_wr_arg
+ do
+ case \$lt_wr_arg in
+ --lt-*) ;;
+ *) set x \"\$@\" \"\$lt_wr_arg\"; shift;;
+ esac
+ shift
+ done ;;
+ esac
+ func_exec_program_core \${1+\"\$@\"}
+}
+
+ # Parse options
+ func_parse_lt_options \"\$0\" \${1+\"\$@\"}
+
+ # Find the directory that this script lives in.
+ thisdir=\`\$ECHO \"\$file\" | $SED 's%/[^/]*$%%'\`
+ test \"x\$thisdir\" = \"x\$file\" && thisdir=.
+
+ # Follow symbolic links until we get to the real thisdir.
+ file=\`ls -ld \"\$file\" | $SED -n 's/.*-> //p'\`
+ while test -n \"\$file\"; do
+ destdir=\`\$ECHO \"\$file\" | $SED 's%/[^/]*\$%%'\`
+
+ # If there was a directory component, then change thisdir.
+ if test \"x\$destdir\" != \"x\$file\"; then
+ case \"\$destdir\" in
+ [\\\\/]* | [A-Za-z]:[\\\\/]*) thisdir=\"\$destdir\" ;;
+ *) thisdir=\"\$thisdir/\$destdir\" ;;
+ esac
+ fi
+
+ file=\`\$ECHO \"\$file\" | $SED 's%^.*/%%'\`
+ file=\`ls -ld \"\$thisdir/\$file\" | $SED -n 's/.*-> //p'\`
+ done
+
+ # Usually 'no', except on cygwin/mingw when embedded into
+ # the cwrapper.
+ WRAPPER_SCRIPT_BELONGS_IN_OBJDIR=$func_emit_wrapper_arg1
+ if test \"\$WRAPPER_SCRIPT_BELONGS_IN_OBJDIR\" = \"yes\"; then
+ # special case for '.'
+ if test \"\$thisdir\" = \".\"; then
+ thisdir=\`pwd\`
+ fi
+ # remove .libs from thisdir
+ case \"\$thisdir\" in
+ *[\\\\/]$objdir ) thisdir=\`\$ECHO \"\$thisdir\" | $SED 's%[\\\\/][^\\\\/]*$%%'\` ;;
+ $objdir ) thisdir=. ;;
+ esac
+ fi
+
+ # Try to get the absolute directory name.
+ absdir=\`cd \"\$thisdir\" && pwd\`
+ test -n \"\$absdir\" && thisdir=\"\$absdir\"
+"
+
+ if test yes = "$fast_install"; then
+ $ECHO "\
+ program=lt-'$outputname'$exeext
+ progdir=\"\$thisdir/$objdir\"
+
+ if test ! -f \"\$progdir/\$program\" ||
+ { file=\`ls -1dt \"\$progdir/\$program\" \"\$progdir/../\$program\" 2>/dev/null | $SED 1q\`; \\
+ test \"X\$file\" != \"X\$progdir/\$program\"; }; then
+
+ file=\"\$\$-\$program\"
+
+ if test ! -d \"\$progdir\"; then
+ $MKDIR \"\$progdir\"
+ else
+ $RM \"\$progdir/\$file\"
+ fi"
+
+ $ECHO "\
+
+ # relink executable if necessary
+ if test -n \"\$relink_command\"; then
+ if relink_command_output=\`eval \$relink_command 2>&1\`; then :
+ else
+ \$ECHO \"\$relink_command_output\" >&2
+ $RM \"\$progdir/\$file\"
+ exit 1
+ fi
+ fi
+
+ $MV \"\$progdir/\$file\" \"\$progdir/\$program\" 2>/dev/null ||
+ { $RM \"\$progdir/\$program\";
+ $MV \"\$progdir/\$file\" \"\$progdir/\$program\"; }
+ $RM \"\$progdir/\$file\"
+ fi"
+ else
+ $ECHO "\
+ program='$outputname'
+ progdir=\"\$thisdir/$objdir\"
+"
+ fi
+
+ $ECHO "\
+
+ if test -f \"\$progdir/\$program\"; then"
+
+ # fixup the dll searchpath if we need to.
+ #
+ # Fix the DLL searchpath if we need to. Do this before prepending
+ # to shlibpath, because on Windows, both are PATH and uninstalled
+ # libraries must come first.
+ if test -n "$dllsearchpath"; then
+ $ECHO "\
+ # Add the dll search path components to the executable PATH
+ PATH=$dllsearchpath:\$PATH
+"
+ fi
+
+ # Export our shlibpath_var if we have one.
+ if test yes = "$shlibpath_overrides_runpath" && test -n "$shlibpath_var" && test -n "$temp_rpath"; then
+ $ECHO "\
+ # Add our own library path to $shlibpath_var
+ $shlibpath_var=\"$temp_rpath\$$shlibpath_var\"
+
+ # Some systems cannot cope with colon-terminated $shlibpath_var
+ # The second colon is a workaround for a bug in BeOS R4 sed
+ $shlibpath_var=\`\$ECHO \"\$$shlibpath_var\" | $SED 's/::*\$//'\`
+
+ export $shlibpath_var
+"
+ fi
+
+ $ECHO "\
+ if test \"\$libtool_execute_magic\" != \"$magic\"; then
+ # Run the actual program with our arguments.
+ func_exec_program \${1+\"\$@\"}
+ fi
+ else
+ # The program doesn't exist.
+ \$ECHO \"\$0: error: '\$progdir/\$program' does not exist\" 1>&2
+ \$ECHO \"This script is just a wrapper for \$program.\" 1>&2
+ \$ECHO \"See the $PACKAGE documentation for more information.\" 1>&2
+ exit 1
+ fi
+fi\
+"
+}
+
+
+# func_emit_cwrapperexe_src
+# emit the source code for a wrapper executable on stdout
+# Must ONLY be called from within func_mode_link because
+# it depends on a number of variable set therein.
+func_emit_cwrapperexe_src ()
+{
+ cat <<EOF
+
+/* $cwrappersource - temporary wrapper executable for $objdir/$outputname
+ Generated by $PROGRAM (GNU $PACKAGE) $VERSION
+
+ The $output program cannot be directly executed until all the libtool
+ libraries that it depends on are installed.
+
+ This wrapper executable should never be moved out of the build directory.
+ If it is, it will not operate correctly.
+*/
+EOF
+ cat <<"EOF"
+#ifdef _MSC_VER
+# define _CRT_SECURE_NO_DEPRECATE 1
+#endif
+#include <stdio.h>
+#include <stdlib.h>
+#ifdef _MSC_VER
+# include <direct.h>
+# include <process.h>
+# include <io.h>
+#else
+# include <unistd.h>
+# include <stdint.h>
+# ifdef __CYGWIN__
+# include <io.h>
+# endif
+#endif
+#include <malloc.h>
+#include <stdarg.h>
+#include <assert.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+
+#define STREQ(s1, s2) (strcmp ((s1), (s2)) == 0)
+
+/* declarations of non-ANSI functions */
+#if defined __MINGW32__
+# ifdef __STRICT_ANSI__
+int _putenv (const char *);
+# endif
+#elif defined __CYGWIN__
+# ifdef __STRICT_ANSI__
+char *realpath (const char *, char *);
+int putenv (char *);
+int setenv (const char *, const char *, int);
+# endif
+/* #elif defined other_platform || defined ... */
+#endif
+
+/* portability defines, excluding path handling macros */
+#if defined _MSC_VER
+# define setmode _setmode
+# define stat _stat
+# define chmod _chmod
+# define getcwd _getcwd
+# define putenv _putenv
+# define S_IXUSR _S_IEXEC
+#elif defined __MINGW32__
+# define setmode _setmode
+# define stat _stat
+# define chmod _chmod
+# define getcwd _getcwd
+# define putenv _putenv
+#elif defined __CYGWIN__
+# define HAVE_SETENV
+# define FOPEN_WB "wb"
+/* #elif defined other platforms ... */
+#endif
+
+#if defined PATH_MAX
+# define LT_PATHMAX PATH_MAX
+#elif defined MAXPATHLEN
+# define LT_PATHMAX MAXPATHLEN
+#else
+# define LT_PATHMAX 1024
+#endif
+
+#ifndef S_IXOTH
+# define S_IXOTH 0
+#endif
+#ifndef S_IXGRP
+# define S_IXGRP 0
+#endif
+
+/* path handling portability macros */
+#ifndef DIR_SEPARATOR
+# define DIR_SEPARATOR '/'
+# define PATH_SEPARATOR ':'
+#endif
+
+#if defined _WIN32 || defined __MSDOS__ || defined __DJGPP__ || \
+ defined __OS2__
+# define HAVE_DOS_BASED_FILE_SYSTEM
+# define FOPEN_WB "wb"
+# ifndef DIR_SEPARATOR_2
+# define DIR_SEPARATOR_2 '\\'
+# endif
+# ifndef PATH_SEPARATOR_2
+# define PATH_SEPARATOR_2 ';'
+# endif
+#endif
+
+#ifndef DIR_SEPARATOR_2
+# define IS_DIR_SEPARATOR(ch) ((ch) == DIR_SEPARATOR)
+#else /* DIR_SEPARATOR_2 */
+# define IS_DIR_SEPARATOR(ch) \
+ (((ch) == DIR_SEPARATOR) || ((ch) == DIR_SEPARATOR_2))
+#endif /* DIR_SEPARATOR_2 */
+
+#ifndef PATH_SEPARATOR_2
+# define IS_PATH_SEPARATOR(ch) ((ch) == PATH_SEPARATOR)
+#else /* PATH_SEPARATOR_2 */
+# define IS_PATH_SEPARATOR(ch) ((ch) == PATH_SEPARATOR_2)
+#endif /* PATH_SEPARATOR_2 */
+
+#ifndef FOPEN_WB
+# define FOPEN_WB "w"
+#endif
+#ifndef _O_BINARY
+# define _O_BINARY 0
+#endif
+
+#define XMALLOC(type, num) ((type *) xmalloc ((num) * sizeof(type)))
+#define XFREE(stale) do { \
+ if (stale) { free (stale); stale = 0; } \
+} while (0)
+
+#if defined LT_DEBUGWRAPPER
+static int lt_debug = 1;
+#else
+static int lt_debug = 0;
+#endif
+
+const char *program_name = "libtool-wrapper"; /* in case xstrdup fails */
+
+void *xmalloc (size_t num);
+char *xstrdup (const char *string);
+const char *base_name (const char *name);
+char *find_executable (const char *wrapper);
+char *chase_symlinks (const char *pathspec);
+int make_executable (const char *path);
+int check_executable (const char *path);
+char *strendzap (char *str, const char *pat);
+void lt_debugprintf (const char *file, int line, const char *fmt, ...);
+void lt_fatal (const char *file, int line, const char *message, ...);
+static const char *nonnull (const char *s);
+static const char *nonempty (const char *s);
+void lt_setenv (const char *name, const char *value);
+char *lt_extend_str (const char *orig_value, const char *add, int to_end);
+void lt_update_exe_path (const char *name, const char *value);
+void lt_update_lib_path (const char *name, const char *value);
+char **prepare_spawn (char **argv);
+void lt_dump_script (FILE *f);
+EOF
+
+ cat <<EOF
+#if __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 5)
+# define externally_visible volatile
+#else
+# define externally_visible __attribute__((externally_visible)) volatile
+#endif
+externally_visible const char * MAGIC_EXE = "$magic_exe";
+const char * LIB_PATH_VARNAME = "$shlibpath_var";
+EOF
+
+ if test yes = "$shlibpath_overrides_runpath" && test -n "$shlibpath_var" && test -n "$temp_rpath"; then
+ func_to_host_path "$temp_rpath"
+ cat <<EOF
+const char * LIB_PATH_VALUE = "$func_to_host_path_result";
+EOF
+ else
+ cat <<"EOF"
+const char * LIB_PATH_VALUE = "";
+EOF
+ fi
+
+ if test -n "$dllsearchpath"; then
+ func_to_host_path "$dllsearchpath:"
+ cat <<EOF
+const char * EXE_PATH_VARNAME = "PATH";
+const char * EXE_PATH_VALUE = "$func_to_host_path_result";
+EOF
+ else
+ cat <<"EOF"
+const char * EXE_PATH_VARNAME = "";
+const char * EXE_PATH_VALUE = "";
+EOF
+ fi
+
+ if test yes = "$fast_install"; then
+ cat <<EOF
+const char * TARGET_PROGRAM_NAME = "lt-$outputname"; /* hopefully, no .exe */
+EOF
+ else
+ cat <<EOF
+const char * TARGET_PROGRAM_NAME = "$outputname"; /* hopefully, no .exe */
+EOF
+ fi
+
+
+ cat <<"EOF"
+
+#define LTWRAPPER_OPTION_PREFIX "--lt-"
+
+static const char *ltwrapper_option_prefix = LTWRAPPER_OPTION_PREFIX;
+static const char *dumpscript_opt = LTWRAPPER_OPTION_PREFIX "dump-script";
+static const char *debug_opt = LTWRAPPER_OPTION_PREFIX "debug";
+
+int
+main (int argc, char *argv[])
+{
+ char **newargz;
+ int newargc;
+ char *tmp_pathspec;
+ char *actual_cwrapper_path;
+ char *actual_cwrapper_name;
+ char *target_name;
+ char *lt_argv_zero;
+ int rval = 127;
+
+ int i;
+
+ program_name = (char *) xstrdup (base_name (argv[0]));
+ newargz = XMALLOC (char *, (size_t) argc + 1);
+
+ /* very simple arg parsing; don't want to rely on getopt
+ * also, copy all non cwrapper options to newargz, except
+ * argz[0], which is handled differently
+ */
+ newargc=0;
+ for (i = 1; i < argc; i++)
+ {
+ if (STREQ (argv[i], dumpscript_opt))
+ {
+EOF
+ case $host in
+ *mingw* | *cygwin* )
+ # make stdout use "unix" line endings
+ echo " setmode(1,_O_BINARY);"
+ ;;
+ esac
+
+ cat <<"EOF"
+ lt_dump_script (stdout);
+ return 0;
+ }
+ if (STREQ (argv[i], debug_opt))
+ {
+ lt_debug = 1;
+ continue;
+ }
+ if (STREQ (argv[i], ltwrapper_option_prefix))
+ {
+ /* however, if there is an option in the LTWRAPPER_OPTION_PREFIX
+ namespace, but it is not one of the ones we know about and
+ have already dealt with, above (inluding dump-script), then
+ report an error. Otherwise, targets might begin to believe
+ they are allowed to use options in the LTWRAPPER_OPTION_PREFIX
+ namespace. The first time any user complains about this, we'll
+ need to make LTWRAPPER_OPTION_PREFIX a configure-time option
+ or a configure.ac-settable value.
+ */
+ lt_fatal (__FILE__, __LINE__,
+ "unrecognized %s option: '%s'",
+ ltwrapper_option_prefix, argv[i]);
+ }
+ /* otherwise ... */
+ newargz[++newargc] = xstrdup (argv[i]);
+ }
+ newargz[++newargc] = NULL;
+
+EOF
+ cat <<EOF
+ /* The GNU banner must be the first non-error debug message */
+ lt_debugprintf (__FILE__, __LINE__, "libtool wrapper (GNU $PACKAGE) $VERSION\n");
+EOF
+ cat <<"EOF"
+ lt_debugprintf (__FILE__, __LINE__, "(main) argv[0]: %s\n", argv[0]);
+ lt_debugprintf (__FILE__, __LINE__, "(main) program_name: %s\n", program_name);
+
+ tmp_pathspec = find_executable (argv[0]);
+ if (tmp_pathspec == NULL)
+ lt_fatal (__FILE__, __LINE__, "couldn't find %s", argv[0]);
+ lt_debugprintf (__FILE__, __LINE__,
+ "(main) found exe (before symlink chase) at: %s\n",
+ tmp_pathspec);
+
+ actual_cwrapper_path = chase_symlinks (tmp_pathspec);
+ lt_debugprintf (__FILE__, __LINE__,
+ "(main) found exe (after symlink chase) at: %s\n",
+ actual_cwrapper_path);
+ XFREE (tmp_pathspec);
+
+ actual_cwrapper_name = xstrdup (base_name (actual_cwrapper_path));
+ strendzap (actual_cwrapper_path, actual_cwrapper_name);
+
+ /* wrapper name transforms */
+ strendzap (actual_cwrapper_name, ".exe");
+ tmp_pathspec = lt_extend_str (actual_cwrapper_name, ".exe", 1);
+ XFREE (actual_cwrapper_name);
+ actual_cwrapper_name = tmp_pathspec;
+ tmp_pathspec = 0;
+
+ /* target_name transforms -- use actual target program name; might have lt- prefix */
+ target_name = xstrdup (base_name (TARGET_PROGRAM_NAME));
+ strendzap (target_name, ".exe");
+ tmp_pathspec = lt_extend_str (target_name, ".exe", 1);
+ XFREE (target_name);
+ target_name = tmp_pathspec;
+ tmp_pathspec = 0;
+
+ lt_debugprintf (__FILE__, __LINE__,
+ "(main) libtool target name: %s\n",
+ target_name);
+EOF
+
+ cat <<EOF
+ newargz[0] =
+ XMALLOC (char, (strlen (actual_cwrapper_path) +
+ strlen ("$objdir") + 1 + strlen (actual_cwrapper_name) + 1));
+ strcpy (newargz[0], actual_cwrapper_path);
+ strcat (newargz[0], "$objdir");
+ strcat (newargz[0], "/");
+EOF
+
+ cat <<"EOF"
+ /* stop here, and copy so we don't have to do this twice */
+ tmp_pathspec = xstrdup (newargz[0]);
+
+ /* do NOT want the lt- prefix here, so use actual_cwrapper_name */
+ strcat (newargz[0], actual_cwrapper_name);
+
+ /* DO want the lt- prefix here if it exists, so use target_name */
+ lt_argv_zero = lt_extend_str (tmp_pathspec, target_name, 1);
+ XFREE (tmp_pathspec);
+ tmp_pathspec = NULL;
+EOF
+
+ case $host_os in
+ mingw*)
+ cat <<"EOF"
+ {
+ char* p;
+ while ((p = strchr (newargz[0], '\\')) != NULL)
+ {
+ *p = '/';
+ }
+ while ((p = strchr (lt_argv_zero, '\\')) != NULL)
+ {
+ *p = '/';
+ }
+ }
+EOF
+ ;;
+ esac
+
+ cat <<"EOF"
+ XFREE (target_name);
+ XFREE (actual_cwrapper_path);
+ XFREE (actual_cwrapper_name);
+
+ lt_setenv ("BIN_SH", "xpg4"); /* for Tru64 */
+ lt_setenv ("DUALCASE", "1"); /* for MSK sh */
+ /* Update the DLL searchpath. EXE_PATH_VALUE ($dllsearchpath) must
+ be prepended before (that is, appear after) LIB_PATH_VALUE ($temp_rpath)
+ because on Windows, both *_VARNAMEs are PATH but uninstalled
+ libraries must come first. */
+ lt_update_exe_path (EXE_PATH_VARNAME, EXE_PATH_VALUE);
+ lt_update_lib_path (LIB_PATH_VARNAME, LIB_PATH_VALUE);
+
+ lt_debugprintf (__FILE__, __LINE__, "(main) lt_argv_zero: %s\n",
+ nonnull (lt_argv_zero));
+ for (i = 0; i < newargc; i++)
+ {
+ lt_debugprintf (__FILE__, __LINE__, "(main) newargz[%d]: %s\n",
+ i, nonnull (newargz[i]));
+ }
+
+EOF
+
+ case $host_os in
+ mingw*)
+ cat <<"EOF"
+ /* execv doesn't actually work on mingw as expected on unix */
+ newargz = prepare_spawn (newargz);
+ rval = (int) _spawnv (_P_WAIT, lt_argv_zero, (const char * const *) newargz);
+ if (rval == -1)
+ {
+ /* failed to start process */
+ lt_debugprintf (__FILE__, __LINE__,
+ "(main) failed to launch target \"%s\": %s\n",
+ lt_argv_zero, nonnull (strerror (errno)));
+ return 127;
+ }
+ return rval;
+EOF
+ ;;
+ *)
+ cat <<"EOF"
+ execv (lt_argv_zero, newargz);
+ return rval; /* =127, but avoids unused variable warning */
+EOF
+ ;;
+ esac
+
+ cat <<"EOF"
+}
+
+void *
+xmalloc (size_t num)
+{
+ void *p = (void *) malloc (num);
+ if (!p)
+ lt_fatal (__FILE__, __LINE__, "memory exhausted");
+
+ return p;
+}
+
+char *
+xstrdup (const char *string)
+{
+ return string ? strcpy ((char *) xmalloc (strlen (string) + 1),
+ string) : NULL;
+}
+
+const char *
+base_name (const char *name)
+{
+ const char *base;
+
+#if defined HAVE_DOS_BASED_FILE_SYSTEM
+ /* Skip over the disk name in MSDOS pathnames. */
+ if (isalpha ((unsigned char) name[0]) && name[1] == ':')
+ name += 2;
+#endif
+
+ for (base = name; *name; name++)
+ if (IS_DIR_SEPARATOR (*name))
+ base = name + 1;
+ return base;
+}
+
+int
+check_executable (const char *path)
+{
+ struct stat st;
+
+ lt_debugprintf (__FILE__, __LINE__, "(check_executable): %s\n",
+ nonempty (path));
+ if ((!path) || (!*path))
+ return 0;
+
+ if ((stat (path, &st) >= 0)
+ && (st.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH)))
+ return 1;
+ else
+ return 0;
+}
+
+int
+make_executable (const char *path)
+{
+ int rval = 0;
+ struct stat st;
+
+ lt_debugprintf (__FILE__, __LINE__, "(make_executable): %s\n",
+ nonempty (path));
+ if ((!path) || (!*path))
+ return 0;
+
+ if (stat (path, &st) >= 0)
+ {
+ rval = chmod (path, st.st_mode | S_IXOTH | S_IXGRP | S_IXUSR);
+ }
+ return rval;
+}
+
+/* Searches for the full path of the wrapper. Returns
+ newly allocated full path name if found, NULL otherwise
+ Does not chase symlinks, even on platforms that support them.
+*/
+char *
+find_executable (const char *wrapper)
+{
+ int has_slash = 0;
+ const char *p;
+ const char *p_next;
+ /* static buffer for getcwd */
+ char tmp[LT_PATHMAX + 1];
+ size_t tmp_len;
+ char *concat_name;
+
+ lt_debugprintf (__FILE__, __LINE__, "(find_executable): %s\n",
+ nonempty (wrapper));
+
+ if ((wrapper == NULL) || (*wrapper == '\0'))
+ return NULL;
+
+ /* Absolute path? */
+#if defined HAVE_DOS_BASED_FILE_SYSTEM
+ if (isalpha ((unsigned char) wrapper[0]) && wrapper[1] == ':')
+ {
+ concat_name = xstrdup (wrapper);
+ if (check_executable (concat_name))
+ return concat_name;
+ XFREE (concat_name);
+ }
+ else
+ {
+#endif
+ if (IS_DIR_SEPARATOR (wrapper[0]))
+ {
+ concat_name = xstrdup (wrapper);
+ if (check_executable (concat_name))
+ return concat_name;
+ XFREE (concat_name);
+ }
+#if defined HAVE_DOS_BASED_FILE_SYSTEM
+ }
+#endif
+
+ for (p = wrapper; *p; p++)
+ if (*p == '/')
+ {
+ has_slash = 1;
+ break;
+ }
+ if (!has_slash)
+ {
+ /* no slashes; search PATH */
+ const char *path = getenv ("PATH");
+ if (path != NULL)
+ {
+ for (p = path; *p; p = p_next)
+ {
+ const char *q;
+ size_t p_len;
+ for (q = p; *q; q++)
+ if (IS_PATH_SEPARATOR (*q))
+ break;
+ p_len = (size_t) (q - p);
+ p_next = (*q == '\0' ? q : q + 1);
+ if (p_len == 0)
+ {
+ /* empty path: current directory */
+ if (getcwd (tmp, LT_PATHMAX) == NULL)
+ lt_fatal (__FILE__, __LINE__, "getcwd failed: %s",
+ nonnull (strerror (errno)));
+ tmp_len = strlen (tmp);
+ concat_name =
+ XMALLOC (char, tmp_len + 1 + strlen (wrapper) + 1);
+ memcpy (concat_name, tmp, tmp_len);
+ concat_name[tmp_len] = '/';
+ strcpy (concat_name + tmp_len + 1, wrapper);
+ }
+ else
+ {
+ concat_name =
+ XMALLOC (char, p_len + 1 + strlen (wrapper) + 1);
+ memcpy (concat_name, p, p_len);
+ concat_name[p_len] = '/';
+ strcpy (concat_name + p_len + 1, wrapper);
+ }
+ if (check_executable (concat_name))
+ return concat_name;
+ XFREE (concat_name);
+ }
+ }
+ /* not found in PATH; assume curdir */
+ }
+ /* Relative path | not found in path: prepend cwd */
+ if (getcwd (tmp, LT_PATHMAX) == NULL)
+ lt_fatal (__FILE__, __LINE__, "getcwd failed: %s",
+ nonnull (strerror (errno)));
+ tmp_len = strlen (tmp);
+ concat_name = XMALLOC (char, tmp_len + 1 + strlen (wrapper) + 1);
+ memcpy (concat_name, tmp, tmp_len);
+ concat_name[tmp_len] = '/';
+ strcpy (concat_name + tmp_len + 1, wrapper);
+
+ if (check_executable (concat_name))
+ return concat_name;
+ XFREE (concat_name);
+ return NULL;
+}
+
+char *
+chase_symlinks (const char *pathspec)
+{
+#ifndef S_ISLNK
+ return xstrdup (pathspec);
+#else
+ char buf[LT_PATHMAX];
+ struct stat s;
+ char *tmp_pathspec = xstrdup (pathspec);
+ char *p;
+ int has_symlinks = 0;
+ while (strlen (tmp_pathspec) && !has_symlinks)
+ {
+ lt_debugprintf (__FILE__, __LINE__,
+ "checking path component for symlinks: %s\n",
+ tmp_pathspec);
+ if (lstat (tmp_pathspec, &s) == 0)
+ {
+ if (S_ISLNK (s.st_mode) != 0)
+ {
+ has_symlinks = 1;
+ break;
+ }
+
+ /* search backwards for last DIR_SEPARATOR */
+ p = tmp_pathspec + strlen (tmp_pathspec) - 1;
+ while ((p > tmp_pathspec) && (!IS_DIR_SEPARATOR (*p)))
+ p--;
+ if ((p == tmp_pathspec) && (!IS_DIR_SEPARATOR (*p)))
+ {
+ /* no more DIR_SEPARATORS left */
+ break;
+ }
+ *p = '\0';
+ }
+ else
+ {
+ lt_fatal (__FILE__, __LINE__,
+ "error accessing file \"%s\": %s",
+ tmp_pathspec, nonnull (strerror (errno)));
+ }
+ }
+ XFREE (tmp_pathspec);
+
+ if (!has_symlinks)
+ {
+ return xstrdup (pathspec);
+ }
+
+ tmp_pathspec = realpath (pathspec, buf);
+ if (tmp_pathspec == 0)
+ {
+ lt_fatal (__FILE__, __LINE__,
+ "could not follow symlinks for %s", pathspec);
+ }
+ return xstrdup (tmp_pathspec);
+#endif
+}
+
+char *
+strendzap (char *str, const char *pat)
+{
+ size_t len, patlen;
+
+ assert (str != NULL);
+ assert (pat != NULL);
+
+ len = strlen (str);
+ patlen = strlen (pat);
+
+ if (patlen <= len)
+ {
+ str += len - patlen;
+ if (STREQ (str, pat))
+ *str = '\0';
+ }
+ return str;
+}
+
+void
+lt_debugprintf (const char *file, int line, const char *fmt, ...)
+{
+ va_list args;
+ if (lt_debug)
+ {
+ (void) fprintf (stderr, "%s:%s:%d: ", program_name, file, line);
+ va_start (args, fmt);
+ (void) vfprintf (stderr, fmt, args);
+ va_end (args);
+ }
+}
+
+static void
+lt_error_core (int exit_status, const char *file,
+ int line, const char *mode,
+ const char *message, va_list ap)
+{
+ fprintf (stderr, "%s:%s:%d: %s: ", program_name, file, line, mode);
+ vfprintf (stderr, message, ap);
+ fprintf (stderr, ".\n");
+
+ if (exit_status >= 0)
+ exit (exit_status);
+}
+
+void
+lt_fatal (const char *file, int line, const char *message, ...)
+{
+ va_list ap;
+ va_start (ap, message);
+ lt_error_core (EXIT_FAILURE, file, line, "FATAL", message, ap);
+ va_end (ap);
+}
+
+static const char *
+nonnull (const char *s)
+{
+ return s ? s : "(null)";
+}
+
+static const char *
+nonempty (const char *s)
+{
+ return (s && !*s) ? "(empty)" : nonnull (s);
+}
+
+void
+lt_setenv (const char *name, const char *value)
+{
+ lt_debugprintf (__FILE__, __LINE__,
+ "(lt_setenv) setting '%s' to '%s'\n",
+ nonnull (name), nonnull (value));
+ {
+#ifdef HAVE_SETENV
+ /* always make a copy, for consistency with !HAVE_SETENV */
+ char *str = xstrdup (value);
+ setenv (name, str, 1);
+#else
+ size_t len = strlen (name) + 1 + strlen (value) + 1;
+ char *str = XMALLOC (char, len);
+ sprintf (str, "%s=%s", name, value);
+ if (putenv (str) != EXIT_SUCCESS)
+ {
+ XFREE (str);
+ }
+#endif
+ }
+}
+
+char *
+lt_extend_str (const char *orig_value, const char *add, int to_end)
+{
+ char *new_value;
+ if (orig_value && *orig_value)
+ {
+ size_t orig_value_len = strlen (orig_value);
+ size_t add_len = strlen (add);
+ new_value = XMALLOC (char, add_len + orig_value_len + 1);
+ if (to_end)
+ {
+ strcpy (new_value, orig_value);
+ strcpy (new_value + orig_value_len, add);
+ }
+ else
+ {
+ strcpy (new_value, add);
+ strcpy (new_value + add_len, orig_value);
+ }
+ }
+ else
+ {
+ new_value = xstrdup (add);
+ }
+ return new_value;
+}
+
+void
+lt_update_exe_path (const char *name, const char *value)
+{
+ lt_debugprintf (__FILE__, __LINE__,
+ "(lt_update_exe_path) modifying '%s' by prepending '%s'\n",
+ nonnull (name), nonnull (value));
+
+ if (name && *name && value && *value)
+ {
+ char *new_value = lt_extend_str (getenv (name), value, 0);
+ /* some systems can't cope with a ':'-terminated path #' */
+ size_t len = strlen (new_value);
+ while ((len > 0) && IS_PATH_SEPARATOR (new_value[len-1]))
+ {
+ new_value[--len] = '\0';
+ }
+ lt_setenv (name, new_value);
+ XFREE (new_value);
+ }
+}
+
+void
+lt_update_lib_path (const char *name, const char *value)
+{
+ lt_debugprintf (__FILE__, __LINE__,
+ "(lt_update_lib_path) modifying '%s' by prepending '%s'\n",
+ nonnull (name), nonnull (value));
+
+ if (name && *name && value && *value)
+ {
+ char *new_value = lt_extend_str (getenv (name), value, 0);
+ lt_setenv (name, new_value);
+ XFREE (new_value);
+ }
+}
+
+EOF
+ case $host_os in
+ mingw*)
+ cat <<"EOF"
+
+/* Prepares an argument vector before calling spawn().
+ Note that spawn() does not by itself call the command interpreter
+ (getenv ("COMSPEC") != NULL ? getenv ("COMSPEC") :
+ ({ OSVERSIONINFO v; v.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
+ GetVersionEx(&v);
+ v.dwPlatformId == VER_PLATFORM_WIN32_NT;
+ }) ? "cmd.exe" : "command.com").
+ Instead it simply concatenates the arguments, separated by ' ', and calls
+ CreateProcess(). We must quote the arguments since Win32 CreateProcess()
+ interprets characters like ' ', '\t', '\\', '"' (but not '<' and '>') in a
+ special way:
+ - Space and tab are interpreted as delimiters. They are not treated as
+ delimiters if they are surrounded by double quotes: "...".
+ - Unescaped double quotes are removed from the input. Their only effect is
+ that within double quotes, space and tab are treated like normal
+ characters.
+ - Backslashes not followed by double quotes are not special.
+ - But 2*n+1 backslashes followed by a double quote become
+ n backslashes followed by a double quote (n >= 0):
+ \" -> "
+ \\\" -> \"
+ \\\\\" -> \\"
+ */
+#define SHELL_SPECIAL_CHARS "\"\\ \001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037"
+#define SHELL_SPACE_CHARS " \001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037"
+char **
+prepare_spawn (char **argv)
+{
+ size_t argc;
+ char **new_argv;
+ size_t i;
+
+ /* Count number of arguments. */
+ for (argc = 0; argv[argc] != NULL; argc++)
+ ;
+
+ /* Allocate new argument vector. */
+ new_argv = XMALLOC (char *, argc + 1);
+
+ /* Put quoted arguments into the new argument vector. */
+ for (i = 0; i < argc; i++)
+ {
+ const char *string = argv[i];
+
+ if (string[0] == '\0')
+ new_argv[i] = xstrdup ("\"\"");
+ else if (strpbrk (string, SHELL_SPECIAL_CHARS) != NULL)
+ {
+ int quote_around = (strpbrk (string, SHELL_SPACE_CHARS) != NULL);
+ size_t length;
+ unsigned int backslashes;
+ const char *s;
+ char *quoted_string;
+ char *p;
+
+ length = 0;
+ backslashes = 0;
+ if (quote_around)
+ length++;
+ for (s = string; *s != '\0'; s++)
+ {
+ char c = *s;
+ if (c == '"')
+ length += backslashes + 1;
+ length++;
+ if (c == '\\')
+ backslashes++;
+ else
+ backslashes = 0;
+ }
+ if (quote_around)
+ length += backslashes + 1;
+
+ quoted_string = XMALLOC (char, length + 1);
+
+ p = quoted_string;
+ backslashes = 0;
+ if (quote_around)
+ *p++ = '"';
+ for (s = string; *s != '\0'; s++)
+ {
+ char c = *s;
+ if (c == '"')
+ {
+ unsigned int j;
+ for (j = backslashes + 1; j > 0; j--)
+ *p++ = '\\';
+ }
+ *p++ = c;
+ if (c == '\\')
+ backslashes++;
+ else
+ backslashes = 0;
+ }
+ if (quote_around)
+ {
+ unsigned int j;
+ for (j = backslashes; j > 0; j--)
+ *p++ = '\\';
+ *p++ = '"';
+ }
+ *p = '\0';
+
+ new_argv[i] = quoted_string;
+ }
+ else
+ new_argv[i] = (char *) string;
+ }
+ new_argv[argc] = NULL;
+
+ return new_argv;
+}
+EOF
+ ;;
+ esac
+
+ cat <<"EOF"
+void lt_dump_script (FILE* f)
+{
+EOF
+ func_emit_wrapper yes |
+ $SED -n -e '
+s/^\(.\{79\}\)\(..*\)/\1\
+\2/
+h
+s/\([\\"]\)/\\\1/g
+s/$/\\n/
+s/\([^\n]*\).*/ fputs ("\1", f);/p
+g
+D'
+ cat <<"EOF"
+}
+EOF
+}
+# end: func_emit_cwrapperexe_src
+
+# func_win32_import_lib_p ARG
+# True if ARG is an import lib, as indicated by $file_magic_cmd
+func_win32_import_lib_p ()
+{
+ $debug_cmd
+
+ case `eval $file_magic_cmd \"\$1\" 2>/dev/null | $SED -e 10q` in
+ *import*) : ;;
+ *) false ;;
+ esac
+}
+
+# func_suncc_cstd_abi
+# !!ONLY CALL THIS FOR SUN CC AFTER $compile_command IS FULLY EXPANDED!!
+# Several compiler flags select an ABI that is incompatible with the
+# Cstd library. Avoid specifying it if any are in CXXFLAGS.
+func_suncc_cstd_abi ()
+{
+ $debug_cmd
+
+ case " $compile_command " in
+ *" -compat=g "*|*\ -std=c++[0-9][0-9]\ *|*" -library=stdcxx4 "*|*" -library=stlport4 "*)
+ suncc_use_cstd_abi=no
+ ;;
+ *)
+ suncc_use_cstd_abi=yes
+ ;;
+ esac
+}
+
+# func_mode_link arg...
+func_mode_link ()
+{
+ $debug_cmd
+
+ case $host in
+ *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*)
+ # It is impossible to link a dll without this setting, and
+ # we shouldn't force the makefile maintainer to figure out
+ # what system we are compiling for in order to pass an extra
+ # flag for every libtool invocation.
+ # allow_undefined=no
+
+ # FIXME: Unfortunately, there are problems with the above when trying
+ # to make a dll that has undefined symbols, in which case not
+ # even a static library is built. For now, we need to specify
+ # -no-undefined on the libtool link line when we can be certain
+ # that all symbols are satisfied, otherwise we get a static library.
+ allow_undefined=yes
+ ;;
+ *)
+ allow_undefined=yes
+ ;;
+ esac
+ libtool_args=$nonopt
+ base_compile="$nonopt $@"
+ compile_command=$nonopt
+ finalize_command=$nonopt
+
+ compile_rpath=
+ finalize_rpath=
+ compile_shlibpath=
+ finalize_shlibpath=
+ convenience=
+ old_convenience=
+ deplibs=
+ old_deplibs=
+ compiler_flags=
+ linker_flags=
+ dllsearchpath=
+ lib_search_path=`pwd`
+ inst_prefix_dir=
+ new_inherited_linker_flags=
+
+ avoid_version=no
+ bindir=
+ dlfiles=
+ dlprefiles=
+ dlself=no
+ export_dynamic=no
+ export_symbols=
+ export_symbols_regex=
+ generated=
+ libobjs=
+ ltlibs=
+ module=no
+ no_install=no
+ objs=
+ os2dllname=
+ non_pic_objects=
+ precious_files_regex=
+ prefer_static_libs=no
+ preload=false
+ prev=
+ prevarg=
+ release=
+ rpath=
+ xrpath=
+ perm_rpath=
+ temp_rpath=
+ thread_safe=no
+ vinfo=
+ vinfo_number=no
+ weak_libs=
+ single_module=$wl-single_module
+ func_infer_tag $base_compile
+
+ # We need to know -static, to get the right output filenames.
+ for arg
+ do
+ case $arg in
+ -shared)
+ test yes != "$build_libtool_libs" \
+ && func_fatal_configuration "cannot build a shared library"
+ build_old_libs=no
+ break
+ ;;
+ -all-static | -static | -static-libtool-libs)
+ case $arg in
+ -all-static)
+ if test yes = "$build_libtool_libs" && test -z "$link_static_flag"; then
+ func_warning "complete static linking is impossible in this configuration"
+ fi
+ if test -n "$link_static_flag"; then
+ dlopen_self=$dlopen_self_static
+ fi
+ prefer_static_libs=yes
+ ;;
+ -static)
+ if test -z "$pic_flag" && test -n "$link_static_flag"; then
+ dlopen_self=$dlopen_self_static
+ fi
+ prefer_static_libs=built
+ ;;
+ -static-libtool-libs)
+ if test -z "$pic_flag" && test -n "$link_static_flag"; then
+ dlopen_self=$dlopen_self_static
+ fi
+ prefer_static_libs=yes
+ ;;
+ esac
+ build_libtool_libs=no
+ build_old_libs=yes
+ break
+ ;;
+ esac
+ done
+
+ # See if our shared archives depend on static archives.
+ test -n "$old_archive_from_new_cmds" && build_old_libs=yes
+
+ # Go through the arguments, transforming them on the way.
+ while test "$#" -gt 0; do
+ arg=$1
+ shift
+ func_quote_for_eval "$arg"
+ qarg=$func_quote_for_eval_unquoted_result
+ func_append libtool_args " $func_quote_for_eval_result"
+
+ # If the previous option needs an argument, assign it.
+ if test -n "$prev"; then
+ case $prev in
+ output)
+ func_append compile_command " @OUTPUT@"
+ func_append finalize_command " @OUTPUT@"
+ ;;
+ esac
+
+ case $prev in
+ bindir)
+ bindir=$arg
+ prev=
+ continue
+ ;;
+ dlfiles|dlprefiles)
+ $preload || {
+ # Add the symbol object into the linking commands.
+ func_append compile_command " @SYMFILE@"
+ func_append finalize_command " @SYMFILE@"
+ preload=:
+ }
+ case $arg in
+ *.la | *.lo) ;; # We handle these cases below.
+ force)
+ if test no = "$dlself"; then
+ dlself=needless
+ export_dynamic=yes
+ fi
+ prev=
+ continue
+ ;;
+ self)
+ if test dlprefiles = "$prev"; then
+ dlself=yes
+ elif test dlfiles = "$prev" && test yes != "$dlopen_self"; then
+ dlself=yes
+ else
+ dlself=needless
+ export_dynamic=yes
+ fi
+ prev=
+ continue
+ ;;
+ *)
+ if test dlfiles = "$prev"; then
+ func_append dlfiles " $arg"
+ else
+ func_append dlprefiles " $arg"
+ fi
+ prev=
+ continue
+ ;;
+ esac
+ ;;
+ expsyms)
+ export_symbols=$arg
+ test -f "$arg" \
+ || func_fatal_error "symbol file '$arg' does not exist"
+ prev=
+ continue
+ ;;
+ expsyms_regex)
+ export_symbols_regex=$arg
+ prev=
+ continue
+ ;;
+ framework)
+ case $host in
+ *-*-darwin*)
+ case "$deplibs " in
+ *" $qarg.ltframework "*) ;;
+ *) func_append deplibs " $qarg.ltframework" # this is fixed later
+ ;;
+ esac
+ ;;
+ esac
+ prev=
+ continue
+ ;;
+ inst_prefix)
+ inst_prefix_dir=$arg
+ prev=
+ continue
+ ;;
+ mllvm)
+ # Clang does not use LLVM to link, so we can simply discard any
+ # '-mllvm $arg' options when doing the link step.
+ prev=
+ continue
+ ;;
+ objectlist)
+ if test -f "$arg"; then
+ save_arg=$arg
+ moreargs=
+ for fil in `cat "$save_arg"`
+ do
+# func_append moreargs " $fil"
+ arg=$fil
+ # A libtool-controlled object.
+
+ # Check to see that this really is a libtool object.
+ if func_lalib_unsafe_p "$arg"; then
+ pic_object=
+ non_pic_object=
+
+ # Read the .lo file
+ func_source "$arg"
+
+ if test -z "$pic_object" ||
+ test -z "$non_pic_object" ||
+ test none = "$pic_object" &&
+ test none = "$non_pic_object"; then
+ func_fatal_error "cannot find name of object for '$arg'"
+ fi
+
+ # Extract subdirectory from the argument.
+ func_dirname "$arg" "/" ""
+ xdir=$func_dirname_result
+
+ if test none != "$pic_object"; then
+ # Prepend the subdirectory the object is found in.
+ pic_object=$xdir$pic_object
+
+ if test dlfiles = "$prev"; then
+ if test yes = "$build_libtool_libs" && test yes = "$dlopen_support"; then
+ func_append dlfiles " $pic_object"
+ prev=
+ continue
+ else
+ # If libtool objects are unsupported, then we need to preload.
+ prev=dlprefiles
+ fi
+ fi
+
+ # CHECK ME: I think I busted this. -Ossama
+ if test dlprefiles = "$prev"; then
+ # Preload the old-style object.
+ func_append dlprefiles " $pic_object"
+ prev=
+ fi
+
+ # A PIC object.
+ func_append libobjs " $pic_object"
+ arg=$pic_object
+ fi
+
+ # Non-PIC object.
+ if test none != "$non_pic_object"; then
+ # Prepend the subdirectory the object is found in.
+ non_pic_object=$xdir$non_pic_object
+
+ # A standard non-PIC object
+ func_append non_pic_objects " $non_pic_object"
+ if test -z "$pic_object" || test none = "$pic_object"; then
+ arg=$non_pic_object
+ fi
+ else
+ # If the PIC object exists, use it instead.
+ # $xdir was prepended to $pic_object above.
+ non_pic_object=$pic_object
+ func_append non_pic_objects " $non_pic_object"
+ fi
+ else
+ # Only an error if not doing a dry-run.
+ if $opt_dry_run; then
+ # Extract subdirectory from the argument.
+ func_dirname "$arg" "/" ""
+ xdir=$func_dirname_result
+
+ func_lo2o "$arg"
+ pic_object=$xdir$objdir/$func_lo2o_result
+ non_pic_object=$xdir$func_lo2o_result
+ func_append libobjs " $pic_object"
+ func_append non_pic_objects " $non_pic_object"
+ else
+ func_fatal_error "'$arg' is not a valid libtool object"
+ fi
+ fi
+ done
+ else
+ func_fatal_error "link input file '$arg' does not exist"
+ fi
+ arg=$save_arg
+ prev=
+ continue
+ ;;
+ os2dllname)
+ os2dllname=$arg
+ prev=
+ continue
+ ;;
+ precious_regex)
+ precious_files_regex=$arg
+ prev=
+ continue
+ ;;
+ release)
+ release=-$arg
+ prev=
+ continue
+ ;;
+ rpath | xrpath)
+ # We need an absolute path.
+ case $arg in
+ [\\/]* | [A-Za-z]:[\\/]*) ;;
+ *)
+ func_fatal_error "only absolute run-paths are allowed"
+ ;;
+ esac
+ if test rpath = "$prev"; then
+ case "$rpath " in
+ *" $arg "*) ;;
+ *) func_append rpath " $arg" ;;
+ esac
+ else
+ case "$xrpath " in
+ *" $arg "*) ;;
+ *) func_append xrpath " $arg" ;;
+ esac
+ fi
+ prev=
+ continue
+ ;;
+ shrext)
+ shrext_cmds=$arg
+ prev=
+ continue
+ ;;
+ weak)
+ func_append weak_libs " $arg"
+ prev=
+ continue
+ ;;
+ xcclinker)
+ func_append linker_flags " $qarg"
+ func_append compiler_flags " $qarg"
+ prev=
+ func_append compile_command " $qarg"
+ func_append finalize_command " $qarg"
+ continue
+ ;;
+ xcompiler)
+ func_append compiler_flags " $qarg"
+ prev=
+ func_append compile_command " $qarg"
+ func_append finalize_command " $qarg"
+ continue
+ ;;
+ xlinker)
+ func_append linker_flags " $qarg"
+ func_append compiler_flags " $wl$qarg"
+ prev=
+ func_append compile_command " $wl$qarg"
+ func_append finalize_command " $wl$qarg"
+ continue
+ ;;
+ *)
+ eval "$prev=\"\$arg\""
+ prev=
+ continue
+ ;;
+ esac
+ fi # test -n "$prev"
+
+ prevarg=$arg
+
+ case $arg in
+ -all-static)
+ if test -n "$link_static_flag"; then
+ # See comment for -static flag below, for more details.
+ func_append compile_command " $link_static_flag"
+ func_append finalize_command " $link_static_flag"
+ fi
+ continue
+ ;;
+
+ -allow-undefined)
+ # FIXME: remove this flag sometime in the future.
+ func_fatal_error "'-allow-undefined' must not be used because it is the default"
+ ;;
+
+ -avoid-version)
+ avoid_version=yes
+ continue
+ ;;
+
+ -bindir)
+ prev=bindir
+ continue
+ ;;
+
+ -dlopen)
+ prev=dlfiles
+ continue
+ ;;
+
+ -dlpreopen)
+ prev=dlprefiles
+ continue
+ ;;
+
+ -export-dynamic)
+ export_dynamic=yes
+ continue
+ ;;
+
+ -export-symbols | -export-symbols-regex)
+ if test -n "$export_symbols" || test -n "$export_symbols_regex"; then
+ func_fatal_error "more than one -exported-symbols argument is not allowed"
+ fi
+ if test X-export-symbols = "X$arg"; then
+ prev=expsyms
+ else
+ prev=expsyms_regex
+ fi
+ continue
+ ;;
+
+ -framework)
+ prev=framework
+ continue
+ ;;
+
+ -inst-prefix-dir)
+ prev=inst_prefix
+ continue
+ ;;
+
+ # The native IRIX linker understands -LANG:*, -LIST:* and -LNO:*
+ # so, if we see these flags be careful not to treat them like -L
+ -L[A-Z][A-Z]*:*)
+ case $with_gcc/$host in
+ no/*-*-irix* | /*-*-irix*)
+ func_append compile_command " $arg"
+ func_append finalize_command " $arg"
+ ;;
+ esac
+ continue
+ ;;
+
+ -L*)
+ func_stripname "-L" '' "$arg"
+ if test -z "$func_stripname_result"; then
+ if test "$#" -gt 0; then
+ func_fatal_error "require no space between '-L' and '$1'"
+ else
+ func_fatal_error "need path for '-L' option"
+ fi
+ fi
+ func_resolve_sysroot "$func_stripname_result"
+ dir=$func_resolve_sysroot_result
+ # We need an absolute path.
+ case $dir in
+ [\\/]* | [A-Za-z]:[\\/]*) ;;
+ *)
+ absdir=`cd "$dir" && pwd`
+ test -z "$absdir" && \
+ func_fatal_error "cannot determine absolute directory name of '$dir'"
+ dir=$absdir
+ ;;
+ esac
+ case "$deplibs " in
+ *" -L$dir "* | *" $arg "*)
+ # Will only happen for absolute or sysroot arguments
+ ;;
+ *)
+ # Preserve sysroot, but never include relative directories
+ case $dir in
+ [\\/]* | [A-Za-z]:[\\/]* | =*) func_append deplibs " $arg" ;;
+ *) func_append deplibs " -L$dir" ;;
+ esac
+ func_append lib_search_path " $dir"
+ ;;
+ esac
+ case $host in
+ *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*)
+ testbindir=`$ECHO "$dir" | $SED 's*/lib$*/bin*'`
+ case :$dllsearchpath: in
+ *":$dir:"*) ;;
+ ::) dllsearchpath=$dir;;
+ *) func_append dllsearchpath ":$dir";;
+ esac
+ case :$dllsearchpath: in
+ *":$testbindir:"*) ;;
+ ::) dllsearchpath=$testbindir;;
+ *) func_append dllsearchpath ":$testbindir";;
+ esac
+ ;;
+ esac
+ continue
+ ;;
+
+ -l*)
+ if test X-lc = "X$arg" || test X-lm = "X$arg"; then
+ case $host in
+ *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-beos* | *-cegcc* | *-*-haiku*)
+ # These systems don't actually have a C or math library (as such)
+ continue
+ ;;
+ *-*-os2*)
+ # These systems don't actually have a C library (as such)
+ test X-lc = "X$arg" && continue
+ ;;
+ *-*-openbsd* | *-*-freebsd* | *-*-dragonfly* | *-*-bitrig*)
+ # Do not include libc due to us having libc/libc_r.
+ test X-lc = "X$arg" && continue
+ ;;
+ *-*-rhapsody* | *-*-darwin1.[012])
+ # Rhapsody C and math libraries are in the System framework
+ func_append deplibs " System.ltframework"
+ continue
+ ;;
+ *-*-sco3.2v5* | *-*-sco5v6*)
+ # Causes problems with __ctype
+ test X-lc = "X$arg" && continue
+ ;;
+ *-*-sysv4.2uw2* | *-*-sysv5* | *-*-unixware* | *-*-OpenUNIX*)
+ # Compiler inserts libc in the correct place for threads to work
+ test X-lc = "X$arg" && continue
+ ;;
+ esac
+ elif test X-lc_r = "X$arg"; then
+ case $host in
+ *-*-openbsd* | *-*-freebsd* | *-*-dragonfly* | *-*-bitrig*)
+ # Do not include libc_r directly, use -pthread flag.
+ continue
+ ;;
+ esac
+ fi
+ func_append deplibs " $arg"
+ continue
+ ;;
+
+ -mllvm)
+ prev=mllvm
+ continue
+ ;;
+
+ -module)
+ module=yes
+ continue
+ ;;
+
+ # Tru64 UNIX uses -model [arg] to determine the layout of C++
+ # classes, name mangling, and exception handling.
+ # Darwin uses the -arch flag to determine output architecture.
+ -model|-arch|-isysroot|--sysroot)
+ func_append compiler_flags " $arg"
+ func_append compile_command " $arg"
+ func_append finalize_command " $arg"
+ prev=xcompiler
+ continue
+ ;;
+
+ -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe \
+ |-threads|-fopenmp|-openmp|-mp|-xopenmp|-omp|-qsmp=*)
+ func_append compiler_flags " $arg"
+ func_append compile_command " $arg"
+ func_append finalize_command " $arg"
+ case "$new_inherited_linker_flags " in
+ *" $arg "*) ;;
+ * ) func_append new_inherited_linker_flags " $arg" ;;
+ esac
+ continue
+ ;;
+
+ -multi_module)
+ single_module=$wl-multi_module
+ continue
+ ;;
+
+ -no-fast-install)
+ fast_install=no
+ continue
+ ;;
+
+ -no-install)
+ case $host in
+ *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-darwin* | *-cegcc*)
+ # The PATH hackery in wrapper scripts is required on Windows
+ # and Darwin in order for the loader to find any dlls it needs.
+ func_warning "'-no-install' is ignored for $host"
+ func_warning "assuming '-no-fast-install' instead"
+ fast_install=no
+ ;;
+ *) no_install=yes ;;
+ esac
+ continue
+ ;;
+
+ -no-undefined)
+ allow_undefined=no
+ continue
+ ;;
+
+ -objectlist)
+ prev=objectlist
+ continue
+ ;;
+
+ -os2dllname)
+ prev=os2dllname
+ continue
+ ;;
+
+ -o) prev=output ;;
+
+ -precious-files-regex)
+ prev=precious_regex
+ continue
+ ;;
+
+ -release)
+ prev=release
+ continue
+ ;;
+
+ -rpath)
+ prev=rpath
+ continue
+ ;;
+
+ -R)
+ prev=xrpath
+ continue
+ ;;
+
+ -R*)
+ func_stripname '-R' '' "$arg"
+ dir=$func_stripname_result
+ # We need an absolute path.
+ case $dir in
+ [\\/]* | [A-Za-z]:[\\/]*) ;;
+ =*)
+ func_stripname '=' '' "$dir"
+ dir=$lt_sysroot$func_stripname_result
+ ;;
+ *)
+ func_fatal_error "only absolute run-paths are allowed"
+ ;;
+ esac
+ case "$xrpath " in
+ *" $dir "*) ;;
+ *) func_append xrpath " $dir" ;;
+ esac
+ continue
+ ;;
+
+ -shared)
+ # The effects of -shared are defined in a previous loop.
+ continue
+ ;;
+
+ -shrext)
+ prev=shrext
+ continue
+ ;;
+
+ -static | -static-libtool-libs)
+ # The effects of -static are defined in a previous loop.
+ # We used to do the same as -all-static on platforms that
+ # didn't have a PIC flag, but the assumption that the effects
+ # would be equivalent was wrong. It would break on at least
+ # Digital Unix and AIX.
+ continue
+ ;;
+
+ -thread-safe)
+ thread_safe=yes
+ continue
+ ;;
+
+ -version-info)
+ prev=vinfo
+ continue
+ ;;
+
+ -version-number)
+ prev=vinfo
+ vinfo_number=yes
+ continue
+ ;;
+
+ -weak)
+ prev=weak
+ continue
+ ;;
+
+ -Wc,*)
+ func_stripname '-Wc,' '' "$arg"
+ args=$func_stripname_result
+ arg=
+ save_ifs=$IFS; IFS=,
+ for flag in $args; do
+ IFS=$save_ifs
+ func_quote_for_eval "$flag"
+ func_append arg " $func_quote_for_eval_result"
+ func_append compiler_flags " $func_quote_for_eval_result"
+ done
+ IFS=$save_ifs
+ func_stripname ' ' '' "$arg"
+ arg=$func_stripname_result
+ ;;
+
+ -Wl,*)
+ func_stripname '-Wl,' '' "$arg"
+ args=$func_stripname_result
+ arg=
+ save_ifs=$IFS; IFS=,
+ for flag in $args; do
+ IFS=$save_ifs
+ func_quote_for_eval "$flag"
+ func_append arg " $wl$func_quote_for_eval_result"
+ func_append compiler_flags " $wl$func_quote_for_eval_result"
+ func_append linker_flags " $func_quote_for_eval_result"
+ done
+ IFS=$save_ifs
+ func_stripname ' ' '' "$arg"
+ arg=$func_stripname_result
+ ;;
+
+ -Xcompiler)
+ prev=xcompiler
+ continue
+ ;;
+
+ -Xlinker)
+ prev=xlinker
+ continue
+ ;;
+
+ -XCClinker)
+ prev=xcclinker
+ continue
+ ;;
+
+ # -msg_* for osf cc
+ -msg_*)
+ func_quote_for_eval "$arg"
+ arg=$func_quote_for_eval_result
+ ;;
+
+ # Flags to be passed through unchanged, with rationale:
+ # -64, -mips[0-9] enable 64-bit mode for the SGI compiler
+ # -r[0-9][0-9]* specify processor for the SGI compiler
+ # -xarch=*, -xtarget=* enable 64-bit mode for the Sun compiler
+ # +DA*, +DD* enable 64-bit mode for the HP compiler
+ # -q* compiler args for the IBM compiler
+ # -m*, -t[45]*, -txscale* architecture-specific flags for GCC
+ # -F/path path to uninstalled frameworks, gcc on darwin
+ # -p, -pg, --coverage, -fprofile-* profiling flags for GCC
+ # -fstack-protector* stack protector flags for GCC
+ # @file GCC response files
+ # -tp=* Portland pgcc target processor selection
+ # --sysroot=* for sysroot support
+ # -O*, -g*, -flto*, -fwhopr*, -fuse-linker-plugin GCC link-time optimization
+ # -specs=* GCC specs files
+ # -stdlib=* select c++ std lib with clang
+ # -fsanitize=* Clang/GCC memory and address sanitizer
+ -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \
+ -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-tp=*|--sysroot=*| \
+ -O*|-g*|-flto*|-fwhopr*|-fuse-linker-plugin|-fstack-protector*|-stdlib=*| \
+ -specs=*|-fsanitize=*)
+ func_quote_for_eval "$arg"
+ arg=$func_quote_for_eval_result
+ func_append compile_command " $arg"
+ func_append finalize_command " $arg"
+ func_append compiler_flags " $arg"
+ continue
+ ;;
+
+ -Z*)
+ if test os2 = "`expr $host : '.*\(os2\)'`"; then
+ # OS/2 uses -Zxxx to specify OS/2-specific options
+ compiler_flags="$compiler_flags $arg"
+ func_append compile_command " $arg"
+ func_append finalize_command " $arg"
+ case $arg in
+ -Zlinker | -Zstack)
+ prev=xcompiler
+ ;;
+ esac
+ continue
+ else
+ # Otherwise treat like 'Some other compiler flag' below
+ func_quote_for_eval "$arg"
+ arg=$func_quote_for_eval_result
+ fi
+ ;;
+
+ # Some other compiler flag.
+ -* | +*)
+ func_quote_for_eval "$arg"
+ arg=$func_quote_for_eval_result
+ ;;
+
+ *.$objext)
+ # A standard object.
+ func_append objs " $arg"
+ ;;
+
+ *.lo)
+ # A libtool-controlled object.
+
+ # Check to see that this really is a libtool object.
+ if func_lalib_unsafe_p "$arg"; then
+ pic_object=
+ non_pic_object=
+
+ # Read the .lo file
+ func_source "$arg"
+
+ if test -z "$pic_object" ||
+ test -z "$non_pic_object" ||
+ test none = "$pic_object" &&
+ test none = "$non_pic_object"; then
+ func_fatal_error "cannot find name of object for '$arg'"
+ fi
+
+ # Extract subdirectory from the argument.
+ func_dirname "$arg" "/" ""
+ xdir=$func_dirname_result
+
+ test none = "$pic_object" || {
+ # Prepend the subdirectory the object is found in.
+ pic_object=$xdir$pic_object
+
+ if test dlfiles = "$prev"; then
+ if test yes = "$build_libtool_libs" && test yes = "$dlopen_support"; then
+ func_append dlfiles " $pic_object"
+ prev=
+ continue
+ else
+ # If libtool objects are unsupported, then we need to preload.
+ prev=dlprefiles
+ fi
+ fi
+
+ # CHECK ME: I think I busted this. -Ossama
+ if test dlprefiles = "$prev"; then
+ # Preload the old-style object.
+ func_append dlprefiles " $pic_object"
+ prev=
+ fi
+
+ # A PIC object.
+ func_append libobjs " $pic_object"
+ arg=$pic_object
+ }
+
+ # Non-PIC object.
+ if test none != "$non_pic_object"; then
+ # Prepend the subdirectory the object is found in.
+ non_pic_object=$xdir$non_pic_object
+
+ # A standard non-PIC object
+ func_append non_pic_objects " $non_pic_object"
+ if test -z "$pic_object" || test none = "$pic_object"; then
+ arg=$non_pic_object
+ fi
+ else
+ # If the PIC object exists, use it instead.
+ # $xdir was prepended to $pic_object above.
+ non_pic_object=$pic_object
+ func_append non_pic_objects " $non_pic_object"
+ fi
+ else
+ # Only an error if not doing a dry-run.
+ if $opt_dry_run; then
+ # Extract subdirectory from the argument.
+ func_dirname "$arg" "/" ""
+ xdir=$func_dirname_result
+
+ func_lo2o "$arg"
+ pic_object=$xdir$objdir/$func_lo2o_result
+ non_pic_object=$xdir$func_lo2o_result
+ func_append libobjs " $pic_object"
+ func_append non_pic_objects " $non_pic_object"
+ else
+ func_fatal_error "'$arg' is not a valid libtool object"
+ fi
+ fi
+ ;;
+
+ *.$libext)
+ # An archive.
+ func_append deplibs " $arg"
+ func_append old_deplibs " $arg"
+ continue
+ ;;
+
+ *.la)
+ # A libtool-controlled library.
+
+ func_resolve_sysroot "$arg"
+ if test dlfiles = "$prev"; then
+ # This library was specified with -dlopen.
+ func_append dlfiles " $func_resolve_sysroot_result"
+ prev=
+ elif test dlprefiles = "$prev"; then
+ # The library was specified with -dlpreopen.
+ func_append dlprefiles " $func_resolve_sysroot_result"
+ prev=
+ else
+ func_append deplibs " $func_resolve_sysroot_result"
+ fi
+ continue
+ ;;
+
+ # Some other compiler argument.
+ *)
+ # Unknown arguments in both finalize_command and compile_command need
+ # to be aesthetically quoted because they are evaled later.
+ func_quote_for_eval "$arg"
+ arg=$func_quote_for_eval_result
+ ;;
+ esac # arg
+
+ # Now actually substitute the argument into the commands.
+ if test -n "$arg"; then
+ func_append compile_command " $arg"
+ func_append finalize_command " $arg"
+ fi
+ done # argument parsing loop
+
+ test -n "$prev" && \
+ func_fatal_help "the '$prevarg' option requires an argument"
+
+ if test yes = "$export_dynamic" && test -n "$export_dynamic_flag_spec"; then
+ eval arg=\"$export_dynamic_flag_spec\"
+ func_append compile_command " $arg"
+ func_append finalize_command " $arg"
+ fi
+
+ oldlibs=
+ # calculate the name of the file, without its directory
+ func_basename "$output"
+ outputname=$func_basename_result
+ libobjs_save=$libobjs
+
+ if test -n "$shlibpath_var"; then
+ # get the directories listed in $shlibpath_var
+ eval shlib_search_path=\`\$ECHO \"\$$shlibpath_var\" \| \$SED \'s/:/ /g\'\`
+ else
+ shlib_search_path=
+ fi
+ eval sys_lib_search_path=\"$sys_lib_search_path_spec\"
+ eval sys_lib_dlsearch_path=\"$sys_lib_dlsearch_path_spec\"
+
+ # Definition is injected by LT_CONFIG during libtool generation.
+ func_munge_path_list sys_lib_dlsearch_path "$LT_SYS_LIBRARY_PATH"
+
+ func_dirname "$output" "/" ""
+ output_objdir=$func_dirname_result$objdir
+ func_to_tool_file "$output_objdir/"
+ tool_output_objdir=$func_to_tool_file_result
+ # Create the object directory.
+ func_mkdir_p "$output_objdir"
+
+ # Determine the type of output
+ case $output in
+ "")
+ func_fatal_help "you must specify an output file"
+ ;;
+ *.$libext) linkmode=oldlib ;;
+ *.lo | *.$objext) linkmode=obj ;;
+ *.la) linkmode=lib ;;
+ *) linkmode=prog ;; # Anything else should be a program.
+ esac
+
+ specialdeplibs=
+
+ libs=
+ # Find all interdependent deplibs by searching for libraries
+ # that are linked more than once (e.g. -la -lb -la)
+ for deplib in $deplibs; do
+ if $opt_preserve_dup_deps; then
+ case "$libs " in
+ *" $deplib "*) func_append specialdeplibs " $deplib" ;;
+ esac
+ fi
+ func_append libs " $deplib"
+ done
+
+ if test lib = "$linkmode"; then
+ libs="$predeps $libs $compiler_lib_search_path $postdeps"
+
+ # Compute libraries that are listed more than once in $predeps
+ # $postdeps and mark them as special (i.e., whose duplicates are
+ # not to be eliminated).
+ pre_post_deps=
+ if $opt_duplicate_compiler_generated_deps; then
+ for pre_post_dep in $predeps $postdeps; do
+ case "$pre_post_deps " in
+ *" $pre_post_dep "*) func_append specialdeplibs " $pre_post_deps" ;;
+ esac
+ func_append pre_post_deps " $pre_post_dep"
+ done
+ fi
+ pre_post_deps=
+ fi
+
+ deplibs=
+ newdependency_libs=
+ newlib_search_path=
+ need_relink=no # whether we're linking any uninstalled libtool libraries
+ notinst_deplibs= # not-installed libtool libraries
+ notinst_path= # paths that contain not-installed libtool libraries
+
+ case $linkmode in
+ lib)
+ passes="conv dlpreopen link"
+ for file in $dlfiles $dlprefiles; do
+ case $file in
+ *.la) ;;
+ *)
+ func_fatal_help "libraries can '-dlopen' only libtool libraries: $file"
+ ;;
+ esac
+ done
+ ;;
+ prog)
+ compile_deplibs=
+ finalize_deplibs=
+ alldeplibs=false
+ newdlfiles=
+ newdlprefiles=
+ passes="conv scan dlopen dlpreopen link"
+ ;;
+ *) passes="conv"
+ ;;
+ esac
+
+ for pass in $passes; do
+ # The preopen pass in lib mode reverses $deplibs; put it back here
+ # so that -L comes before libs that need it for instance...
+ if test lib,link = "$linkmode,$pass"; then
+ ## FIXME: Find the place where the list is rebuilt in the wrong
+ ## order, and fix it there properly
+ tmp_deplibs=
+ for deplib in $deplibs; do
+ tmp_deplibs="$deplib $tmp_deplibs"
+ done
+ deplibs=$tmp_deplibs
+ fi
+
+ if test lib,link = "$linkmode,$pass" ||
+ test prog,scan = "$linkmode,$pass"; then
+ libs=$deplibs
+ deplibs=
+ fi
+ if test prog = "$linkmode"; then
+ case $pass in
+ dlopen) libs=$dlfiles ;;
+ dlpreopen) libs=$dlprefiles ;;
+ link)
+ libs="$deplibs %DEPLIBS%"
+ test "X$link_all_deplibs" != Xno && libs="$libs $dependency_libs"
+ ;;
+ esac
+ fi
+ if test lib,dlpreopen = "$linkmode,$pass"; then
+ # Collect and forward deplibs of preopened libtool libs
+ for lib in $dlprefiles; do
+ # Ignore non-libtool-libs
+ dependency_libs=
+ func_resolve_sysroot "$lib"
+ case $lib in
+ *.la) func_source "$func_resolve_sysroot_result" ;;
+ esac
+
+ # Collect preopened libtool deplibs, except any this library
+ # has declared as weak libs
+ for deplib in $dependency_libs; do
+ func_basename "$deplib"
+ deplib_base=$func_basename_result
+ case " $weak_libs " in
+ *" $deplib_base "*) ;;
+ *) func_append deplibs " $deplib" ;;
+ esac
+ done
+ done
+ libs=$dlprefiles
+ fi
+ if test dlopen = "$pass"; then
+ # Collect dlpreopened libraries
+ save_deplibs=$deplibs
+ deplibs=
+ fi
+
+ for deplib in $libs; do
+ lib=
+ found=false
+ case $deplib in
+ -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe \
+ |-threads|-fopenmp|-openmp|-mp|-xopenmp|-omp|-qsmp=*)
+ if test prog,link = "$linkmode,$pass"; then
+ compile_deplibs="$deplib $compile_deplibs"
+ finalize_deplibs="$deplib $finalize_deplibs"
+ else
+ func_append compiler_flags " $deplib"
+ if test lib = "$linkmode"; then
+ case "$new_inherited_linker_flags " in
+ *" $deplib "*) ;;
+ * ) func_append new_inherited_linker_flags " $deplib" ;;
+ esac
+ fi
+ fi
+ continue
+ ;;
+ -l*)
+ if test lib != "$linkmode" && test prog != "$linkmode"; then
+ func_warning "'-l' is ignored for archives/objects"
+ continue
+ fi
+ func_stripname '-l' '' "$deplib"
+ name=$func_stripname_result
+ if test lib = "$linkmode"; then
+ searchdirs="$newlib_search_path $lib_search_path $compiler_lib_search_dirs $sys_lib_search_path $shlib_search_path"
+ else
+ searchdirs="$newlib_search_path $lib_search_path $sys_lib_search_path $shlib_search_path"
+ fi
+ for searchdir in $searchdirs; do
+ for search_ext in .la $std_shrext .so .a; do
+ # Search the libtool library
+ lib=$searchdir/lib$name$search_ext
+ if test -f "$lib"; then
+ if test .la = "$search_ext"; then
+ found=:
+ else
+ found=false
+ fi
+ break 2
+ fi
+ done
+ done
+ if $found; then
+ # deplib is a libtool library
+ # If $allow_libtool_libs_with_static_runtimes && $deplib is a stdlib,
+ # We need to do some special things here, and not later.
+ if test yes = "$allow_libtool_libs_with_static_runtimes"; then
+ case " $predeps $postdeps " in
+ *" $deplib "*)
+ if func_lalib_p "$lib"; then
+ library_names=
+ old_library=
+ func_source "$lib"
+ for l in $old_library $library_names; do
+ ll=$l
+ done
+ if test "X$ll" = "X$old_library"; then # only static version available
+ found=false
+ func_dirname "$lib" "" "."
+ ladir=$func_dirname_result
+ lib=$ladir/$old_library
+ if test prog,link = "$linkmode,$pass"; then
+ compile_deplibs="$deplib $compile_deplibs"
+ finalize_deplibs="$deplib $finalize_deplibs"
+ else
+ deplibs="$deplib $deplibs"
+ test lib = "$linkmode" && newdependency_libs="$deplib $newdependency_libs"
+ fi
+ continue
+ fi
+ fi
+ ;;
+ *) ;;
+ esac
+ fi
+ else
+ # deplib doesn't seem to be a libtool library
+ if test prog,link = "$linkmode,$pass"; then
+ compile_deplibs="$deplib $compile_deplibs"
+ finalize_deplibs="$deplib $finalize_deplibs"
+ else
+ deplibs="$deplib $deplibs"
+ test lib = "$linkmode" && newdependency_libs="$deplib $newdependency_libs"
+ fi
+ continue
+ fi
+ ;; # -l
+ *.ltframework)
+ if test prog,link = "$linkmode,$pass"; then
+ compile_deplibs="$deplib $compile_deplibs"
+ finalize_deplibs="$deplib $finalize_deplibs"
+ else
+ deplibs="$deplib $deplibs"
+ if test lib = "$linkmode"; then
+ case "$new_inherited_linker_flags " in
+ *" $deplib "*) ;;
+ * ) func_append new_inherited_linker_flags " $deplib" ;;
+ esac
+ fi
+ fi
+ continue
+ ;;
+ -L*)
+ case $linkmode in
+ lib)
+ deplibs="$deplib $deplibs"
+ test conv = "$pass" && continue
+ newdependency_libs="$deplib $newdependency_libs"
+ func_stripname '-L' '' "$deplib"
+ func_resolve_sysroot "$func_stripname_result"
+ func_append newlib_search_path " $func_resolve_sysroot_result"
+ ;;
+ prog)
+ if test conv = "$pass"; then
+ deplibs="$deplib $deplibs"
+ continue
+ fi
+ if test scan = "$pass"; then
+ deplibs="$deplib $deplibs"
+ else
+ compile_deplibs="$deplib $compile_deplibs"
+ finalize_deplibs="$deplib $finalize_deplibs"
+ fi
+ func_stripname '-L' '' "$deplib"
+ func_resolve_sysroot "$func_stripname_result"
+ func_append newlib_search_path " $func_resolve_sysroot_result"
+ ;;
+ *)
+ func_warning "'-L' is ignored for archives/objects"
+ ;;
+ esac # linkmode
+ continue
+ ;; # -L
+ -R*)
+ if test link = "$pass"; then
+ func_stripname '-R' '' "$deplib"
+ func_resolve_sysroot "$func_stripname_result"
+ dir=$func_resolve_sysroot_result
+ # Make sure the xrpath contains only unique directories.
+ case "$xrpath " in
+ *" $dir "*) ;;
+ *) func_append xrpath " $dir" ;;
+ esac
+ fi
+ deplibs="$deplib $deplibs"
+ continue
+ ;;
+ *.la)
+ func_resolve_sysroot "$deplib"
+ lib=$func_resolve_sysroot_result
+ ;;
+ *.$libext)
+ if test conv = "$pass"; then
+ deplibs="$deplib $deplibs"
+ continue
+ fi
+ case $linkmode in
+ lib)
+ # Linking convenience modules into shared libraries is allowed,
+ # but linking other static libraries is non-portable.
+ case " $dlpreconveniencelibs " in
+ *" $deplib "*) ;;
+ *)
+ valid_a_lib=false
+ case $deplibs_check_method in
+ match_pattern*)
+ set dummy $deplibs_check_method; shift
+ match_pattern_regex=`expr "$deplibs_check_method" : "$1 \(.*\)"`
+ if eval "\$ECHO \"$deplib\"" 2>/dev/null | $SED 10q \
+ | $EGREP "$match_pattern_regex" > /dev/null; then
+ valid_a_lib=:
+ fi
+ ;;
+ pass_all)
+ valid_a_lib=:
+ ;;
+ esac
+ if $valid_a_lib; then
+ echo
+ $ECHO "*** Warning: Linking the shared library $output against the"
+ $ECHO "*** static library $deplib is not portable!"
+ deplibs="$deplib $deplibs"
+ else
+ echo
+ $ECHO "*** Warning: Trying to link with static lib archive $deplib."
+ echo "*** I have the capability to make that library automatically link in when"
+ echo "*** you link to this library. But I can only do this if you have a"
+ echo "*** shared version of the library, which you do not appear to have"
+ echo "*** because the file extensions .$libext of this argument makes me believe"
+ echo "*** that it is just a static archive that I should not use here."
+ fi
+ ;;
+ esac
+ continue
+ ;;
+ prog)
+ if test link != "$pass"; then
+ deplibs="$deplib $deplibs"
+ else
+ compile_deplibs="$deplib $compile_deplibs"
+ finalize_deplibs="$deplib $finalize_deplibs"
+ fi
+ continue
+ ;;
+ esac # linkmode
+ ;; # *.$libext
+ *.lo | *.$objext)
+ if test conv = "$pass"; then
+ deplibs="$deplib $deplibs"
+ elif test prog = "$linkmode"; then
+ if test dlpreopen = "$pass" || test yes != "$dlopen_support" || test no = "$build_libtool_libs"; then
+ # If there is no dlopen support or we're linking statically,
+ # we need to preload.
+ func_append newdlprefiles " $deplib"
+ compile_deplibs="$deplib $compile_deplibs"
+ finalize_deplibs="$deplib $finalize_deplibs"
+ else
+ func_append newdlfiles " $deplib"
+ fi
+ fi
+ continue
+ ;;
+ %DEPLIBS%)
+ alldeplibs=:
+ continue
+ ;;
+ esac # case $deplib
+
+ $found || test -f "$lib" \
+ || func_fatal_error "cannot find the library '$lib' or unhandled argument '$deplib'"
+
+ # Check to see that this really is a libtool archive.
+ func_lalib_unsafe_p "$lib" \
+ || func_fatal_error "'$lib' is not a valid libtool archive"
+
+ func_dirname "$lib" "" "."
+ ladir=$func_dirname_result
+
+ dlname=
+ dlopen=
+ dlpreopen=
+ libdir=
+ library_names=
+ old_library=
+ inherited_linker_flags=
+ # If the library was installed with an old release of libtool,
+ # it will not redefine variables installed, or shouldnotlink
+ installed=yes
+ shouldnotlink=no
+ avoidtemprpath=
+
+
+ # Read the .la file
+ func_source "$lib"
+
+ # Convert "-framework foo" to "foo.ltframework"
+ if test -n "$inherited_linker_flags"; then
+ tmp_inherited_linker_flags=`$ECHO "$inherited_linker_flags" | $SED 's/-framework \([^ $]*\)/\1.ltframework/g'`
+ for tmp_inherited_linker_flag in $tmp_inherited_linker_flags; do
+ case " $new_inherited_linker_flags " in
+ *" $tmp_inherited_linker_flag "*) ;;
+ *) func_append new_inherited_linker_flags " $tmp_inherited_linker_flag";;
+ esac
+ done
+ fi
+ dependency_libs=`$ECHO " $dependency_libs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'`
+ if test lib,link = "$linkmode,$pass" ||
+ test prog,scan = "$linkmode,$pass" ||
+ { test prog != "$linkmode" && test lib != "$linkmode"; }; then
+ test -n "$dlopen" && func_append dlfiles " $dlopen"
+ test -n "$dlpreopen" && func_append dlprefiles " $dlpreopen"
+ fi
+
+ if test conv = "$pass"; then
+ # Only check for convenience libraries
+ deplibs="$lib $deplibs"
+ if test -z "$libdir"; then
+ if test -z "$old_library"; then
+ func_fatal_error "cannot find name of link library for '$lib'"
+ fi
+ # It is a libtool convenience library, so add in its objects.
+ func_append convenience " $ladir/$objdir/$old_library"
+ func_append old_convenience " $ladir/$objdir/$old_library"
+ tmp_libs=
+ for deplib in $dependency_libs; do
+ deplibs="$deplib $deplibs"
+ if $opt_preserve_dup_deps; then
+ case "$tmp_libs " in
+ *" $deplib "*) func_append specialdeplibs " $deplib" ;;
+ esac
+ fi
+ func_append tmp_libs " $deplib"
+ done
+ elif test prog != "$linkmode" && test lib != "$linkmode"; then
+ func_fatal_error "'$lib' is not a convenience library"
+ fi
+ continue
+ fi # $pass = conv
+
+
+ # Get the name of the library we link against.
+ linklib=
+ if test -n "$old_library" &&
+ { test yes = "$prefer_static_libs" ||
+ test built,no = "$prefer_static_libs,$installed"; }; then
+ linklib=$old_library
+ else
+ for l in $old_library $library_names; do
+ linklib=$l
+ done
+ fi
+ if test -z "$linklib"; then
+ func_fatal_error "cannot find name of link library for '$lib'"
+ fi
+
+ # This library was specified with -dlopen.
+ if test dlopen = "$pass"; then
+ test -z "$libdir" \
+ && func_fatal_error "cannot -dlopen a convenience library: '$lib'"
+ if test -z "$dlname" ||
+ test yes != "$dlopen_support" ||
+ test no = "$build_libtool_libs"
+ then
+ # If there is no dlname, no dlopen support or we're linking
+ # statically, we need to preload. We also need to preload any
+ # dependent libraries so libltdl's deplib preloader doesn't
+ # bomb out in the load deplibs phase.
+ func_append dlprefiles " $lib $dependency_libs"
+ else
+ func_append newdlfiles " $lib"
+ fi
+ continue
+ fi # $pass = dlopen
+
+ # We need an absolute path.
+ case $ladir in
+ [\\/]* | [A-Za-z]:[\\/]*) abs_ladir=$ladir ;;
+ *)
+ abs_ladir=`cd "$ladir" && pwd`
+ if test -z "$abs_ladir"; then
+ func_warning "cannot determine absolute directory name of '$ladir'"
+ func_warning "passing it literally to the linker, although it might fail"
+ abs_ladir=$ladir
+ fi
+ ;;
+ esac
+ func_basename "$lib"
+ laname=$func_basename_result
+
+ # Find the relevant object directory and library name.
+ if test yes = "$installed"; then
+ if test ! -f "$lt_sysroot$libdir/$linklib" && test -f "$abs_ladir/$linklib"; then
+ func_warning "library '$lib' was moved."
+ dir=$ladir
+ absdir=$abs_ladir
+ libdir=$abs_ladir
+ else
+ dir=$lt_sysroot$libdir
+ absdir=$lt_sysroot$libdir
+ fi
+ test yes = "$hardcode_automatic" && avoidtemprpath=yes
+ else
+ if test ! -f "$ladir/$objdir/$linklib" && test -f "$abs_ladir/$linklib"; then
+ dir=$ladir
+ absdir=$abs_ladir
+ # Remove this search path later
+ func_append notinst_path " $abs_ladir"
+ else
+ dir=$ladir/$objdir
+ absdir=$abs_ladir/$objdir
+ # Remove this search path later
+ func_append notinst_path " $abs_ladir"
+ fi
+ fi # $installed = yes
+ func_stripname 'lib' '.la' "$laname"
+ name=$func_stripname_result
+
+ # This library was specified with -dlpreopen.
+ if test dlpreopen = "$pass"; then
+ if test -z "$libdir" && test prog = "$linkmode"; then
+ func_fatal_error "only libraries may -dlpreopen a convenience library: '$lib'"
+ fi
+ case $host in
+ # special handling for platforms with PE-DLLs.
+ *cygwin* | *mingw* | *cegcc* )
+ # Linker will automatically link against shared library if both
+ # static and shared are present. Therefore, ensure we extract
+ # symbols from the import library if a shared library is present
+ # (otherwise, the dlopen module name will be incorrect). We do
+ # this by putting the import library name into $newdlprefiles.
+ # We recover the dlopen module name by 'saving' the la file
+ # name in a special purpose variable, and (later) extracting the
+ # dlname from the la file.
+ if test -n "$dlname"; then
+ func_tr_sh "$dir/$linklib"
+ eval "libfile_$func_tr_sh_result=\$abs_ladir/\$laname"
+ func_append newdlprefiles " $dir/$linklib"
+ else
+ func_append newdlprefiles " $dir/$old_library"
+ # Keep a list of preopened convenience libraries to check
+ # that they are being used correctly in the link pass.
+ test -z "$libdir" && \
+ func_append dlpreconveniencelibs " $dir/$old_library"
+ fi
+ ;;
+ * )
+ # Prefer using a static library (so that no silly _DYNAMIC symbols
+ # are required to link).
+ if test -n "$old_library"; then
+ func_append newdlprefiles " $dir/$old_library"
+ # Keep a list of preopened convenience libraries to check
+ # that they are being used correctly in the link pass.
+ test -z "$libdir" && \
+ func_append dlpreconveniencelibs " $dir/$old_library"
+ # Otherwise, use the dlname, so that lt_dlopen finds it.
+ elif test -n "$dlname"; then
+ func_append newdlprefiles " $dir/$dlname"
+ else
+ func_append newdlprefiles " $dir/$linklib"
+ fi
+ ;;
+ esac
+ fi # $pass = dlpreopen
+
+ if test -z "$libdir"; then
+ # Link the convenience library
+ if test lib = "$linkmode"; then
+ deplibs="$dir/$old_library $deplibs"
+ elif test prog,link = "$linkmode,$pass"; then
+ compile_deplibs="$dir/$old_library $compile_deplibs"
+ finalize_deplibs="$dir/$old_library $finalize_deplibs"
+ else
+ deplibs="$lib $deplibs" # used for prog,scan pass
+ fi
+ continue
+ fi
+
+
+ if test prog = "$linkmode" && test link != "$pass"; then
+ func_append newlib_search_path " $ladir"
+ deplibs="$lib $deplibs"
+
+ linkalldeplibs=false
+ if test no != "$link_all_deplibs" || test -z "$library_names" ||
+ test no = "$build_libtool_libs"; then
+ linkalldeplibs=:
+ fi
+
+ tmp_libs=
+ for deplib in $dependency_libs; do
+ case $deplib in
+ -L*) func_stripname '-L' '' "$deplib"
+ func_resolve_sysroot "$func_stripname_result"
+ func_append newlib_search_path " $func_resolve_sysroot_result"
+ ;;
+ esac
+ # Need to link against all dependency_libs?
+ if $linkalldeplibs; then
+ deplibs="$deplib $deplibs"
+ else
+ # Need to hardcode shared library paths
+ # or/and link against static libraries
+ newdependency_libs="$deplib $newdependency_libs"
+ fi
+ if $opt_preserve_dup_deps; then
+ case "$tmp_libs " in
+ *" $deplib "*) func_append specialdeplibs " $deplib" ;;
+ esac
+ fi
+ func_append tmp_libs " $deplib"
+ done # for deplib
+ continue
+ fi # $linkmode = prog...
+
+ if test prog,link = "$linkmode,$pass"; then
+ if test -n "$library_names" &&
+ { { test no = "$prefer_static_libs" ||
+ test built,yes = "$prefer_static_libs,$installed"; } ||
+ test -z "$old_library"; }; then
+ # We need to hardcode the library path
+ if test -n "$shlibpath_var" && test -z "$avoidtemprpath"; then
+ # Make sure the rpath contains only unique directories.
+ case $temp_rpath: in
+ *"$absdir:"*) ;;
+ *) func_append temp_rpath "$absdir:" ;;
+ esac
+ fi
+
+ # Hardcode the library path.
+ # Skip directories that are in the system default run-time
+ # search path.
+ case " $sys_lib_dlsearch_path " in
+ *" $absdir "*) ;;
+ *)
+ case "$compile_rpath " in
+ *" $absdir "*) ;;
+ *) func_append compile_rpath " $absdir" ;;
+ esac
+ ;;
+ esac
+ case " $sys_lib_dlsearch_path " in
+ *" $libdir "*) ;;
+ *)
+ case "$finalize_rpath " in
+ *" $libdir "*) ;;
+ *) func_append finalize_rpath " $libdir" ;;
+ esac
+ ;;
+ esac
+ fi # $linkmode,$pass = prog,link...
+
+ if $alldeplibs &&
+ { test pass_all = "$deplibs_check_method" ||
+ { test yes = "$build_libtool_libs" &&
+ test -n "$library_names"; }; }; then
+ # We only need to search for static libraries
+ continue
+ fi
+ fi
+
+ link_static=no # Whether the deplib will be linked statically
+ use_static_libs=$prefer_static_libs
+ if test built = "$use_static_libs" && test yes = "$installed"; then
+ use_static_libs=no
+ fi
+ if test -n "$library_names" &&
+ { test no = "$use_static_libs" || test -z "$old_library"; }; then
+ case $host in
+ *cygwin* | *mingw* | *cegcc* | *os2*)
+ # No point in relinking DLLs because paths are not encoded
+ func_append notinst_deplibs " $lib"
+ need_relink=no
+ ;;
+ *)
+ if test no = "$installed"; then
+ func_append notinst_deplibs " $lib"
+ need_relink=yes
+ fi
+ ;;
+ esac
+ # This is a shared library
+
+ # Warn about portability, can't link against -module's on some
+ # systems (darwin). Don't bleat about dlopened modules though!
+ dlopenmodule=
+ for dlpremoduletest in $dlprefiles; do
+ if test "X$dlpremoduletest" = "X$lib"; then
+ dlopenmodule=$dlpremoduletest
+ break
+ fi
+ done
+ if test -z "$dlopenmodule" && test yes = "$shouldnotlink" && test link = "$pass"; then
+ echo
+ if test prog = "$linkmode"; then
+ $ECHO "*** Warning: Linking the executable $output against the loadable module"
+ else
+ $ECHO "*** Warning: Linking the shared library $output against the loadable module"
+ fi
+ $ECHO "*** $linklib is not portable!"
+ fi
+ if test lib = "$linkmode" &&
+ test yes = "$hardcode_into_libs"; then
+ # Hardcode the library path.
+ # Skip directories that are in the system default run-time
+ # search path.
+ case " $sys_lib_dlsearch_path " in
+ *" $absdir "*) ;;
+ *)
+ case "$compile_rpath " in
+ *" $absdir "*) ;;
+ *) func_append compile_rpath " $absdir" ;;
+ esac
+ ;;
+ esac
+ case " $sys_lib_dlsearch_path " in
+ *" $libdir "*) ;;
+ *)
+ case "$finalize_rpath " in
+ *" $libdir "*) ;;
+ *) func_append finalize_rpath " $libdir" ;;
+ esac
+ ;;
+ esac
+ fi
+
+ if test -n "$old_archive_from_expsyms_cmds"; then
+ # figure out the soname
+ set dummy $library_names
+ shift
+ realname=$1
+ shift
+ libname=`eval "\\$ECHO \"$libname_spec\""`
+ # use dlname if we got it. it's perfectly good, no?
+ if test -n "$dlname"; then
+ soname=$dlname
+ elif test -n "$soname_spec"; then
+ # bleh windows
+ case $host in
+ *cygwin* | mingw* | *cegcc* | *os2*)
+ func_arith $current - $age
+ major=$func_arith_result
+ versuffix=-$major
+ ;;
+ esac
+ eval soname=\"$soname_spec\"
+ else
+ soname=$realname
+ fi
+
+ # Make a new name for the extract_expsyms_cmds to use
+ soroot=$soname
+ func_basename "$soroot"
+ soname=$func_basename_result
+ func_stripname 'lib' '.dll' "$soname"
+ newlib=libimp-$func_stripname_result.a
+
+ # If the library has no export list, then create one now
+ if test -f "$output_objdir/$soname-def"; then :
+ else
+ func_verbose "extracting exported symbol list from '$soname'"
+ func_execute_cmds "$extract_expsyms_cmds" 'exit $?'
+ fi
+
+ # Create $newlib
+ if test -f "$output_objdir/$newlib"; then :; else
+ func_verbose "generating import library for '$soname'"
+ func_execute_cmds "$old_archive_from_expsyms_cmds" 'exit $?'
+ fi
+ # make sure the library variables are pointing to the new library
+ dir=$output_objdir
+ linklib=$newlib
+ fi # test -n "$old_archive_from_expsyms_cmds"
+
+ if test prog = "$linkmode" || test relink != "$opt_mode"; then
+ add_shlibpath=
+ add_dir=
+ add=
+ lib_linked=yes
+ case $hardcode_action in
+ immediate | unsupported)
+ if test no = "$hardcode_direct"; then
+ add=$dir/$linklib
+ case $host in
+ *-*-sco3.2v5.0.[024]*) add_dir=-L$dir ;;
+ *-*-sysv4*uw2*) add_dir=-L$dir ;;
+ *-*-sysv5OpenUNIX* | *-*-sysv5UnixWare7.[01].[10]* | \
+ *-*-unixware7*) add_dir=-L$dir ;;
+ *-*-darwin* )
+ # if the lib is a (non-dlopened) module then we cannot
+ # link against it, someone is ignoring the earlier warnings
+ if /usr/bin/file -L $add 2> /dev/null |
+ $GREP ": [^:]* bundle" >/dev/null; then
+ if test "X$dlopenmodule" != "X$lib"; then
+ $ECHO "*** Warning: lib $linklib is a module, not a shared library"
+ if test -z "$old_library"; then
+ echo
+ echo "*** And there doesn't seem to be a static archive available"
+ echo "*** The link will probably fail, sorry"
+ else
+ add=$dir/$old_library
+ fi
+ elif test -n "$old_library"; then
+ add=$dir/$old_library
+ fi
+ fi
+ esac
+ elif test no = "$hardcode_minus_L"; then
+ case $host in
+ *-*-sunos*) add_shlibpath=$dir ;;
+ esac
+ add_dir=-L$dir
+ add=-l$name
+ elif test no = "$hardcode_shlibpath_var"; then
+ add_shlibpath=$dir
+ add=-l$name
+ else
+ lib_linked=no
+ fi
+ ;;
+ relink)
+ if test yes = "$hardcode_direct" &&
+ test no = "$hardcode_direct_absolute"; then
+ add=$dir/$linklib
+ elif test yes = "$hardcode_minus_L"; then
+ add_dir=-L$absdir
+ # Try looking first in the location we're being installed to.
+ if test -n "$inst_prefix_dir"; then
+ case $libdir in
+ [\\/]*)
+ func_append add_dir " -L$inst_prefix_dir$libdir"
+ ;;
+ esac
+ fi
+ add=-l$name
+ elif test yes = "$hardcode_shlibpath_var"; then
+ add_shlibpath=$dir
+ add=-l$name
+ else
+ lib_linked=no
+ fi
+ ;;
+ *) lib_linked=no ;;
+ esac
+
+ if test yes != "$lib_linked"; then
+ func_fatal_configuration "unsupported hardcode properties"
+ fi
+
+ if test -n "$add_shlibpath"; then
+ case :$compile_shlibpath: in
+ *":$add_shlibpath:"*) ;;
+ *) func_append compile_shlibpath "$add_shlibpath:" ;;
+ esac
+ fi
+ if test prog = "$linkmode"; then
+ test -n "$add_dir" && compile_deplibs="$add_dir $compile_deplibs"
+ test -n "$add" && compile_deplibs="$add $compile_deplibs"
+ else
+ test -n "$add_dir" && deplibs="$add_dir $deplibs"
+ test -n "$add" && deplibs="$add $deplibs"
+ if test yes != "$hardcode_direct" &&
+ test yes != "$hardcode_minus_L" &&
+ test yes = "$hardcode_shlibpath_var"; then
+ case :$finalize_shlibpath: in
+ *":$libdir:"*) ;;
+ *) func_append finalize_shlibpath "$libdir:" ;;
+ esac
+ fi
+ fi
+ fi
+
+ if test prog = "$linkmode" || test relink = "$opt_mode"; then
+ add_shlibpath=
+ add_dir=
+ add=
+ # Finalize command for both is simple: just hardcode it.
+ if test yes = "$hardcode_direct" &&
+ test no = "$hardcode_direct_absolute"; then
+ add=$libdir/$linklib
+ elif test yes = "$hardcode_minus_L"; then
+ add_dir=-L$libdir
+ add=-l$name
+ elif test yes = "$hardcode_shlibpath_var"; then
+ case :$finalize_shlibpath: in
+ *":$libdir:"*) ;;
+ *) func_append finalize_shlibpath "$libdir:" ;;
+ esac
+ add=-l$name
+ elif test yes = "$hardcode_automatic"; then
+ if test -n "$inst_prefix_dir" &&
+ test -f "$inst_prefix_dir$libdir/$linklib"; then
+ add=$inst_prefix_dir$libdir/$linklib
+ else
+ add=$libdir/$linklib
+ fi
+ else
+ # We cannot seem to hardcode it, guess we'll fake it.
+ add_dir=-L$libdir
+ # Try looking first in the location we're being installed to.
+ if test -n "$inst_prefix_dir"; then
+ case $libdir in
+ [\\/]*)
+ func_append add_dir " -L$inst_prefix_dir$libdir"
+ ;;
+ esac
+ fi
+ add=-l$name
+ fi
+
+ if test prog = "$linkmode"; then
+ test -n "$add_dir" && finalize_deplibs="$add_dir $finalize_deplibs"
+ test -n "$add" && finalize_deplibs="$add $finalize_deplibs"
+ else
+ test -n "$add_dir" && deplibs="$add_dir $deplibs"
+ test -n "$add" && deplibs="$add $deplibs"
+ fi
+ fi
+ elif test prog = "$linkmode"; then
+ # Here we assume that one of hardcode_direct or hardcode_minus_L
+ # is not unsupported. This is valid on all known static and
+ # shared platforms.
+ if test unsupported != "$hardcode_direct"; then
+ test -n "$old_library" && linklib=$old_library
+ compile_deplibs="$dir/$linklib $compile_deplibs"
+ finalize_deplibs="$dir/$linklib $finalize_deplibs"
+ else
+ compile_deplibs="-l$name -L$dir $compile_deplibs"
+ finalize_deplibs="-l$name -L$dir $finalize_deplibs"
+ fi
+ elif test yes = "$build_libtool_libs"; then
+ # Not a shared library
+ if test pass_all != "$deplibs_check_method"; then
+ # We're trying link a shared library against a static one
+ # but the system doesn't support it.
+
+ # Just print a warning and add the library to dependency_libs so
+ # that the program can be linked against the static library.
+ echo
+ $ECHO "*** Warning: This system cannot link to static lib archive $lib."
+ echo "*** I have the capability to make that library automatically link in when"
+ echo "*** you link to this library. But I can only do this if you have a"
+ echo "*** shared version of the library, which you do not appear to have."
+ if test yes = "$module"; then
+ echo "*** But as you try to build a module library, libtool will still create "
+ echo "*** a static module, that should work as long as the dlopening application"
+ echo "*** is linked with the -dlopen flag to resolve symbols at runtime."
+ if test -z "$global_symbol_pipe"; then
+ echo
+ echo "*** However, this would only work if libtool was able to extract symbol"
+ echo "*** lists from a program, using 'nm' or equivalent, but libtool could"
+ echo "*** not find such a program. So, this module is probably useless."
+ echo "*** 'nm' from GNU binutils and a full rebuild may help."
+ fi
+ if test no = "$build_old_libs"; then
+ build_libtool_libs=module
+ build_old_libs=yes
+ else
+ build_libtool_libs=no
+ fi
+ fi
+ else
+ deplibs="$dir/$old_library $deplibs"
+ link_static=yes
+ fi
+ fi # link shared/static library?
+
+ if test lib = "$linkmode"; then
+ if test -n "$dependency_libs" &&
+ { test yes != "$hardcode_into_libs" ||
+ test yes = "$build_old_libs" ||
+ test yes = "$link_static"; }; then
+ # Extract -R from dependency_libs
+ temp_deplibs=
+ for libdir in $dependency_libs; do
+ case $libdir in
+ -R*) func_stripname '-R' '' "$libdir"
+ temp_xrpath=$func_stripname_result
+ case " $xrpath " in
+ *" $temp_xrpath "*) ;;
+ *) func_append xrpath " $temp_xrpath";;
+ esac;;
+ *) func_append temp_deplibs " $libdir";;
+ esac
+ done
+ dependency_libs=$temp_deplibs
+ fi
+
+ func_append newlib_search_path " $absdir"
+ # Link against this library
+ test no = "$link_static" && newdependency_libs="$abs_ladir/$laname $newdependency_libs"
+ # ... and its dependency_libs
+ tmp_libs=
+ for deplib in $dependency_libs; do
+ newdependency_libs="$deplib $newdependency_libs"
+ case $deplib in
+ -L*) func_stripname '-L' '' "$deplib"
+ func_resolve_sysroot "$func_stripname_result";;
+ *) func_resolve_sysroot "$deplib" ;;
+ esac
+ if $opt_preserve_dup_deps; then
+ case "$tmp_libs " in
+ *" $func_resolve_sysroot_result "*)
+ func_append specialdeplibs " $func_resolve_sysroot_result" ;;
+ esac
+ fi
+ func_append tmp_libs " $func_resolve_sysroot_result"
+ done
+
+ if test no != "$link_all_deplibs"; then
+ # Add the search paths of all dependency libraries
+ for deplib in $dependency_libs; do
+ path=
+ case $deplib in
+ -L*) path=$deplib ;;
+ *.la)
+ func_resolve_sysroot "$deplib"
+ deplib=$func_resolve_sysroot_result
+ func_dirname "$deplib" "" "."
+ dir=$func_dirname_result
+ # We need an absolute path.
+ case $dir in
+ [\\/]* | [A-Za-z]:[\\/]*) absdir=$dir ;;
+ *)
+ absdir=`cd "$dir" && pwd`
+ if test -z "$absdir"; then
+ func_warning "cannot determine absolute directory name of '$dir'"
+ absdir=$dir
+ fi
+ ;;
+ esac
+ if $GREP "^installed=no" $deplib > /dev/null; then
+ case $host in
+ *-*-darwin*)
+ depdepl=
+ eval deplibrary_names=`$SED -n -e 's/^library_names=\(.*\)$/\1/p' $deplib`
+ if test -n "$deplibrary_names"; then
+ for tmp in $deplibrary_names; do
+ depdepl=$tmp
+ done
+ if test -f "$absdir/$objdir/$depdepl"; then
+ depdepl=$absdir/$objdir/$depdepl
+ darwin_install_name=`$OTOOL -L $depdepl | awk '{if (NR == 2) {print $1;exit}}'`
+ if test -z "$darwin_install_name"; then
+ darwin_install_name=`$OTOOL64 -L $depdepl | awk '{if (NR == 2) {print $1;exit}}'`
+ fi
+ func_append compiler_flags " $wl-dylib_file $wl$darwin_install_name:$depdepl"
+ func_append linker_flags " -dylib_file $darwin_install_name:$depdepl"
+ path=
+ fi
+ fi
+ ;;
+ *)
+ path=-L$absdir/$objdir
+ ;;
+ esac
+ else
+ eval libdir=`$SED -n -e 's/^libdir=\(.*\)$/\1/p' $deplib`
+ test -z "$libdir" && \
+ func_fatal_error "'$deplib' is not a valid libtool archive"
+ test "$absdir" != "$libdir" && \
+ func_warning "'$deplib' seems to be moved"
+
+ path=-L$absdir
+ fi
+ ;;
+ esac
+ case " $deplibs " in
+ *" $path "*) ;;
+ *) deplibs="$path $deplibs" ;;
+ esac
+ done
+ fi # link_all_deplibs != no
+ fi # linkmode = lib
+ done # for deplib in $libs
+ if test link = "$pass"; then
+ if test prog = "$linkmode"; then
+ compile_deplibs="$new_inherited_linker_flags $compile_deplibs"
+ finalize_deplibs="$new_inherited_linker_flags $finalize_deplibs"
+ else
+ compiler_flags="$compiler_flags "`$ECHO " $new_inherited_linker_flags" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'`
+ fi
+ fi
+ dependency_libs=$newdependency_libs
+ if test dlpreopen = "$pass"; then
+ # Link the dlpreopened libraries before other libraries
+ for deplib in $save_deplibs; do
+ deplibs="$deplib $deplibs"
+ done
+ fi
+ if test dlopen != "$pass"; then
+ test conv = "$pass" || {
+ # Make sure lib_search_path contains only unique directories.
+ lib_search_path=
+ for dir in $newlib_search_path; do
+ case "$lib_search_path " in
+ *" $dir "*) ;;
+ *) func_append lib_search_path " $dir" ;;
+ esac
+ done
+ newlib_search_path=
+ }
+
+ if test prog,link = "$linkmode,$pass"; then
+ vars="compile_deplibs finalize_deplibs"
+ else
+ vars=deplibs
+ fi
+ for var in $vars dependency_libs; do
+ # Add libraries to $var in reverse order
+ eval tmp_libs=\"\$$var\"
+ new_libs=
+ for deplib in $tmp_libs; do
+ # FIXME: Pedantically, this is the right thing to do, so
+ # that some nasty dependency loop isn't accidentally
+ # broken:
+ #new_libs="$deplib $new_libs"
+ # Pragmatically, this seems to cause very few problems in
+ # practice:
+ case $deplib in
+ -L*) new_libs="$deplib $new_libs" ;;
+ -R*) ;;
+ *)
+ # And here is the reason: when a library appears more
+ # than once as an explicit dependence of a library, or
+ # is implicitly linked in more than once by the
+ # compiler, it is considered special, and multiple
+ # occurrences thereof are not removed. Compare this
+ # with having the same library being listed as a
+ # dependency of multiple other libraries: in this case,
+ # we know (pedantically, we assume) the library does not
+ # need to be listed more than once, so we keep only the
+ # last copy. This is not always right, but it is rare
+ # enough that we require users that really mean to play
+ # such unportable linking tricks to link the library
+ # using -Wl,-lname, so that libtool does not consider it
+ # for duplicate removal.
+ case " $specialdeplibs " in
+ *" $deplib "*) new_libs="$deplib $new_libs" ;;
+ *)
+ case " $new_libs " in
+ *" $deplib "*) ;;
+ *) new_libs="$deplib $new_libs" ;;
+ esac
+ ;;
+ esac
+ ;;
+ esac
+ done
+ tmp_libs=
+ for deplib in $new_libs; do
+ case $deplib in
+ -L*)
+ case " $tmp_libs " in
+ *" $deplib "*) ;;
+ *) func_append tmp_libs " $deplib" ;;
+ esac
+ ;;
+ *) func_append tmp_libs " $deplib" ;;
+ esac
+ done
+ eval $var=\"$tmp_libs\"
+ done # for var
+ fi
+
+ # Add Sun CC postdeps if required:
+ test CXX = "$tagname" && {
+ case $host_os in
+ linux*)
+ case `$CC -V 2>&1 | sed 5q` in
+ *Sun\ C*) # Sun C++ 5.9
+ func_suncc_cstd_abi
+
+ if test no != "$suncc_use_cstd_abi"; then
+ func_append postdeps ' -library=Cstd -library=Crun'
+ fi
+ ;;
+ esac
+ ;;
+
+ solaris*)
+ func_cc_basename "$CC"
+ case $func_cc_basename_result in
+ CC* | sunCC*)
+ func_suncc_cstd_abi
+
+ if test no != "$suncc_use_cstd_abi"; then
+ func_append postdeps ' -library=Cstd -library=Crun'
+ fi
+ ;;
+ esac
+ ;;
+ esac
+ }
+
+ # Last step: remove runtime libs from dependency_libs
+ # (they stay in deplibs)
+ tmp_libs=
+ for i in $dependency_libs; do
+ case " $predeps $postdeps $compiler_lib_search_path " in
+ *" $i "*)
+ i=
+ ;;
+ esac
+ if test -n "$i"; then
+ func_append tmp_libs " $i"
+ fi
+ done
+ dependency_libs=$tmp_libs
+ done # for pass
+ if test prog = "$linkmode"; then
+ dlfiles=$newdlfiles
+ fi
+ if test prog = "$linkmode" || test lib = "$linkmode"; then
+ dlprefiles=$newdlprefiles
+ fi
+
+ case $linkmode in
+ oldlib)
+ if test -n "$dlfiles$dlprefiles" || test no != "$dlself"; then
+ func_warning "'-dlopen' is ignored for archives"
+ fi
+
+ case " $deplibs" in
+ *\ -l* | *\ -L*)
+ func_warning "'-l' and '-L' are ignored for archives" ;;
+ esac
+
+ test -n "$rpath" && \
+ func_warning "'-rpath' is ignored for archives"
+
+ test -n "$xrpath" && \
+ func_warning "'-R' is ignored for archives"
+
+ test -n "$vinfo" && \
+ func_warning "'-version-info/-version-number' is ignored for archives"
+
+ test -n "$release" && \
+ func_warning "'-release' is ignored for archives"
+
+ test -n "$export_symbols$export_symbols_regex" && \
+ func_warning "'-export-symbols' is ignored for archives"
+
+ # Now set the variables for building old libraries.
+ build_libtool_libs=no
+ oldlibs=$output
+ func_append objs "$old_deplibs"
+ ;;
+
+ lib)
+ # Make sure we only generate libraries of the form 'libNAME.la'.
+ case $outputname in
+ lib*)
+ func_stripname 'lib' '.la' "$outputname"
+ name=$func_stripname_result
+ eval shared_ext=\"$shrext_cmds\"
+ eval libname=\"$libname_spec\"
+ ;;
+ *)
+ test no = "$module" \
+ && func_fatal_help "libtool library '$output' must begin with 'lib'"
+
+ if test no != "$need_lib_prefix"; then
+ # Add the "lib" prefix for modules if required
+ func_stripname '' '.la' "$outputname"
+ name=$func_stripname_result
+ eval shared_ext=\"$shrext_cmds\"
+ eval libname=\"$libname_spec\"
+ else
+ func_stripname '' '.la' "$outputname"
+ libname=$func_stripname_result
+ fi
+ ;;
+ esac
+
+ if test -n "$objs"; then
+ if test pass_all != "$deplibs_check_method"; then
+ func_fatal_error "cannot build libtool library '$output' from non-libtool objects on this host:$objs"
+ else
+ echo
+ $ECHO "*** Warning: Linking the shared library $output against the non-libtool"
+ $ECHO "*** objects $objs is not portable!"
+ func_append libobjs " $objs"
+ fi
+ fi
+
+ test no = "$dlself" \
+ || func_warning "'-dlopen self' is ignored for libtool libraries"
+
+ set dummy $rpath
+ shift
+ test 1 -lt "$#" \
+ && func_warning "ignoring multiple '-rpath's for a libtool library"
+
+ install_libdir=$1
+
+ oldlibs=
+ if test -z "$rpath"; then
+ if test yes = "$build_libtool_libs"; then
+ # Building a libtool convenience library.
+ # Some compilers have problems with a '.al' extension so
+ # convenience libraries should have the same extension an
+ # archive normally would.
+ oldlibs="$output_objdir/$libname.$libext $oldlibs"
+ build_libtool_libs=convenience
+ build_old_libs=yes
+ fi
+
+ test -n "$vinfo" && \
+ func_warning "'-version-info/-version-number' is ignored for convenience libraries"
+
+ test -n "$release" && \
+ func_warning "'-release' is ignored for convenience libraries"
+ else
+
+ # Parse the version information argument.
+ save_ifs=$IFS; IFS=:
+ set dummy $vinfo 0 0 0
+ shift
+ IFS=$save_ifs
+
+ test -n "$7" && \
+ func_fatal_help "too many parameters to '-version-info'"
+
+ # convert absolute version numbers to libtool ages
+ # this retains compatibility with .la files and attempts
+ # to make the code below a bit more comprehensible
+
+ case $vinfo_number in
+ yes)
+ number_major=$1
+ number_minor=$2
+ number_revision=$3
+ #
+ # There are really only two kinds -- those that
+ # use the current revision as the major version
+ # and those that subtract age and use age as
+ # a minor version. But, then there is irix
+ # that has an extra 1 added just for fun
+ #
+ case $version_type in
+ # correct linux to gnu/linux during the next big refactor
+ darwin|freebsd-elf|linux|osf|windows|none)
+ func_arith $number_major + $number_minor
+ current=$func_arith_result
+ age=$number_minor
+ revision=$number_revision
+ ;;
+ freebsd-aout|qnx|sunos)
+ current=$number_major
+ revision=$number_minor
+ age=0
+ ;;
+ irix|nonstopux)
+ func_arith $number_major + $number_minor
+ current=$func_arith_result
+ age=$number_minor
+ revision=$number_minor
+ lt_irix_increment=no
+ ;;
+ *)
+ func_fatal_configuration "$modename: unknown library version type '$version_type'"
+ ;;
+ esac
+ ;;
+ no)
+ current=$1
+ revision=$2
+ age=$3
+ ;;
+ esac
+
+ # Check that each of the things are valid numbers.
+ case $current in
+ 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;;
+ *)
+ func_error "CURRENT '$current' must be a nonnegative integer"
+ func_fatal_error "'$vinfo' is not valid version information"
+ ;;
+ esac
+
+ case $revision in
+ 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;;
+ *)
+ func_error "REVISION '$revision' must be a nonnegative integer"
+ func_fatal_error "'$vinfo' is not valid version information"
+ ;;
+ esac
+
+ case $age in
+ 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;;
+ *)
+ func_error "AGE '$age' must be a nonnegative integer"
+ func_fatal_error "'$vinfo' is not valid version information"
+ ;;
+ esac
+
+ if test "$age" -gt "$current"; then
+ func_error "AGE '$age' is greater than the current interface number '$current'"
+ func_fatal_error "'$vinfo' is not valid version information"
+ fi
+
+ # Calculate the version variables.
+ major=
+ versuffix=
+ verstring=
+ case $version_type in
+ none) ;;
+
+ darwin)
+ # Like Linux, but with the current version available in
+ # verstring for coding it into the library header
+ func_arith $current - $age
+ major=.$func_arith_result
+ versuffix=$major.$age.$revision
+ # Darwin ld doesn't like 0 for these options...
+ func_arith $current + 1
+ minor_current=$func_arith_result
+ xlcverstring="$wl-compatibility_version $wl$minor_current $wl-current_version $wl$minor_current.$revision"
+ verstring="-compatibility_version $minor_current -current_version $minor_current.$revision"
+ # On Darwin other compilers
+ case $CC in
+ nagfor*)
+ verstring="$wl-compatibility_version $wl$minor_current $wl-current_version $wl$minor_current.$revision"
+ ;;
+ *)
+ verstring="-compatibility_version $minor_current -current_version $minor_current.$revision"
+ ;;
+ esac
+ ;;
+
+ freebsd-aout)
+ major=.$current
+ versuffix=.$current.$revision
+ ;;
+
+ freebsd-elf)
+ func_arith $current - $age
+ major=.$func_arith_result
+ versuffix=$major.$age.$revision
+ ;;
+
+ irix | nonstopux)
+ if test no = "$lt_irix_increment"; then
+ func_arith $current - $age
+ else
+ func_arith $current - $age + 1
+ fi
+ major=$func_arith_result
+
+ case $version_type in
+ nonstopux) verstring_prefix=nonstopux ;;
+ *) verstring_prefix=sgi ;;
+ esac
+ verstring=$verstring_prefix$major.$revision
+
+ # Add in all the interfaces that we are compatible with.
+ loop=$revision
+ while test 0 -ne "$loop"; do
+ func_arith $revision - $loop
+ iface=$func_arith_result
+ func_arith $loop - 1
+ loop=$func_arith_result
+ verstring=$verstring_prefix$major.$iface:$verstring
+ done
+
+ # Before this point, $major must not contain '.'.
+ major=.$major
+ versuffix=$major.$revision
+ ;;
+
+ linux) # correct to gnu/linux during the next big refactor
+ func_arith $current - $age
+ major=.$func_arith_result
+ versuffix=$major.$age.$revision
+ ;;
+
+ osf)
+ func_arith $current - $age
+ major=.$func_arith_result
+ versuffix=.$current.$age.$revision
+ verstring=$current.$age.$revision
+
+ # Add in all the interfaces that we are compatible with.
+ loop=$age
+ while test 0 -ne "$loop"; do
+ func_arith $current - $loop
+ iface=$func_arith_result
+ func_arith $loop - 1
+ loop=$func_arith_result
+ verstring=$verstring:$iface.0
+ done
+
+ # Make executables depend on our current version.
+ func_append verstring ":$current.0"
+ ;;
+
+ qnx)
+ major=.$current
+ versuffix=.$current
+ ;;
+
+ sco)
+ major=.$current
+ versuffix=.$current
+ ;;
+
+ sunos)
+ major=.$current
+ versuffix=.$current.$revision
+ ;;
+
+ windows)
+ # Use '-' rather than '.', since we only want one
+ # extension on DOS 8.3 file systems.
+ func_arith $current - $age
+ major=$func_arith_result
+ versuffix=-$major
+ ;;
+
+ *)
+ func_fatal_configuration "unknown library version type '$version_type'"
+ ;;
+ esac
+
+ # Clear the version info if we defaulted, and they specified a release.
+ if test -z "$vinfo" && test -n "$release"; then
+ major=
+ case $version_type in
+ darwin)
+ # we can't check for "0.0" in archive_cmds due to quoting
+ # problems, so we reset it completely
+ verstring=
+ ;;
+ *)
+ verstring=0.0
+ ;;
+ esac
+ if test no = "$need_version"; then
+ versuffix=
+ else
+ versuffix=.0.0
+ fi
+ fi
+
+ # Remove version info from name if versioning should be avoided
+ if test yes,no = "$avoid_version,$need_version"; then
+ major=
+ versuffix=
+ verstring=
+ fi
+
+ # Check to see if the archive will have undefined symbols.
+ if test yes = "$allow_undefined"; then
+ if test unsupported = "$allow_undefined_flag"; then
+ if test yes = "$build_old_libs"; then
+ func_warning "undefined symbols not allowed in $host shared libraries; building static only"
+ build_libtool_libs=no
+ else
+ func_fatal_error "can't build $host shared library unless -no-undefined is specified"
+ fi
+ fi
+ else
+ # Don't allow undefined symbols.
+ allow_undefined_flag=$no_undefined_flag
+ fi
+
+ fi
+
+ func_generate_dlsyms "$libname" "$libname" :
+ func_append libobjs " $symfileobj"
+ test " " = "$libobjs" && libobjs=
+
+ if test relink != "$opt_mode"; then
+ # Remove our outputs, but don't remove object files since they
+ # may have been created when compiling PIC objects.
+ removelist=
+ tempremovelist=`$ECHO "$output_objdir/*"`
+ for p in $tempremovelist; do
+ case $p in
+ *.$objext | *.gcno)
+ ;;
+ $output_objdir/$outputname | $output_objdir/$libname.* | $output_objdir/$libname$release.*)
+ if test -n "$precious_files_regex"; then
+ if $ECHO "$p" | $EGREP -e "$precious_files_regex" >/dev/null 2>&1
+ then
+ continue
+ fi
+ fi
+ func_append removelist " $p"
+ ;;
+ *) ;;
+ esac
+ done
+ test -n "$removelist" && \
+ func_show_eval "${RM}r \$removelist"
+ fi
+
+ # Now set the variables for building old libraries.
+ if test yes = "$build_old_libs" && test convenience != "$build_libtool_libs"; then
+ func_append oldlibs " $output_objdir/$libname.$libext"
+
+ # Transform .lo files to .o files.
+ oldobjs="$objs "`$ECHO "$libobjs" | $SP2NL | $SED "/\.$libext$/d; $lo2o" | $NL2SP`
+ fi
+
+ # Eliminate all temporary directories.
+ #for path in $notinst_path; do
+ # lib_search_path=`$ECHO "$lib_search_path " | $SED "s% $path % %g"`
+ # deplibs=`$ECHO "$deplibs " | $SED "s% -L$path % %g"`
+ # dependency_libs=`$ECHO "$dependency_libs " | $SED "s% -L$path % %g"`
+ #done
+
+ if test -n "$xrpath"; then
+ # If the user specified any rpath flags, then add them.
+ temp_xrpath=
+ for libdir in $xrpath; do
+ func_replace_sysroot "$libdir"
+ func_append temp_xrpath " -R$func_replace_sysroot_result"
+ case "$finalize_rpath " in
+ *" $libdir "*) ;;
+ *) func_append finalize_rpath " $libdir" ;;
+ esac
+ done
+ if test yes != "$hardcode_into_libs" || test yes = "$build_old_libs"; then
+ dependency_libs="$temp_xrpath $dependency_libs"
+ fi
+ fi
+
+ # Make sure dlfiles contains only unique files that won't be dlpreopened
+ old_dlfiles=$dlfiles
+ dlfiles=
+ for lib in $old_dlfiles; do
+ case " $dlprefiles $dlfiles " in
+ *" $lib "*) ;;
+ *) func_append dlfiles " $lib" ;;
+ esac
+ done
+
+ # Make sure dlprefiles contains only unique files
+ old_dlprefiles=$dlprefiles
+ dlprefiles=
+ for lib in $old_dlprefiles; do
+ case "$dlprefiles " in
+ *" $lib "*) ;;
+ *) func_append dlprefiles " $lib" ;;
+ esac
+ done
+
+ if test yes = "$build_libtool_libs"; then
+ if test -n "$rpath"; then
+ case $host in
+ *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-beos* | *-cegcc* | *-*-haiku*)
+ # these systems don't actually have a c library (as such)!
+ ;;
+ *-*-rhapsody* | *-*-darwin1.[012])
+ # Rhapsody C library is in the System framework
+ func_append deplibs " System.ltframework"
+ ;;
+ *-*-netbsd*)
+ # Don't link with libc until the a.out ld.so is fixed.
+ ;;
+ *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*)
+ # Do not include libc due to us having libc/libc_r.
+ ;;
+ *-*-sco3.2v5* | *-*-sco5v6*)
+ # Causes problems with __ctype
+ ;;
+ *-*-sysv4.2uw2* | *-*-sysv5* | *-*-unixware* | *-*-OpenUNIX*)
+ # Compiler inserts libc in the correct place for threads to work
+ ;;
+ *)
+ # Add libc to deplibs on all other systems if necessary.
+ if test yes = "$build_libtool_need_lc"; then
+ func_append deplibs " -lc"
+ fi
+ ;;
+ esac
+ fi
+
+ # Transform deplibs into only deplibs that can be linked in shared.
+ name_save=$name
+ libname_save=$libname
+ release_save=$release
+ versuffix_save=$versuffix
+ major_save=$major
+ # I'm not sure if I'm treating the release correctly. I think
+ # release should show up in the -l (ie -lgmp5) so we don't want to
+ # add it in twice. Is that correct?
+ release=
+ versuffix=
+ major=
+ newdeplibs=
+ droppeddeps=no
+ case $deplibs_check_method in
+ pass_all)
+ # Don't check for shared/static. Everything works.
+ # This might be a little naive. We might want to check
+ # whether the library exists or not. But this is on
+ # osf3 & osf4 and I'm not really sure... Just
+ # implementing what was already the behavior.
+ newdeplibs=$deplibs
+ ;;
+ test_compile)
+ # This code stresses the "libraries are programs" paradigm to its
+ # limits. Maybe even breaks it. We compile a program, linking it
+ # against the deplibs as a proxy for the library. Then we can check
+ # whether they linked in statically or dynamically with ldd.
+ $opt_dry_run || $RM conftest.c
+ cat > conftest.c <<EOF
+ int main() { return 0; }
+EOF
+ $opt_dry_run || $RM conftest
+ if $LTCC $LTCFLAGS -o conftest conftest.c $deplibs; then
+ ldd_output=`ldd conftest`
+ for i in $deplibs; do
+ case $i in
+ -l*)
+ func_stripname -l '' "$i"
+ name=$func_stripname_result
+ if test yes = "$allow_libtool_libs_with_static_runtimes"; then
+ case " $predeps $postdeps " in
+ *" $i "*)
+ func_append newdeplibs " $i"
+ i=
+ ;;
+ esac
+ fi
+ if test -n "$i"; then
+ libname=`eval "\\$ECHO \"$libname_spec\""`
+ deplib_matches=`eval "\\$ECHO \"$library_names_spec\""`
+ set dummy $deplib_matches; shift
+ deplib_match=$1
+ if test `expr "$ldd_output" : ".*$deplib_match"` -ne 0; then
+ func_append newdeplibs " $i"
+ else
+ droppeddeps=yes
+ echo
+ $ECHO "*** Warning: dynamic linker does not accept needed library $i."
+ echo "*** I have the capability to make that library automatically link in when"
+ echo "*** you link to this library. But I can only do this if you have a"
+ echo "*** shared version of the library, which I believe you do not have"
+ echo "*** because a test_compile did reveal that the linker did not use it for"
+ echo "*** its dynamic dependency list that programs get resolved with at runtime."
+ fi
+ fi
+ ;;
+ *)
+ func_append newdeplibs " $i"
+ ;;
+ esac
+ done
+ else
+ # Error occurred in the first compile. Let's try to salvage
+ # the situation: Compile a separate program for each library.
+ for i in $deplibs; do
+ case $i in
+ -l*)
+ func_stripname -l '' "$i"
+ name=$func_stripname_result
+ $opt_dry_run || $RM conftest
+ if $LTCC $LTCFLAGS -o conftest conftest.c $i; then
+ ldd_output=`ldd conftest`
+ if test yes = "$allow_libtool_libs_with_static_runtimes"; then
+ case " $predeps $postdeps " in
+ *" $i "*)
+ func_append newdeplibs " $i"
+ i=
+ ;;
+ esac
+ fi
+ if test -n "$i"; then
+ libname=`eval "\\$ECHO \"$libname_spec\""`
+ deplib_matches=`eval "\\$ECHO \"$library_names_spec\""`
+ set dummy $deplib_matches; shift
+ deplib_match=$1
+ if test `expr "$ldd_output" : ".*$deplib_match"` -ne 0; then
+ func_append newdeplibs " $i"
+ else
+ droppeddeps=yes
+ echo
+ $ECHO "*** Warning: dynamic linker does not accept needed library $i."
+ echo "*** I have the capability to make that library automatically link in when"
+ echo "*** you link to this library. But I can only do this if you have a"
+ echo "*** shared version of the library, which you do not appear to have"
+ echo "*** because a test_compile did reveal that the linker did not use this one"
+ echo "*** as a dynamic dependency that programs can get resolved with at runtime."
+ fi
+ fi
+ else
+ droppeddeps=yes
+ echo
+ $ECHO "*** Warning! Library $i is needed by this library but I was not able to"
+ echo "*** make it link in! You will probably need to install it or some"
+ echo "*** library that it depends on before this library will be fully"
+ echo "*** functional. Installing it before continuing would be even better."
+ fi
+ ;;
+ *)
+ func_append newdeplibs " $i"
+ ;;
+ esac
+ done
+ fi
+ ;;
+ file_magic*)
+ set dummy $deplibs_check_method; shift
+ file_magic_regex=`expr "$deplibs_check_method" : "$1 \(.*\)"`
+ for a_deplib in $deplibs; do
+ case $a_deplib in
+ -l*)
+ func_stripname -l '' "$a_deplib"
+ name=$func_stripname_result
+ if test yes = "$allow_libtool_libs_with_static_runtimes"; then
+ case " $predeps $postdeps " in
+ *" $a_deplib "*)
+ func_append newdeplibs " $a_deplib"
+ a_deplib=
+ ;;
+ esac
+ fi
+ if test -n "$a_deplib"; then
+ libname=`eval "\\$ECHO \"$libname_spec\""`
+ if test -n "$file_magic_glob"; then
+ libnameglob=`func_echo_all "$libname" | $SED -e $file_magic_glob`
+ else
+ libnameglob=$libname
+ fi
+ test yes = "$want_nocaseglob" && nocaseglob=`shopt -p nocaseglob`
+ for i in $lib_search_path $sys_lib_search_path $shlib_search_path; do
+ if test yes = "$want_nocaseglob"; then
+ shopt -s nocaseglob
+ potential_libs=`ls $i/$libnameglob[.-]* 2>/dev/null`
+ $nocaseglob
+ else
+ potential_libs=`ls $i/$libnameglob[.-]* 2>/dev/null`
+ fi
+ for potent_lib in $potential_libs; do
+ # Follow soft links.
+ if ls -lLd "$potent_lib" 2>/dev/null |
+ $GREP " -> " >/dev/null; then
+ continue
+ fi
+ # The statement above tries to avoid entering an
+ # endless loop below, in case of cyclic links.
+ # We might still enter an endless loop, since a link
+ # loop can be closed while we follow links,
+ # but so what?
+ potlib=$potent_lib
+ while test -h "$potlib" 2>/dev/null; do
+ potliblink=`ls -ld $potlib | $SED 's/.* -> //'`
+ case $potliblink in
+ [\\/]* | [A-Za-z]:[\\/]*) potlib=$potliblink;;
+ *) potlib=`$ECHO "$potlib" | $SED 's|[^/]*$||'`"$potliblink";;
+ esac
+ done
+ if eval $file_magic_cmd \"\$potlib\" 2>/dev/null |
+ $SED -e 10q |
+ $EGREP "$file_magic_regex" > /dev/null; then
+ func_append newdeplibs " $a_deplib"
+ a_deplib=
+ break 2
+ fi
+ done
+ done
+ fi
+ if test -n "$a_deplib"; then
+ droppeddeps=yes
+ echo
+ $ECHO "*** Warning: linker path does not have real file for library $a_deplib."
+ echo "*** I have the capability to make that library automatically link in when"
+ echo "*** you link to this library. But I can only do this if you have a"
+ echo "*** shared version of the library, which you do not appear to have"
+ echo "*** because I did check the linker path looking for a file starting"
+ if test -z "$potlib"; then
+ $ECHO "*** with $libname but no candidates were found. (...for file magic test)"
+ else
+ $ECHO "*** with $libname and none of the candidates passed a file format test"
+ $ECHO "*** using a file magic. Last file checked: $potlib"
+ fi
+ fi
+ ;;
+ *)
+ # Add a -L argument.
+ func_append newdeplibs " $a_deplib"
+ ;;
+ esac
+ done # Gone through all deplibs.
+ ;;
+ match_pattern*)
+ set dummy $deplibs_check_method; shift
+ match_pattern_regex=`expr "$deplibs_check_method" : "$1 \(.*\)"`
+ for a_deplib in $deplibs; do
+ case $a_deplib in
+ -l*)
+ func_stripname -l '' "$a_deplib"
+ name=$func_stripname_result
+ if test yes = "$allow_libtool_libs_with_static_runtimes"; then
+ case " $predeps $postdeps " in
+ *" $a_deplib "*)
+ func_append newdeplibs " $a_deplib"
+ a_deplib=
+ ;;
+ esac
+ fi
+ if test -n "$a_deplib"; then
+ libname=`eval "\\$ECHO \"$libname_spec\""`
+ for i in $lib_search_path $sys_lib_search_path $shlib_search_path; do
+ potential_libs=`ls $i/$libname[.-]* 2>/dev/null`
+ for potent_lib in $potential_libs; do
+ potlib=$potent_lib # see symlink-check above in file_magic test
+ if eval "\$ECHO \"$potent_lib\"" 2>/dev/null | $SED 10q | \
+ $EGREP "$match_pattern_regex" > /dev/null; then
+ func_append newdeplibs " $a_deplib"
+ a_deplib=
+ break 2
+ fi
+ done
+ done
+ fi
+ if test -n "$a_deplib"; then
+ droppeddeps=yes
+ echo
+ $ECHO "*** Warning: linker path does not have real file for library $a_deplib."
+ echo "*** I have the capability to make that library automatically link in when"
+ echo "*** you link to this library. But I can only do this if you have a"
+ echo "*** shared version of the library, which you do not appear to have"
+ echo "*** because I did check the linker path looking for a file starting"
+ if test -z "$potlib"; then
+ $ECHO "*** with $libname but no candidates were found. (...for regex pattern test)"
+ else
+ $ECHO "*** with $libname and none of the candidates passed a file format test"
+ $ECHO "*** using a regex pattern. Last file checked: $potlib"
+ fi
+ fi
+ ;;
+ *)
+ # Add a -L argument.
+ func_append newdeplibs " $a_deplib"
+ ;;
+ esac
+ done # Gone through all deplibs.
+ ;;
+ none | unknown | *)
+ newdeplibs=
+ tmp_deplibs=`$ECHO " $deplibs" | $SED 's/ -lc$//; s/ -[LR][^ ]*//g'`
+ if test yes = "$allow_libtool_libs_with_static_runtimes"; then
+ for i in $predeps $postdeps; do
+ # can't use Xsed below, because $i might contain '/'
+ tmp_deplibs=`$ECHO " $tmp_deplibs" | $SED "s|$i||"`
+ done
+ fi
+ case $tmp_deplibs in
+ *[!\ \ ]*)
+ echo
+ if test none = "$deplibs_check_method"; then
+ echo "*** Warning: inter-library dependencies are not supported in this platform."
+ else
+ echo "*** Warning: inter-library dependencies are not known to be supported."
+ fi
+ echo "*** All declared inter-library dependencies are being dropped."
+ droppeddeps=yes
+ ;;
+ esac
+ ;;
+ esac
+ versuffix=$versuffix_save
+ major=$major_save
+ release=$release_save
+ libname=$libname_save
+ name=$name_save
+
+ case $host in
+ *-*-rhapsody* | *-*-darwin1.[012])
+ # On Rhapsody replace the C library with the System framework
+ newdeplibs=`$ECHO " $newdeplibs" | $SED 's/ -lc / System.ltframework /'`
+ ;;
+ esac
+
+ if test yes = "$droppeddeps"; then
+ if test yes = "$module"; then
+ echo
+ echo "*** Warning: libtool could not satisfy all declared inter-library"
+ $ECHO "*** dependencies of module $libname. Therefore, libtool will create"
+ echo "*** a static module, that should work as long as the dlopening"
+ echo "*** application is linked with the -dlopen flag."
+ if test -z "$global_symbol_pipe"; then
+ echo
+ echo "*** However, this would only work if libtool was able to extract symbol"
+ echo "*** lists from a program, using 'nm' or equivalent, but libtool could"
+ echo "*** not find such a program. So, this module is probably useless."
+ echo "*** 'nm' from GNU binutils and a full rebuild may help."
+ fi
+ if test no = "$build_old_libs"; then
+ oldlibs=$output_objdir/$libname.$libext
+ build_libtool_libs=module
+ build_old_libs=yes
+ else
+ build_libtool_libs=no
+ fi
+ else
+ echo "*** The inter-library dependencies that have been dropped here will be"
+ echo "*** automatically added whenever a program is linked with this library"
+ echo "*** or is declared to -dlopen it."
+
+ if test no = "$allow_undefined"; then
+ echo
+ echo "*** Since this library must not contain undefined symbols,"
+ echo "*** because either the platform does not support them or"
+ echo "*** it was explicitly requested with -no-undefined,"
+ echo "*** libtool will only create a static version of it."
+ if test no = "$build_old_libs"; then
+ oldlibs=$output_objdir/$libname.$libext
+ build_libtool_libs=module
+ build_old_libs=yes
+ else
+ build_libtool_libs=no
+ fi
+ fi
+ fi
+ fi
+ # Done checking deplibs!
+ deplibs=$newdeplibs
+ fi
+ # Time to change all our "foo.ltframework" stuff back to "-framework foo"
+ case $host in
+ *-*-darwin*)
+ newdeplibs=`$ECHO " $newdeplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'`
+ new_inherited_linker_flags=`$ECHO " $new_inherited_linker_flags" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'`
+ deplibs=`$ECHO " $deplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'`
+ ;;
+ esac
+
+ # move library search paths that coincide with paths to not yet
+ # installed libraries to the beginning of the library search list
+ new_libs=
+ for path in $notinst_path; do
+ case " $new_libs " in
+ *" -L$path/$objdir "*) ;;
+ *)
+ case " $deplibs " in
+ *" -L$path/$objdir "*)
+ func_append new_libs " -L$path/$objdir" ;;
+ esac
+ ;;
+ esac
+ done
+ for deplib in $deplibs; do
+ case $deplib in
+ -L*)
+ case " $new_libs " in
+ *" $deplib "*) ;;
+ *) func_append new_libs " $deplib" ;;
+ esac
+ ;;
+ *) func_append new_libs " $deplib" ;;
+ esac
+ done
+ deplibs=$new_libs
+
+ # All the library-specific variables (install_libdir is set above).
+ library_names=
+ old_library=
+ dlname=
+
+ # Test again, we may have decided not to build it any more
+ if test yes = "$build_libtool_libs"; then
+ # Remove $wl instances when linking with ld.
+ # FIXME: should test the right _cmds variable.
+ case $archive_cmds in
+ *\$LD\ *) wl= ;;
+ esac
+ if test yes = "$hardcode_into_libs"; then
+ # Hardcode the library paths
+ hardcode_libdirs=
+ dep_rpath=
+ rpath=$finalize_rpath
+ test relink = "$opt_mode" || rpath=$compile_rpath$rpath
+ for libdir in $rpath; do
+ if test -n "$hardcode_libdir_flag_spec"; then
+ if test -n "$hardcode_libdir_separator"; then
+ func_replace_sysroot "$libdir"
+ libdir=$func_replace_sysroot_result
+ if test -z "$hardcode_libdirs"; then
+ hardcode_libdirs=$libdir
+ else
+ # Just accumulate the unique libdirs.
+ case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in
+ *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*)
+ ;;
+ *)
+ func_append hardcode_libdirs "$hardcode_libdir_separator$libdir"
+ ;;
+ esac
+ fi
+ else
+ eval flag=\"$hardcode_libdir_flag_spec\"
+ func_append dep_rpath " $flag"
+ fi
+ elif test -n "$runpath_var"; then
+ case "$perm_rpath " in
+ *" $libdir "*) ;;
+ *) func_append perm_rpath " $libdir" ;;
+ esac
+ fi
+ done
+ # Substitute the hardcoded libdirs into the rpath.
+ if test -n "$hardcode_libdir_separator" &&
+ test -n "$hardcode_libdirs"; then
+ libdir=$hardcode_libdirs
+ eval "dep_rpath=\"$hardcode_libdir_flag_spec\""
+ fi
+ if test -n "$runpath_var" && test -n "$perm_rpath"; then
+ # We should set the runpath_var.
+ rpath=
+ for dir in $perm_rpath; do
+ func_append rpath "$dir:"
+ done
+ eval "$runpath_var='$rpath\$$runpath_var'; export $runpath_var"
+ fi
+ test -n "$dep_rpath" && deplibs="$dep_rpath $deplibs"
+ fi
+
+ shlibpath=$finalize_shlibpath
+ test relink = "$opt_mode" || shlibpath=$compile_shlibpath$shlibpath
+ if test -n "$shlibpath"; then
+ eval "$shlibpath_var='$shlibpath\$$shlibpath_var'; export $shlibpath_var"
+ fi
+
+ # Get the real and link names of the library.
+ eval shared_ext=\"$shrext_cmds\"
+ eval library_names=\"$library_names_spec\"
+ set dummy $library_names
+ shift
+ realname=$1
+ shift
+
+ if test -n "$soname_spec"; then
+ eval soname=\"$soname_spec\"
+ else
+ soname=$realname
+ fi
+ if test -z "$dlname"; then
+ dlname=$soname
+ fi
+
+ lib=$output_objdir/$realname
+ linknames=
+ for link
+ do
+ func_append linknames " $link"
+ done
+
+ # Use standard objects if they are pic
+ test -z "$pic_flag" && libobjs=`$ECHO "$libobjs" | $SP2NL | $SED "$lo2o" | $NL2SP`
+ test "X$libobjs" = "X " && libobjs=
+
+ delfiles=
+ if test -n "$export_symbols" && test -n "$include_expsyms"; then
+ $opt_dry_run || cp "$export_symbols" "$output_objdir/$libname.uexp"
+ export_symbols=$output_objdir/$libname.uexp
+ func_append delfiles " $export_symbols"
+ fi
+
+ orig_export_symbols=
+ case $host_os in
+ cygwin* | mingw* | cegcc*)
+ if test -n "$export_symbols" && test -z "$export_symbols_regex"; then
+ # exporting using user supplied symfile
+ func_dll_def_p "$export_symbols" || {
+ # and it's NOT already a .def file. Must figure out
+ # which of the given symbols are data symbols and tag
+ # them as such. So, trigger use of export_symbols_cmds.
+ # export_symbols gets reassigned inside the "prepare
+ # the list of exported symbols" if statement, so the
+ # include_expsyms logic still works.
+ orig_export_symbols=$export_symbols
+ export_symbols=
+ always_export_symbols=yes
+ }
+ fi
+ ;;
+ esac
+
+ # Prepare the list of exported symbols
+ if test -z "$export_symbols"; then
+ if test yes = "$always_export_symbols" || test -n "$export_symbols_regex"; then
+ func_verbose "generating symbol list for '$libname.la'"
+ export_symbols=$output_objdir/$libname.exp
+ $opt_dry_run || $RM $export_symbols
+ cmds=$export_symbols_cmds
+ save_ifs=$IFS; IFS='~'
+ for cmd1 in $cmds; do
+ IFS=$save_ifs
+ # Take the normal branch if the nm_file_list_spec branch
+ # doesn't work or if tool conversion is not needed.
+ case $nm_file_list_spec~$to_tool_file_cmd in
+ *~func_convert_file_noop | *~func_convert_file_msys_to_w32 | ~*)
+ try_normal_branch=yes
+ eval cmd=\"$cmd1\"
+ func_len " $cmd"
+ len=$func_len_result
+ ;;
+ *)
+ try_normal_branch=no
+ ;;
+ esac
+ if test yes = "$try_normal_branch" \
+ && { test "$len" -lt "$max_cmd_len" \
+ || test "$max_cmd_len" -le -1; }
+ then
+ func_show_eval "$cmd" 'exit $?'
+ skipped_export=false
+ elif test -n "$nm_file_list_spec"; then
+ func_basename "$output"
+ output_la=$func_basename_result
+ save_libobjs=$libobjs
+ save_output=$output
+ output=$output_objdir/$output_la.nm
+ func_to_tool_file "$output"
+ libobjs=$nm_file_list_spec$func_to_tool_file_result
+ func_append delfiles " $output"
+ func_verbose "creating $NM input file list: $output"
+ for obj in $save_libobjs; do
+ func_to_tool_file "$obj"
+ $ECHO "$func_to_tool_file_result"
+ done > "$output"
+ eval cmd=\"$cmd1\"
+ func_show_eval "$cmd" 'exit $?'
+ output=$save_output
+ libobjs=$save_libobjs
+ skipped_export=false
+ else
+ # The command line is too long to execute in one step.
+ func_verbose "using reloadable object file for export list..."
+ skipped_export=:
+ # Break out early, otherwise skipped_export may be
+ # set to false by a later but shorter cmd.
+ break
+ fi
+ done
+ IFS=$save_ifs
+ if test -n "$export_symbols_regex" && test : != "$skipped_export"; then
+ func_show_eval '$EGREP -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"'
+ func_show_eval '$MV "${export_symbols}T" "$export_symbols"'
+ fi
+ fi
+ fi
+
+ if test -n "$export_symbols" && test -n "$include_expsyms"; then
+ tmp_export_symbols=$export_symbols
+ test -n "$orig_export_symbols" && tmp_export_symbols=$orig_export_symbols
+ $opt_dry_run || eval '$ECHO "$include_expsyms" | $SP2NL >> "$tmp_export_symbols"'
+ fi
+
+ if test : != "$skipped_export" && test -n "$orig_export_symbols"; then
+ # The given exports_symbols file has to be filtered, so filter it.
+ func_verbose "filter symbol list for '$libname.la' to tag DATA exports"
+ # FIXME: $output_objdir/$libname.filter potentially contains lots of
+ # 's' commands, which not all seds can handle. GNU sed should be fine
+ # though. Also, the filter scales superlinearly with the number of
+ # global variables. join(1) would be nice here, but unfortunately
+ # isn't a blessed tool.
+ $opt_dry_run || $SED -e '/[ ,]DATA/!d;s,\(.*\)\([ \,].*\),s|^\1$|\1\2|,' < $export_symbols > $output_objdir/$libname.filter
+ func_append delfiles " $export_symbols $output_objdir/$libname.filter"
+ export_symbols=$output_objdir/$libname.def
+ $opt_dry_run || $SED -f $output_objdir/$libname.filter < $orig_export_symbols > $export_symbols
+ fi
+
+ tmp_deplibs=
+ for test_deplib in $deplibs; do
+ case " $convenience " in
+ *" $test_deplib "*) ;;
+ *)
+ func_append tmp_deplibs " $test_deplib"
+ ;;
+ esac
+ done
+ deplibs=$tmp_deplibs
+
+ if test -n "$convenience"; then
+ if test -n "$whole_archive_flag_spec" &&
+ test yes = "$compiler_needs_object" &&
+ test -z "$libobjs"; then
+ # extract the archives, so we have objects to list.
+ # TODO: could optimize this to just extract one archive.
+ whole_archive_flag_spec=
+ fi
+ if test -n "$whole_archive_flag_spec"; then
+ save_libobjs=$libobjs
+ eval libobjs=\"\$libobjs $whole_archive_flag_spec\"
+ test "X$libobjs" = "X " && libobjs=
+ else
+ gentop=$output_objdir/${outputname}x
+ func_append generated " $gentop"
+
+ func_extract_archives $gentop $convenience
+ func_append libobjs " $func_extract_archives_result"
+ test "X$libobjs" = "X " && libobjs=
+ fi
+ fi
+
+ if test yes = "$thread_safe" && test -n "$thread_safe_flag_spec"; then
+ eval flag=\"$thread_safe_flag_spec\"
+ func_append linker_flags " $flag"
+ fi
+
+ # Make a backup of the uninstalled library when relinking
+ if test relink = "$opt_mode"; then
+ $opt_dry_run || eval '(cd $output_objdir && $RM ${realname}U && $MV $realname ${realname}U)' || exit $?
+ fi
+
+ # Do each of the archive commands.
+ if test yes = "$module" && test -n "$module_cmds"; then
+ if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then
+ eval test_cmds=\"$module_expsym_cmds\"
+ cmds=$module_expsym_cmds
+ else
+ eval test_cmds=\"$module_cmds\"
+ cmds=$module_cmds
+ fi
+ else
+ if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then
+ eval test_cmds=\"$archive_expsym_cmds\"
+ cmds=$archive_expsym_cmds
+ else
+ eval test_cmds=\"$archive_cmds\"
+ cmds=$archive_cmds
+ fi
+ fi
+
+ if test : != "$skipped_export" &&
+ func_len " $test_cmds" &&
+ len=$func_len_result &&
+ test "$len" -lt "$max_cmd_len" || test "$max_cmd_len" -le -1; then
+ :
+ else
+ # The command line is too long to link in one step, link piecewise
+ # or, if using GNU ld and skipped_export is not :, use a linker
+ # script.
+
+ # Save the value of $output and $libobjs because we want to
+ # use them later. If we have whole_archive_flag_spec, we
+ # want to use save_libobjs as it was before
+ # whole_archive_flag_spec was expanded, because we can't
+ # assume the linker understands whole_archive_flag_spec.
+ # This may have to be revisited, in case too many
+ # convenience libraries get linked in and end up exceeding
+ # the spec.
+ if test -z "$convenience" || test -z "$whole_archive_flag_spec"; then
+ save_libobjs=$libobjs
+ fi
+ save_output=$output
+ func_basename "$output"
+ output_la=$func_basename_result
+
+ # Clear the reloadable object creation command queue and
+ # initialize k to one.
+ test_cmds=
+ concat_cmds=
+ objlist=
+ last_robj=
+ k=1
+
+ if test -n "$save_libobjs" && test : != "$skipped_export" && test yes = "$with_gnu_ld"; then
+ output=$output_objdir/$output_la.lnkscript
+ func_verbose "creating GNU ld script: $output"
+ echo 'INPUT (' > $output
+ for obj in $save_libobjs
+ do
+ func_to_tool_file "$obj"
+ $ECHO "$func_to_tool_file_result" >> $output
+ done
+ echo ')' >> $output
+ func_append delfiles " $output"
+ func_to_tool_file "$output"
+ output=$func_to_tool_file_result
+ elif test -n "$save_libobjs" && test : != "$skipped_export" && test -n "$file_list_spec"; then
+ output=$output_objdir/$output_la.lnk
+ func_verbose "creating linker input file list: $output"
+ : > $output
+ set x $save_libobjs
+ shift
+ firstobj=
+ if test yes = "$compiler_needs_object"; then
+ firstobj="$1 "
+ shift
+ fi
+ for obj
+ do
+ func_to_tool_file "$obj"
+ $ECHO "$func_to_tool_file_result" >> $output
+ done
+ func_append delfiles " $output"
+ func_to_tool_file "$output"
+ output=$firstobj\"$file_list_spec$func_to_tool_file_result\"
+ else
+ if test -n "$save_libobjs"; then
+ func_verbose "creating reloadable object files..."
+ output=$output_objdir/$output_la-$k.$objext
+ eval test_cmds=\"$reload_cmds\"
+ func_len " $test_cmds"
+ len0=$func_len_result
+ len=$len0
+
+ # Loop over the list of objects to be linked.
+ for obj in $save_libobjs
+ do
+ func_len " $obj"
+ func_arith $len + $func_len_result
+ len=$func_arith_result
+ if test -z "$objlist" ||
+ test "$len" -lt "$max_cmd_len"; then
+ func_append objlist " $obj"
+ else
+ # The command $test_cmds is almost too long, add a
+ # command to the queue.
+ if test 1 -eq "$k"; then
+ # The first file doesn't have a previous command to add.
+ reload_objs=$objlist
+ eval concat_cmds=\"$reload_cmds\"
+ else
+ # All subsequent reloadable object files will link in
+ # the last one created.
+ reload_objs="$objlist $last_robj"
+ eval concat_cmds=\"\$concat_cmds~$reload_cmds~\$RM $last_robj\"
+ fi
+ last_robj=$output_objdir/$output_la-$k.$objext
+ func_arith $k + 1
+ k=$func_arith_result
+ output=$output_objdir/$output_la-$k.$objext
+ objlist=" $obj"
+ func_len " $last_robj"
+ func_arith $len0 + $func_len_result
+ len=$func_arith_result
+ fi
+ done
+ # Handle the remaining objects by creating one last
+ # reloadable object file. All subsequent reloadable object
+ # files will link in the last one created.
+ test -z "$concat_cmds" || concat_cmds=$concat_cmds~
+ reload_objs="$objlist $last_robj"
+ eval concat_cmds=\"\$concat_cmds$reload_cmds\"
+ if test -n "$last_robj"; then
+ eval concat_cmds=\"\$concat_cmds~\$RM $last_robj\"
+ fi
+ func_append delfiles " $output"
+
+ else
+ output=
+ fi
+
+ ${skipped_export-false} && {
+ func_verbose "generating symbol list for '$libname.la'"
+ export_symbols=$output_objdir/$libname.exp
+ $opt_dry_run || $RM $export_symbols
+ libobjs=$output
+ # Append the command to create the export file.
+ test -z "$concat_cmds" || concat_cmds=$concat_cmds~
+ eval concat_cmds=\"\$concat_cmds$export_symbols_cmds\"
+ if test -n "$last_robj"; then
+ eval concat_cmds=\"\$concat_cmds~\$RM $last_robj\"
+ fi
+ }
+
+ test -n "$save_libobjs" &&
+ func_verbose "creating a temporary reloadable object file: $output"
+
+ # Loop through the commands generated above and execute them.
+ save_ifs=$IFS; IFS='~'
+ for cmd in $concat_cmds; do
+ IFS=$save_ifs
+ $opt_quiet || {
+ func_quote_for_expand "$cmd"
+ eval "func_echo $func_quote_for_expand_result"
+ }
+ $opt_dry_run || eval "$cmd" || {
+ lt_exit=$?
+
+ # Restore the uninstalled library and exit
+ if test relink = "$opt_mode"; then
+ ( cd "$output_objdir" && \
+ $RM "${realname}T" && \
+ $MV "${realname}U" "$realname" )
+ fi
+
+ exit $lt_exit
+ }
+ done
+ IFS=$save_ifs
+
+ if test -n "$export_symbols_regex" && ${skipped_export-false}; then
+ func_show_eval '$EGREP -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"'
+ func_show_eval '$MV "${export_symbols}T" "$export_symbols"'
+ fi
+ fi
+
+ ${skipped_export-false} && {
+ if test -n "$export_symbols" && test -n "$include_expsyms"; then
+ tmp_export_symbols=$export_symbols
+ test -n "$orig_export_symbols" && tmp_export_symbols=$orig_export_symbols
+ $opt_dry_run || eval '$ECHO "$include_expsyms" | $SP2NL >> "$tmp_export_symbols"'
+ fi
+
+ if test -n "$orig_export_symbols"; then
+ # The given exports_symbols file has to be filtered, so filter it.
+ func_verbose "filter symbol list for '$libname.la' to tag DATA exports"
+ # FIXME: $output_objdir/$libname.filter potentially contains lots of
+ # 's' commands, which not all seds can handle. GNU sed should be fine
+ # though. Also, the filter scales superlinearly with the number of
+ # global variables. join(1) would be nice here, but unfortunately
+ # isn't a blessed tool.
+ $opt_dry_run || $SED -e '/[ ,]DATA/!d;s,\(.*\)\([ \,].*\),s|^\1$|\1\2|,' < $export_symbols > $output_objdir/$libname.filter
+ func_append delfiles " $export_symbols $output_objdir/$libname.filter"
+ export_symbols=$output_objdir/$libname.def
+ $opt_dry_run || $SED -f $output_objdir/$libname.filter < $orig_export_symbols > $export_symbols
+ fi
+ }
+
+ libobjs=$output
+ # Restore the value of output.
+ output=$save_output
+
+ if test -n "$convenience" && test -n "$whole_archive_flag_spec"; then
+ eval libobjs=\"\$libobjs $whole_archive_flag_spec\"
+ test "X$libobjs" = "X " && libobjs=
+ fi
+ # Expand the library linking commands again to reset the
+ # value of $libobjs for piecewise linking.
+
+ # Do each of the archive commands.
+ if test yes = "$module" && test -n "$module_cmds"; then
+ if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then
+ cmds=$module_expsym_cmds
+ else
+ cmds=$module_cmds
+ fi
+ else
+ if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then
+ cmds=$archive_expsym_cmds
+ else
+ cmds=$archive_cmds
+ fi
+ fi
+ fi
+
+ if test -n "$delfiles"; then
+ # Append the command to remove temporary files to $cmds.
+ eval cmds=\"\$cmds~\$RM $delfiles\"
+ fi
+
+ # Add any objects from preloaded convenience libraries
+ if test -n "$dlprefiles"; then
+ gentop=$output_objdir/${outputname}x
+ func_append generated " $gentop"
+
+ func_extract_archives $gentop $dlprefiles
+ func_append libobjs " $func_extract_archives_result"
+ test "X$libobjs" = "X " && libobjs=
+ fi
+
+ save_ifs=$IFS; IFS='~'
+ for cmd in $cmds; do
+ IFS=$sp$nl
+ eval cmd=\"$cmd\"
+ IFS=$save_ifs
+ $opt_quiet || {
+ func_quote_for_expand "$cmd"
+ eval "func_echo $func_quote_for_expand_result"
+ }
+ $opt_dry_run || eval "$cmd" || {
+ lt_exit=$?
+
+ # Restore the uninstalled library and exit
+ if test relink = "$opt_mode"; then
+ ( cd "$output_objdir" && \
+ $RM "${realname}T" && \
+ $MV "${realname}U" "$realname" )
+ fi
+
+ exit $lt_exit
+ }
+ done
+ IFS=$save_ifs
+
+ # Restore the uninstalled library and exit
+ if test relink = "$opt_mode"; then
+ $opt_dry_run || eval '(cd $output_objdir && $RM ${realname}T && $MV $realname ${realname}T && $MV ${realname}U $realname)' || exit $?
+
+ if test -n "$convenience"; then
+ if test -z "$whole_archive_flag_spec"; then
+ func_show_eval '${RM}r "$gentop"'
+ fi
+ fi
+
+ exit $EXIT_SUCCESS
+ fi
+
+ # Create links to the real library.
+ for linkname in $linknames; do
+ if test "$realname" != "$linkname"; then
+ func_show_eval '(cd "$output_objdir" && $RM "$linkname" && $LN_S "$realname" "$linkname")' 'exit $?'
+ fi
+ done
+
+ # If -module or -export-dynamic was specified, set the dlname.
+ if test yes = "$module" || test yes = "$export_dynamic"; then
+ # On all known operating systems, these are identical.
+ dlname=$soname
+ fi
+ fi
+ ;;
+
+ obj)
+ if test -n "$dlfiles$dlprefiles" || test no != "$dlself"; then
+ func_warning "'-dlopen' is ignored for objects"
+ fi
+
+ case " $deplibs" in
+ *\ -l* | *\ -L*)
+ func_warning "'-l' and '-L' are ignored for objects" ;;
+ esac
+
+ test -n "$rpath" && \
+ func_warning "'-rpath' is ignored for objects"
+
+ test -n "$xrpath" && \
+ func_warning "'-R' is ignored for objects"
+
+ test -n "$vinfo" && \
+ func_warning "'-version-info' is ignored for objects"
+
+ test -n "$release" && \
+ func_warning "'-release' is ignored for objects"
+
+ case $output in
+ *.lo)
+ test -n "$objs$old_deplibs" && \
+ func_fatal_error "cannot build library object '$output' from non-libtool objects"
+
+ libobj=$output
+ func_lo2o "$libobj"
+ obj=$func_lo2o_result
+ ;;
+ *)
+ libobj=
+ obj=$output
+ ;;
+ esac
+
+ # Delete the old objects.
+ $opt_dry_run || $RM $obj $libobj
+
+ # Objects from convenience libraries. This assumes
+ # single-version convenience libraries. Whenever we create
+ # different ones for PIC/non-PIC, this we'll have to duplicate
+ # the extraction.
+ reload_conv_objs=
+ gentop=
+ # if reload_cmds runs $LD directly, get rid of -Wl from
+ # whole_archive_flag_spec and hope we can get by with turning comma
+ # into space.
+ case $reload_cmds in
+ *\$LD[\ \$]*) wl= ;;
+ esac
+ if test -n "$convenience"; then
+ if test -n "$whole_archive_flag_spec"; then
+ eval tmp_whole_archive_flags=\"$whole_archive_flag_spec\"
+ test -n "$wl" || tmp_whole_archive_flags=`$ECHO "$tmp_whole_archive_flags" | $SED 's|,| |g'`
+ reload_conv_objs=$reload_objs\ $tmp_whole_archive_flags
+ else
+ gentop=$output_objdir/${obj}x
+ func_append generated " $gentop"
+
+ func_extract_archives $gentop $convenience
+ reload_conv_objs="$reload_objs $func_extract_archives_result"
+ fi
+ fi
+
+ # If we're not building shared, we need to use non_pic_objs
+ test yes = "$build_libtool_libs" || libobjs=$non_pic_objects
+
+ # Create the old-style object.
+ reload_objs=$objs$old_deplibs' '`$ECHO "$libobjs" | $SP2NL | $SED "/\.$libext$/d; /\.lib$/d; $lo2o" | $NL2SP`' '$reload_conv_objs
+
+ output=$obj
+ func_execute_cmds "$reload_cmds" 'exit $?'
+
+ # Exit if we aren't doing a library object file.
+ if test -z "$libobj"; then
+ if test -n "$gentop"; then
+ func_show_eval '${RM}r "$gentop"'
+ fi
+
+ exit $EXIT_SUCCESS
+ fi
+
+ test yes = "$build_libtool_libs" || {
+ if test -n "$gentop"; then
+ func_show_eval '${RM}r "$gentop"'
+ fi
+
+ # Create an invalid libtool object if no PIC, so that we don't
+ # accidentally link it into a program.
+ # $show "echo timestamp > $libobj"
+ # $opt_dry_run || eval "echo timestamp > $libobj" || exit $?
+ exit $EXIT_SUCCESS
+ }
+
+ if test -n "$pic_flag" || test default != "$pic_mode"; then
+ # Only do commands if we really have different PIC objects.
+ reload_objs="$libobjs $reload_conv_objs"
+ output=$libobj
+ func_execute_cmds "$reload_cmds" 'exit $?'
+ fi
+
+ if test -n "$gentop"; then
+ func_show_eval '${RM}r "$gentop"'
+ fi
+
+ exit $EXIT_SUCCESS
+ ;;
+
+ prog)
+ case $host in
+ *cygwin*) func_stripname '' '.exe' "$output"
+ output=$func_stripname_result.exe;;
+ esac
+ test -n "$vinfo" && \
+ func_warning "'-version-info' is ignored for programs"
+
+ test -n "$release" && \
+ func_warning "'-release' is ignored for programs"
+
+ $preload \
+ && test unknown,unknown,unknown = "$dlopen_support,$dlopen_self,$dlopen_self_static" \
+ && func_warning "'LT_INIT([dlopen])' not used. Assuming no dlopen support."
+
+ case $host in
+ *-*-rhapsody* | *-*-darwin1.[012])
+ # On Rhapsody replace the C library is the System framework
+ compile_deplibs=`$ECHO " $compile_deplibs" | $SED 's/ -lc / System.ltframework /'`
+ finalize_deplibs=`$ECHO " $finalize_deplibs" | $SED 's/ -lc / System.ltframework /'`
+ ;;
+ esac
+
+ case $host in
+ *-*-darwin*)
+ # Don't allow lazy linking, it breaks C++ global constructors
+ # But is supposedly fixed on 10.4 or later (yay!).
+ if test CXX = "$tagname"; then
+ case ${MACOSX_DEPLOYMENT_TARGET-10.0} in
+ 10.[0123])
+ func_append compile_command " $wl-bind_at_load"
+ func_append finalize_command " $wl-bind_at_load"
+ ;;
+ esac
+ fi
+ # Time to change all our "foo.ltframework" stuff back to "-framework foo"
+ compile_deplibs=`$ECHO " $compile_deplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'`
+ finalize_deplibs=`$ECHO " $finalize_deplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'`
+ ;;
+ esac
+
+
+ # move library search paths that coincide with paths to not yet
+ # installed libraries to the beginning of the library search list
+ new_libs=
+ for path in $notinst_path; do
+ case " $new_libs " in
+ *" -L$path/$objdir "*) ;;
+ *)
+ case " $compile_deplibs " in
+ *" -L$path/$objdir "*)
+ func_append new_libs " -L$path/$objdir" ;;
+ esac
+ ;;
+ esac
+ done
+ for deplib in $compile_deplibs; do
+ case $deplib in
+ -L*)
+ case " $new_libs " in
+ *" $deplib "*) ;;
+ *) func_append new_libs " $deplib" ;;
+ esac
+ ;;
+ *) func_append new_libs " $deplib" ;;
+ esac
+ done
+ compile_deplibs=$new_libs
+
+
+ func_append compile_command " $compile_deplibs"
+ func_append finalize_command " $finalize_deplibs"
+
+ if test -n "$rpath$xrpath"; then
+ # If the user specified any rpath flags, then add them.
+ for libdir in $rpath $xrpath; do
+ # This is the magic to use -rpath.
+ case "$finalize_rpath " in
+ *" $libdir "*) ;;
+ *) func_append finalize_rpath " $libdir" ;;
+ esac
+ done
+ fi
+
+ # Now hardcode the library paths
+ rpath=
+ hardcode_libdirs=
+ for libdir in $compile_rpath $finalize_rpath; do
+ if test -n "$hardcode_libdir_flag_spec"; then
+ if test -n "$hardcode_libdir_separator"; then
+ if test -z "$hardcode_libdirs"; then
+ hardcode_libdirs=$libdir
+ else
+ # Just accumulate the unique libdirs.
+ case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in
+ *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*)
+ ;;
+ *)
+ func_append hardcode_libdirs "$hardcode_libdir_separator$libdir"
+ ;;
+ esac
+ fi
+ else
+ eval flag=\"$hardcode_libdir_flag_spec\"
+ func_append rpath " $flag"
+ fi
+ elif test -n "$runpath_var"; then
+ case "$perm_rpath " in
+ *" $libdir "*) ;;
+ *) func_append perm_rpath " $libdir" ;;
+ esac
+ fi
+ case $host in
+ *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*)
+ testbindir=`$ECHO "$libdir" | $SED -e 's*/lib$*/bin*'`
+ case :$dllsearchpath: in
+ *":$libdir:"*) ;;
+ ::) dllsearchpath=$libdir;;
+ *) func_append dllsearchpath ":$libdir";;
+ esac
+ case :$dllsearchpath: in
+ *":$testbindir:"*) ;;
+ ::) dllsearchpath=$testbindir;;
+ *) func_append dllsearchpath ":$testbindir";;
+ esac
+ ;;
+ esac
+ done
+ # Substitute the hardcoded libdirs into the rpath.
+ if test -n "$hardcode_libdir_separator" &&
+ test -n "$hardcode_libdirs"; then
+ libdir=$hardcode_libdirs
+ eval rpath=\" $hardcode_libdir_flag_spec\"
+ fi
+ compile_rpath=$rpath
+
+ rpath=
+ hardcode_libdirs=
+ for libdir in $finalize_rpath; do
+ if test -n "$hardcode_libdir_flag_spec"; then
+ if test -n "$hardcode_libdir_separator"; then
+ if test -z "$hardcode_libdirs"; then
+ hardcode_libdirs=$libdir
+ else
+ # Just accumulate the unique libdirs.
+ case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in
+ *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*)
+ ;;
+ *)
+ func_append hardcode_libdirs "$hardcode_libdir_separator$libdir"
+ ;;
+ esac
+ fi
+ else
+ eval flag=\"$hardcode_libdir_flag_spec\"
+ func_append rpath " $flag"
+ fi
+ elif test -n "$runpath_var"; then
+ case "$finalize_perm_rpath " in
+ *" $libdir "*) ;;
+ *) func_append finalize_perm_rpath " $libdir" ;;
+ esac
+ fi
+ done
+ # Substitute the hardcoded libdirs into the rpath.
+ if test -n "$hardcode_libdir_separator" &&
+ test -n "$hardcode_libdirs"; then
+ libdir=$hardcode_libdirs
+ eval rpath=\" $hardcode_libdir_flag_spec\"
+ fi
+ finalize_rpath=$rpath
+
+ if test -n "$libobjs" && test yes = "$build_old_libs"; then
+ # Transform all the library objects into standard objects.
+ compile_command=`$ECHO "$compile_command" | $SP2NL | $SED "$lo2o" | $NL2SP`
+ finalize_command=`$ECHO "$finalize_command" | $SP2NL | $SED "$lo2o" | $NL2SP`
+ fi
+
+ func_generate_dlsyms "$outputname" "@PROGRAM@" false
+
+ # template prelinking step
+ if test -n "$prelink_cmds"; then
+ func_execute_cmds "$prelink_cmds" 'exit $?'
+ fi
+
+ wrappers_required=:
+ case $host in
+ *cegcc* | *mingw32ce*)
+ # Disable wrappers for cegcc and mingw32ce hosts, we are cross compiling anyway.
+ wrappers_required=false
+ ;;
+ *cygwin* | *mingw* )
+ test yes = "$build_libtool_libs" || wrappers_required=false
+ ;;
+ *)
+ if test no = "$need_relink" || test yes != "$build_libtool_libs"; then
+ wrappers_required=false
+ fi
+ ;;
+ esac
+ $wrappers_required || {
+ # Replace the output file specification.
+ compile_command=`$ECHO "$compile_command" | $SED 's%@OUTPUT@%'"$output"'%g'`
+ link_command=$compile_command$compile_rpath
+
+ # We have no uninstalled library dependencies, so finalize right now.
+ exit_status=0
+ func_show_eval "$link_command" 'exit_status=$?'
+
+ if test -n "$postlink_cmds"; then
+ func_to_tool_file "$output"
+ postlink_cmds=`func_echo_all "$postlink_cmds" | $SED -e 's%@OUTPUT@%'"$output"'%g' -e 's%@TOOL_OUTPUT@%'"$func_to_tool_file_result"'%g'`
+ func_execute_cmds "$postlink_cmds" 'exit $?'
+ fi
+
+ # Delete the generated files.
+ if test -f "$output_objdir/${outputname}S.$objext"; then
+ func_show_eval '$RM "$output_objdir/${outputname}S.$objext"'
+ fi
+
+ exit $exit_status
+ }
+
+ if test -n "$compile_shlibpath$finalize_shlibpath"; then
+ compile_command="$shlibpath_var=\"$compile_shlibpath$finalize_shlibpath\$$shlibpath_var\" $compile_command"
+ fi
+ if test -n "$finalize_shlibpath"; then
+ finalize_command="$shlibpath_var=\"$finalize_shlibpath\$$shlibpath_var\" $finalize_command"
+ fi
+
+ compile_var=
+ finalize_var=
+ if test -n "$runpath_var"; then
+ if test -n "$perm_rpath"; then
+ # We should set the runpath_var.
+ rpath=
+ for dir in $perm_rpath; do
+ func_append rpath "$dir:"
+ done
+ compile_var="$runpath_var=\"$rpath\$$runpath_var\" "
+ fi
+ if test -n "$finalize_perm_rpath"; then
+ # We should set the runpath_var.
+ rpath=
+ for dir in $finalize_perm_rpath; do
+ func_append rpath "$dir:"
+ done
+ finalize_var="$runpath_var=\"$rpath\$$runpath_var\" "
+ fi
+ fi
+
+ if test yes = "$no_install"; then
+ # We don't need to create a wrapper script.
+ link_command=$compile_var$compile_command$compile_rpath
+ # Replace the output file specification.
+ link_command=`$ECHO "$link_command" | $SED 's%@OUTPUT@%'"$output"'%g'`
+ # Delete the old output file.
+ $opt_dry_run || $RM $output
+ # Link the executable and exit
+ func_show_eval "$link_command" 'exit $?'
+
+ if test -n "$postlink_cmds"; then
+ func_to_tool_file "$output"
+ postlink_cmds=`func_echo_all "$postlink_cmds" | $SED -e 's%@OUTPUT@%'"$output"'%g' -e 's%@TOOL_OUTPUT@%'"$func_to_tool_file_result"'%g'`
+ func_execute_cmds "$postlink_cmds" 'exit $?'
+ fi
+
+ exit $EXIT_SUCCESS
+ fi
+
+ case $hardcode_action,$fast_install in
+ relink,*)
+ # Fast installation is not supported
+ link_command=$compile_var$compile_command$compile_rpath
+ relink_command=$finalize_var$finalize_command$finalize_rpath
+
+ func_warning "this platform does not like uninstalled shared libraries"
+ func_warning "'$output' will be relinked during installation"
+ ;;
+ *,yes)
+ link_command=$finalize_var$compile_command$finalize_rpath
+ relink_command=`$ECHO "$compile_var$compile_command$compile_rpath" | $SED 's%@OUTPUT@%\$progdir/\$file%g'`
+ ;;
+ *,no)
+ link_command=$compile_var$compile_command$compile_rpath
+ relink_command=$finalize_var$finalize_command$finalize_rpath
+ ;;
+ *,needless)
+ link_command=$finalize_var$compile_command$finalize_rpath
+ relink_command=
+ ;;
+ esac
+
+ # Replace the output file specification.
+ link_command=`$ECHO "$link_command" | $SED 's%@OUTPUT@%'"$output_objdir/$outputname"'%g'`
+
+ # Delete the old output files.
+ $opt_dry_run || $RM $output $output_objdir/$outputname $output_objdir/lt-$outputname
+
+ func_show_eval "$link_command" 'exit $?'
+
+ if test -n "$postlink_cmds"; then
+ func_to_tool_file "$output_objdir/$outputname"
+ postlink_cmds=`func_echo_all "$postlink_cmds" | $SED -e 's%@OUTPUT@%'"$output_objdir/$outputname"'%g' -e 's%@TOOL_OUTPUT@%'"$func_to_tool_file_result"'%g'`
+ func_execute_cmds "$postlink_cmds" 'exit $?'
+ fi
+
+ # Now create the wrapper script.
+ func_verbose "creating $output"
+
+ # Quote the relink command for shipping.
+ if test -n "$relink_command"; then
+ # Preserve any variables that may affect compiler behavior
+ for var in $variables_saved_for_relink; do
+ if eval test -z \"\${$var+set}\"; then
+ relink_command="{ test -z \"\${$var+set}\" || $lt_unset $var || { $var=; export $var; }; }; $relink_command"
+ elif eval var_value=\$$var; test -z "$var_value"; then
+ relink_command="$var=; export $var; $relink_command"
+ else
+ func_quote_for_eval "$var_value"
+ relink_command="$var=$func_quote_for_eval_result; export $var; $relink_command"
+ fi
+ done
+ relink_command="(cd `pwd`; $relink_command)"
+ relink_command=`$ECHO "$relink_command" | $SED "$sed_quote_subst"`
+ fi
+
+ # Only actually do things if not in dry run mode.
+ $opt_dry_run || {
+ # win32 will think the script is a binary if it has
+ # a .exe suffix, so we strip it off here.
+ case $output in
+ *.exe) func_stripname '' '.exe' "$output"
+ output=$func_stripname_result ;;
+ esac
+ # test for cygwin because mv fails w/o .exe extensions
+ case $host in
+ *cygwin*)
+ exeext=.exe
+ func_stripname '' '.exe' "$outputname"
+ outputname=$func_stripname_result ;;
+ *) exeext= ;;
+ esac
+ case $host in
+ *cygwin* | *mingw* )
+ func_dirname_and_basename "$output" "" "."
+ output_name=$func_basename_result
+ output_path=$func_dirname_result
+ cwrappersource=$output_path/$objdir/lt-$output_name.c
+ cwrapper=$output_path/$output_name.exe
+ $RM $cwrappersource $cwrapper
+ trap "$RM $cwrappersource $cwrapper; exit $EXIT_FAILURE" 1 2 15
+
+ func_emit_cwrapperexe_src > $cwrappersource
+
+ # The wrapper executable is built using the $host compiler,
+ # because it contains $host paths and files. If cross-
+ # compiling, it, like the target executable, must be
+ # executed on the $host or under an emulation environment.
+ $opt_dry_run || {
+ $LTCC $LTCFLAGS -o $cwrapper $cwrappersource
+ $STRIP $cwrapper
+ }
+
+ # Now, create the wrapper script for func_source use:
+ func_ltwrapper_scriptname $cwrapper
+ $RM $func_ltwrapper_scriptname_result
+ trap "$RM $func_ltwrapper_scriptname_result; exit $EXIT_FAILURE" 1 2 15
+ $opt_dry_run || {
+ # note: this script will not be executed, so do not chmod.
+ if test "x$build" = "x$host"; then
+ $cwrapper --lt-dump-script > $func_ltwrapper_scriptname_result
+ else
+ func_emit_wrapper no > $func_ltwrapper_scriptname_result
+ fi
+ }
+ ;;
+ * )
+ $RM $output
+ trap "$RM $output; exit $EXIT_FAILURE" 1 2 15
+
+ func_emit_wrapper no > $output
+ chmod +x $output
+ ;;
+ esac
+ }
+ exit $EXIT_SUCCESS
+ ;;
+ esac
+
+ # See if we need to build an old-fashioned archive.
+ for oldlib in $oldlibs; do
+
+ case $build_libtool_libs in
+ convenience)
+ oldobjs="$libobjs_save $symfileobj"
+ addlibs=$convenience
+ build_libtool_libs=no
+ ;;
+ module)
+ oldobjs=$libobjs_save
+ addlibs=$old_convenience
+ build_libtool_libs=no
+ ;;
+ *)
+ oldobjs="$old_deplibs $non_pic_objects"
+ $preload && test -f "$symfileobj" \
+ && func_append oldobjs " $symfileobj"
+ addlibs=$old_convenience
+ ;;
+ esac
+
+ if test -n "$addlibs"; then
+ gentop=$output_objdir/${outputname}x
+ func_append generated " $gentop"
+
+ func_extract_archives $gentop $addlibs
+ func_append oldobjs " $func_extract_archives_result"
+ fi
+
+ # Do each command in the archive commands.
+ if test -n "$old_archive_from_new_cmds" && test yes = "$build_libtool_libs"; then
+ cmds=$old_archive_from_new_cmds
+ else
+
+ # Add any objects from preloaded convenience libraries
+ if test -n "$dlprefiles"; then
+ gentop=$output_objdir/${outputname}x
+ func_append generated " $gentop"
+
+ func_extract_archives $gentop $dlprefiles
+ func_append oldobjs " $func_extract_archives_result"
+ fi
+
+ # POSIX demands no paths to be encoded in archives. We have
+ # to avoid creating archives with duplicate basenames if we
+ # might have to extract them afterwards, e.g., when creating a
+ # static archive out of a convenience library, or when linking
+ # the entirety of a libtool archive into another (currently
+ # not supported by libtool).
+ if (for obj in $oldobjs
+ do
+ func_basename "$obj"
+ $ECHO "$func_basename_result"
+ done | sort | sort -uc >/dev/null 2>&1); then
+ :
+ else
+ echo "copying selected object files to avoid basename conflicts..."
+ gentop=$output_objdir/${outputname}x
+ func_append generated " $gentop"
+ func_mkdir_p "$gentop"
+ save_oldobjs=$oldobjs
+ oldobjs=
+ counter=1
+ for obj in $save_oldobjs
+ do
+ func_basename "$obj"
+ objbase=$func_basename_result
+ case " $oldobjs " in
+ " ") oldobjs=$obj ;;
+ *[\ /]"$objbase "*)
+ while :; do
+ # Make sure we don't pick an alternate name that also
+ # overlaps.
+ newobj=lt$counter-$objbase
+ func_arith $counter + 1
+ counter=$func_arith_result
+ case " $oldobjs " in
+ *[\ /]"$newobj "*) ;;
+ *) if test ! -f "$gentop/$newobj"; then break; fi ;;
+ esac
+ done
+ func_show_eval "ln $obj $gentop/$newobj || cp $obj $gentop/$newobj"
+ func_append oldobjs " $gentop/$newobj"
+ ;;
+ *) func_append oldobjs " $obj" ;;
+ esac
+ done
+ fi
+ func_to_tool_file "$oldlib" func_convert_file_msys_to_w32
+ tool_oldlib=$func_to_tool_file_result
+ eval cmds=\"$old_archive_cmds\"
+
+ func_len " $cmds"
+ len=$func_len_result
+ if test "$len" -lt "$max_cmd_len" || test "$max_cmd_len" -le -1; then
+ cmds=$old_archive_cmds
+ elif test -n "$archiver_list_spec"; then
+ func_verbose "using command file archive linking..."
+ for obj in $oldobjs
+ do
+ func_to_tool_file "$obj"
+ $ECHO "$func_to_tool_file_result"
+ done > $output_objdir/$libname.libcmd
+ func_to_tool_file "$output_objdir/$libname.libcmd"
+ oldobjs=" $archiver_list_spec$func_to_tool_file_result"
+ cmds=$old_archive_cmds
+ else
+ # the command line is too long to link in one step, link in parts
+ func_verbose "using piecewise archive linking..."
+ save_RANLIB=$RANLIB
+ RANLIB=:
+ objlist=
+ concat_cmds=
+ save_oldobjs=$oldobjs
+ oldobjs=
+ # Is there a better way of finding the last object in the list?
+ for obj in $save_oldobjs
+ do
+ last_oldobj=$obj
+ done
+ eval test_cmds=\"$old_archive_cmds\"
+ func_len " $test_cmds"
+ len0=$func_len_result
+ len=$len0
+ for obj in $save_oldobjs
+ do
+ func_len " $obj"
+ func_arith $len + $func_len_result
+ len=$func_arith_result
+ func_append objlist " $obj"
+ if test "$len" -lt "$max_cmd_len"; then
+ :
+ else
+ # the above command should be used before it gets too long
+ oldobjs=$objlist
+ if test "$obj" = "$last_oldobj"; then
+ RANLIB=$save_RANLIB
+ fi
+ test -z "$concat_cmds" || concat_cmds=$concat_cmds~
+ eval concat_cmds=\"\$concat_cmds$old_archive_cmds\"
+ objlist=
+ len=$len0
+ fi
+ done
+ RANLIB=$save_RANLIB
+ oldobjs=$objlist
+ if test -z "$oldobjs"; then
+ eval cmds=\"\$concat_cmds\"
+ else
+ eval cmds=\"\$concat_cmds~\$old_archive_cmds\"
+ fi
+ fi
+ fi
+ func_execute_cmds "$cmds" 'exit $?'
+ done
+
+ test -n "$generated" && \
+ func_show_eval "${RM}r$generated"
+
+ # Now create the libtool archive.
+ case $output in
+ *.la)
+ old_library=
+ test yes = "$build_old_libs" && old_library=$libname.$libext
+ func_verbose "creating $output"
+
+ # Preserve any variables that may affect compiler behavior
+ for var in $variables_saved_for_relink; do
+ if eval test -z \"\${$var+set}\"; then
+ relink_command="{ test -z \"\${$var+set}\" || $lt_unset $var || { $var=; export $var; }; }; $relink_command"
+ elif eval var_value=\$$var; test -z "$var_value"; then
+ relink_command="$var=; export $var; $relink_command"
+ else
+ func_quote_for_eval "$var_value"
+ relink_command="$var=$func_quote_for_eval_result; export $var; $relink_command"
+ fi
+ done
+ # Quote the link command for shipping.
+ relink_command="(cd `pwd`; $SHELL \"$progpath\" $preserve_args --mode=relink $libtool_args @inst_prefix_dir@)"
+ relink_command=`$ECHO "$relink_command" | $SED "$sed_quote_subst"`
+ if test yes = "$hardcode_automatic"; then
+ relink_command=
+ fi
+
+ # Only create the output if not a dry run.
+ $opt_dry_run || {
+ for installed in no yes; do
+ if test yes = "$installed"; then
+ if test -z "$install_libdir"; then
+ break
+ fi
+ output=$output_objdir/${outputname}i
+ # Replace all uninstalled libtool libraries with the installed ones
+ newdependency_libs=
+ for deplib in $dependency_libs; do
+ case $deplib in
+ *.la)
+ func_basename "$deplib"
+ name=$func_basename_result
+ func_resolve_sysroot "$deplib"
+ eval libdir=`$SED -n -e 's/^libdir=\(.*\)$/\1/p' $func_resolve_sysroot_result`
+ test -z "$libdir" && \
+ func_fatal_error "'$deplib' is not a valid libtool archive"
+ func_append newdependency_libs " ${lt_sysroot:+=}$libdir/$name"
+ ;;
+ -L*)
+ func_stripname -L '' "$deplib"
+ func_replace_sysroot "$func_stripname_result"
+ func_append newdependency_libs " -L$func_replace_sysroot_result"
+ ;;
+ -R*)
+ func_stripname -R '' "$deplib"
+ func_replace_sysroot "$func_stripname_result"
+ func_append newdependency_libs " -R$func_replace_sysroot_result"
+ ;;
+ *) func_append newdependency_libs " $deplib" ;;
+ esac
+ done
+ dependency_libs=$newdependency_libs
+ newdlfiles=
+
+ for lib in $dlfiles; do
+ case $lib in
+ *.la)
+ func_basename "$lib"
+ name=$func_basename_result
+ eval libdir=`$SED -n -e 's/^libdir=\(.*\)$/\1/p' $lib`
+ test -z "$libdir" && \
+ func_fatal_error "'$lib' is not a valid libtool archive"
+ func_append newdlfiles " ${lt_sysroot:+=}$libdir/$name"
+ ;;
+ *) func_append newdlfiles " $lib" ;;
+ esac
+ done
+ dlfiles=$newdlfiles
+ newdlprefiles=
+ for lib in $dlprefiles; do
+ case $lib in
+ *.la)
+ # Only pass preopened files to the pseudo-archive (for
+ # eventual linking with the app. that links it) if we
+ # didn't already link the preopened objects directly into
+ # the library:
+ func_basename "$lib"
+ name=$func_basename_result
+ eval libdir=`$SED -n -e 's/^libdir=\(.*\)$/\1/p' $lib`
+ test -z "$libdir" && \
+ func_fatal_error "'$lib' is not a valid libtool archive"
+ func_append newdlprefiles " ${lt_sysroot:+=}$libdir/$name"
+ ;;
+ esac
+ done
+ dlprefiles=$newdlprefiles
+ else
+ newdlfiles=
+ for lib in $dlfiles; do
+ case $lib in
+ [\\/]* | [A-Za-z]:[\\/]*) abs=$lib ;;
+ *) abs=`pwd`"/$lib" ;;
+ esac
+ func_append newdlfiles " $abs"
+ done
+ dlfiles=$newdlfiles
+ newdlprefiles=
+ for lib in $dlprefiles; do
+ case $lib in
+ [\\/]* | [A-Za-z]:[\\/]*) abs=$lib ;;
+ *) abs=`pwd`"/$lib" ;;
+ esac
+ func_append newdlprefiles " $abs"
+ done
+ dlprefiles=$newdlprefiles
+ fi
+ $RM $output
+ # place dlname in correct position for cygwin
+ # In fact, it would be nice if we could use this code for all target
+ # systems that can't hard-code library paths into their executables
+ # and that have no shared library path variable independent of PATH,
+ # but it turns out we can't easily determine that from inspecting
+ # libtool variables, so we have to hard-code the OSs to which it
+ # applies here; at the moment, that means platforms that use the PE
+ # object format with DLL files. See the long comment at the top of
+ # tests/bindir.at for full details.
+ tdlname=$dlname
+ case $host,$output,$installed,$module,$dlname in
+ *cygwin*,*lai,yes,no,*.dll | *mingw*,*lai,yes,no,*.dll | *cegcc*,*lai,yes,no,*.dll)
+ # If a -bindir argument was supplied, place the dll there.
+ if test -n "$bindir"; then
+ func_relative_path "$install_libdir" "$bindir"
+ tdlname=$func_relative_path_result/$dlname
+ else
+ # Otherwise fall back on heuristic.
+ tdlname=../bin/$dlname
+ fi
+ ;;
+ esac
+ $ECHO > $output "\
+# $outputname - a libtool library file
+# Generated by $PROGRAM (GNU $PACKAGE) $VERSION
+#
+# Please DO NOT delete this file!
+# It is necessary for linking the library.
+
+# The name that we can dlopen(3).
+dlname='$tdlname'
+
+# Names of this library.
+library_names='$library_names'
+
+# The name of the static archive.
+old_library='$old_library'
+
+# Linker flags that cannot go in dependency_libs.
+inherited_linker_flags='$new_inherited_linker_flags'
+
+# Libraries that this one depends upon.
+dependency_libs='$dependency_libs'
+
+# Names of additional weak libraries provided by this library
+weak_library_names='$weak_libs'
+
+# Version information for $libname.
+current=$current
+age=$age
+revision=$revision
+
+# Is this an already installed library?
+installed=$installed
+
+# Should we warn about portability when linking against -modules?
+shouldnotlink=$module
+
+# Files to dlopen/dlpreopen
+dlopen='$dlfiles'
+dlpreopen='$dlprefiles'
+
+# Directory that this library needs to be installed in:
+libdir='$install_libdir'"
+ if test no,yes = "$installed,$need_relink"; then
+ $ECHO >> $output "\
+relink_command=\"$relink_command\""
+ fi
+ done
+ }
+
+ # Do a symbolic link so that the libtool archive can be found in
+ # LD_LIBRARY_PATH before the program is installed.
+ func_show_eval '( cd "$output_objdir" && $RM "$outputname" && $LN_S "../$outputname" "$outputname" )' 'exit $?'
+ ;;
+ esac
+ exit $EXIT_SUCCESS
+}
+
+if test link = "$opt_mode" || test relink = "$opt_mode"; then
+ func_mode_link ${1+"$@"}
+fi
+
+
+# func_mode_uninstall arg...
+func_mode_uninstall ()
+{
+ $debug_cmd
+
+ RM=$nonopt
+ files=
+ rmforce=false
+ exit_status=0
+
+ # This variable tells wrapper scripts just to set variables rather
+ # than running their programs.
+ libtool_install_magic=$magic
+
+ for arg
+ do
+ case $arg in
+ -f) func_append RM " $arg"; rmforce=: ;;
+ -*) func_append RM " $arg" ;;
+ *) func_append files " $arg" ;;
+ esac
+ done
+
+ test -z "$RM" && \
+ func_fatal_help "you must specify an RM program"
+
+ rmdirs=
+
+ for file in $files; do
+ func_dirname "$file" "" "."
+ dir=$func_dirname_result
+ if test . = "$dir"; then
+ odir=$objdir
+ else
+ odir=$dir/$objdir
+ fi
+ func_basename "$file"
+ name=$func_basename_result
+ test uninstall = "$opt_mode" && odir=$dir
+
+ # Remember odir for removal later, being careful to avoid duplicates
+ if test clean = "$opt_mode"; then
+ case " $rmdirs " in
+ *" $odir "*) ;;
+ *) func_append rmdirs " $odir" ;;
+ esac
+ fi
+
+ # Don't error if the file doesn't exist and rm -f was used.
+ if { test -L "$file"; } >/dev/null 2>&1 ||
+ { test -h "$file"; } >/dev/null 2>&1 ||
+ test -f "$file"; then
+ :
+ elif test -d "$file"; then
+ exit_status=1
+ continue
+ elif $rmforce; then
+ continue
+ fi
+
+ rmfiles=$file
+
+ case $name in
+ *.la)
+ # Possibly a libtool archive, so verify it.
+ if func_lalib_p "$file"; then
+ func_source $dir/$name
+
+ # Delete the libtool libraries and symlinks.
+ for n in $library_names; do
+ func_append rmfiles " $odir/$n"
+ done
+ test -n "$old_library" && func_append rmfiles " $odir/$old_library"
+
+ case $opt_mode in
+ clean)
+ case " $library_names " in
+ *" $dlname "*) ;;
+ *) test -n "$dlname" && func_append rmfiles " $odir/$dlname" ;;
+ esac
+ test -n "$libdir" && func_append rmfiles " $odir/$name $odir/${name}i"
+ ;;
+ uninstall)
+ if test -n "$library_names"; then
+ # Do each command in the postuninstall commands.
+ func_execute_cmds "$postuninstall_cmds" '$rmforce || exit_status=1'
+ fi
+
+ if test -n "$old_library"; then
+ # Do each command in the old_postuninstall commands.
+ func_execute_cmds "$old_postuninstall_cmds" '$rmforce || exit_status=1'
+ fi
+ # FIXME: should reinstall the best remaining shared library.
+ ;;
+ esac
+ fi
+ ;;
+
+ *.lo)
+ # Possibly a libtool object, so verify it.
+ if func_lalib_p "$file"; then
+
+ # Read the .lo file
+ func_source $dir/$name
+
+ # Add PIC object to the list of files to remove.
+ if test -n "$pic_object" && test none != "$pic_object"; then
+ func_append rmfiles " $dir/$pic_object"
+ fi
+
+ # Add non-PIC object to the list of files to remove.
+ if test -n "$non_pic_object" && test none != "$non_pic_object"; then
+ func_append rmfiles " $dir/$non_pic_object"
+ fi
+ fi
+ ;;
+
+ *)
+ if test clean = "$opt_mode"; then
+ noexename=$name
+ case $file in
+ *.exe)
+ func_stripname '' '.exe' "$file"
+ file=$func_stripname_result
+ func_stripname '' '.exe' "$name"
+ noexename=$func_stripname_result
+ # $file with .exe has already been added to rmfiles,
+ # add $file without .exe
+ func_append rmfiles " $file"
+ ;;
+ esac
+ # Do a test to see if this is a libtool program.
+ if func_ltwrapper_p "$file"; then
+ if func_ltwrapper_executable_p "$file"; then
+ func_ltwrapper_scriptname "$file"
+ relink_command=
+ func_source $func_ltwrapper_scriptname_result
+ func_append rmfiles " $func_ltwrapper_scriptname_result"
+ else
+ relink_command=
+ func_source $dir/$noexename
+ fi
+
+ # note $name still contains .exe if it was in $file originally
+ # as does the version of $file that was added into $rmfiles
+ func_append rmfiles " $odir/$name $odir/${name}S.$objext"
+ if test yes = "$fast_install" && test -n "$relink_command"; then
+ func_append rmfiles " $odir/lt-$name"
+ fi
+ if test "X$noexename" != "X$name"; then
+ func_append rmfiles " $odir/lt-$noexename.c"
+ fi
+ fi
+ fi
+ ;;
+ esac
+ func_show_eval "$RM $rmfiles" 'exit_status=1'
+ done
+
+ # Try to remove the $objdir's in the directories where we deleted files
+ for dir in $rmdirs; do
+ if test -d "$dir"; then
+ func_show_eval "rmdir $dir >/dev/null 2>&1"
+ fi
+ done
+
+ exit $exit_status
+}
+
+if test uninstall = "$opt_mode" || test clean = "$opt_mode"; then
+ func_mode_uninstall ${1+"$@"}
+fi
+
+test -z "$opt_mode" && {
+ help=$generic_help
+ func_fatal_help "you must specify a MODE"
+}
+
+test -z "$exec_cmd" && \
+ func_fatal_help "invalid operation mode '$opt_mode'"
+
+if test -n "$exec_cmd"; then
+ eval exec "$exec_cmd"
+ exit $EXIT_FAILURE
+fi
+
+exit $exit_status
+
+
+# The TAGs below are defined such that we never get into a situation
+# where we disable both kinds of libraries. Given conflicting
+# choices, we go for a static library, that is the most portable,
+# since we can't tell whether shared libraries were disabled because
+# the user asked for that or because the platform doesn't support
+# them. This is particularly important on AIX, because we don't
+# support having both static and shared libraries enabled at the same
+# time on that platform, so we default to a shared-only configuration.
+# If a disable-shared tag is given, we'll fallback to a static-only
+# configuration. But we'll never go from static-only to shared-only.
+
+# ### BEGIN LIBTOOL TAG CONFIG: disable-shared
+build_libtool_libs=no
+build_old_libs=yes
+# ### END LIBTOOL TAG CONFIG: disable-shared
+
+# ### BEGIN LIBTOOL TAG CONFIG: disable-static
+build_old_libs=`case $build_libtool_libs in yes) echo no;; *) echo yes;; esac`
+# ### END LIBTOOL TAG CONFIG: disable-static
+
+# Local Variables:
+# mode:shell-script
+# sh-indentation:2
+# End:
diff --git a/m4/libtool.m4 b/m4/libtool.m4
new file mode 100644
index 0000000..10ab284
--- /dev/null
+++ b/m4/libtool.m4
@@ -0,0 +1,8388 @@
+# libtool.m4 - Configure libtool for the host system. -*-Autoconf-*-
+#
+# Copyright (C) 1996-2001, 2003-2015 Free Software Foundation, Inc.
+# Written by Gordon Matzigkeit, 1996
+#
+# This file is free software; the Free Software Foundation gives
+# unlimited permission to copy and/or distribute it, with or without
+# modifications, as long as this notice is preserved.
+
+m4_define([_LT_COPYING], [dnl
+# Copyright (C) 2014 Free Software Foundation, Inc.
+# This is free software; see the source for copying conditions. There is NO
+# warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+# GNU Libtool 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 of the License, or
+# (at your option) any later version.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program or library that is built
+# using GNU Libtool, you may include this file under the same
+# distribution terms that you use for the rest of that program.
+#
+# GNU Libtool 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/>.
+])
+
+# serial 58 LT_INIT
+
+
+# LT_PREREQ(VERSION)
+# ------------------
+# Complain and exit if this libtool version is less that VERSION.
+m4_defun([LT_PREREQ],
+[m4_if(m4_version_compare(m4_defn([LT_PACKAGE_VERSION]), [$1]), -1,
+ [m4_default([$3],
+ [m4_fatal([Libtool version $1 or higher is required],
+ 63)])],
+ [$2])])
+
+
+# _LT_CHECK_BUILDDIR
+# ------------------
+# Complain if the absolute build directory name contains unusual characters
+m4_defun([_LT_CHECK_BUILDDIR],
+[case `pwd` in
+ *\ * | *\ *)
+ AC_MSG_WARN([Libtool does not cope well with whitespace in `pwd`]) ;;
+esac
+])
+
+
+# LT_INIT([OPTIONS])
+# ------------------
+AC_DEFUN([LT_INIT],
+[AC_PREREQ([2.62])dnl We use AC_PATH_PROGS_FEATURE_CHECK
+AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT])dnl
+AC_BEFORE([$0], [LT_LANG])dnl
+AC_BEFORE([$0], [LT_OUTPUT])dnl
+AC_BEFORE([$0], [LTDL_INIT])dnl
+m4_require([_LT_CHECK_BUILDDIR])dnl
+
+dnl Autoconf doesn't catch unexpanded LT_ macros by default:
+m4_pattern_forbid([^_?LT_[A-Z_]+$])dnl
+m4_pattern_allow([^(_LT_EOF|LT_DLGLOBAL|LT_DLLAZY_OR_NOW|LT_MULTI_MODULE)$])dnl
+dnl aclocal doesn't pull ltoptions.m4, ltsugar.m4, or ltversion.m4
+dnl unless we require an AC_DEFUNed macro:
+AC_REQUIRE([LTOPTIONS_VERSION])dnl
+AC_REQUIRE([LTSUGAR_VERSION])dnl
+AC_REQUIRE([LTVERSION_VERSION])dnl
+AC_REQUIRE([LTOBSOLETE_VERSION])dnl
+m4_require([_LT_PROG_LTMAIN])dnl
+
+_LT_SHELL_INIT([SHELL=${CONFIG_SHELL-/bin/sh}])
+
+dnl Parse OPTIONS
+_LT_SET_OPTIONS([$0], [$1])
+
+# This can be used to rebuild libtool when needed
+LIBTOOL_DEPS=$ltmain
+
+# Always use our own libtool.
+LIBTOOL='$(SHELL) $(top_builddir)/libtool'
+AC_SUBST(LIBTOOL)dnl
+
+_LT_SETUP
+
+# Only expand once:
+m4_define([LT_INIT])
+])# LT_INIT
+
+# Old names:
+AU_ALIAS([AC_PROG_LIBTOOL], [LT_INIT])
+AU_ALIAS([AM_PROG_LIBTOOL], [LT_INIT])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_PROG_LIBTOOL], [])
+dnl AC_DEFUN([AM_PROG_LIBTOOL], [])
+
+
+# _LT_PREPARE_CC_BASENAME
+# -----------------------
+m4_defun([_LT_PREPARE_CC_BASENAME], [
+# Calculate cc_basename. Skip known compiler wrappers and cross-prefix.
+func_cc_basename ()
+{
+ for cc_temp in @S|@*""; do
+ case $cc_temp in
+ compile | *[[\\/]]compile | ccache | *[[\\/]]ccache ) ;;
+ distcc | *[[\\/]]distcc | purify | *[[\\/]]purify ) ;;
+ \-*) ;;
+ *) break;;
+ esac
+ done
+ func_cc_basename_result=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"`
+}
+])# _LT_PREPARE_CC_BASENAME
+
+
+# _LT_CC_BASENAME(CC)
+# -------------------
+# It would be clearer to call AC_REQUIREs from _LT_PREPARE_CC_BASENAME,
+# but that macro is also expanded into generated libtool script, which
+# arranges for $SED and $ECHO to be set by different means.
+m4_defun([_LT_CC_BASENAME],
+[m4_require([_LT_PREPARE_CC_BASENAME])dnl
+AC_REQUIRE([_LT_DECL_SED])dnl
+AC_REQUIRE([_LT_PROG_ECHO_BACKSLASH])dnl
+func_cc_basename $1
+cc_basename=$func_cc_basename_result
+])
+
+
+# _LT_FILEUTILS_DEFAULTS
+# ----------------------
+# It is okay to use these file commands and assume they have been set
+# sensibly after 'm4_require([_LT_FILEUTILS_DEFAULTS])'.
+m4_defun([_LT_FILEUTILS_DEFAULTS],
+[: ${CP="cp -f"}
+: ${MV="mv -f"}
+: ${RM="rm -f"}
+])# _LT_FILEUTILS_DEFAULTS
+
+
+# _LT_SETUP
+# ---------
+m4_defun([_LT_SETUP],
+[AC_REQUIRE([AC_CANONICAL_HOST])dnl
+AC_REQUIRE([AC_CANONICAL_BUILD])dnl
+AC_REQUIRE([_LT_PREPARE_SED_QUOTE_VARS])dnl
+AC_REQUIRE([_LT_PROG_ECHO_BACKSLASH])dnl
+
+_LT_DECL([], [PATH_SEPARATOR], [1], [The PATH separator for the build system])dnl
+dnl
+_LT_DECL([], [host_alias], [0], [The host system])dnl
+_LT_DECL([], [host], [0])dnl
+_LT_DECL([], [host_os], [0])dnl
+dnl
+_LT_DECL([], [build_alias], [0], [The build system])dnl
+_LT_DECL([], [build], [0])dnl
+_LT_DECL([], [build_os], [0])dnl
+dnl
+AC_REQUIRE([AC_PROG_CC])dnl
+AC_REQUIRE([LT_PATH_LD])dnl
+AC_REQUIRE([LT_PATH_NM])dnl
+dnl
+AC_REQUIRE([AC_PROG_LN_S])dnl
+test -z "$LN_S" && LN_S="ln -s"
+_LT_DECL([], [LN_S], [1], [Whether we need soft or hard links])dnl
+dnl
+AC_REQUIRE([LT_CMD_MAX_LEN])dnl
+_LT_DECL([objext], [ac_objext], [0], [Object file suffix (normally "o")])dnl
+_LT_DECL([], [exeext], [0], [Executable file suffix (normally "")])dnl
+dnl
+m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+m4_require([_LT_CHECK_SHELL_FEATURES])dnl
+m4_require([_LT_PATH_CONVERSION_FUNCTIONS])dnl
+m4_require([_LT_CMD_RELOAD])dnl
+m4_require([_LT_CHECK_MAGIC_METHOD])dnl
+m4_require([_LT_CHECK_SHAREDLIB_FROM_LINKLIB])dnl
+m4_require([_LT_CMD_OLD_ARCHIVE])dnl
+m4_require([_LT_CMD_GLOBAL_SYMBOLS])dnl
+m4_require([_LT_WITH_SYSROOT])dnl
+m4_require([_LT_CMD_TRUNCATE])dnl
+
+_LT_CONFIG_LIBTOOL_INIT([
+# See if we are running on zsh, and set the options that allow our
+# commands through without removal of \ escapes INIT.
+if test -n "\${ZSH_VERSION+set}"; then
+ setopt NO_GLOB_SUBST
+fi
+])
+if test -n "${ZSH_VERSION+set}"; then
+ setopt NO_GLOB_SUBST
+fi
+
+_LT_CHECK_OBJDIR
+
+m4_require([_LT_TAG_COMPILER])dnl
+
+case $host_os in
+aix3*)
+ # AIX sometimes has problems with the GCC collect2 program. For some
+ # reason, if we set the COLLECT_NAMES environment variable, the problems
+ # vanish in a puff of smoke.
+ if test set != "${COLLECT_NAMES+set}"; then
+ COLLECT_NAMES=
+ export COLLECT_NAMES
+ fi
+ ;;
+esac
+
+# Global variables:
+ofile=libtool
+can_build_shared=yes
+
+# All known linkers require a '.a' archive for static linking (except MSVC,
+# which needs '.lib').
+libext=a
+
+with_gnu_ld=$lt_cv_prog_gnu_ld
+
+old_CC=$CC
+old_CFLAGS=$CFLAGS
+
+# Set sane defaults for various variables
+test -z "$CC" && CC=cc
+test -z "$LTCC" && LTCC=$CC
+test -z "$LTCFLAGS" && LTCFLAGS=$CFLAGS
+test -z "$LD" && LD=ld
+test -z "$ac_objext" && ac_objext=o
+
+_LT_CC_BASENAME([$compiler])
+
+# Only perform the check for file, if the check method requires it
+test -z "$MAGIC_CMD" && MAGIC_CMD=file
+case $deplibs_check_method in
+file_magic*)
+ if test "$file_magic_cmd" = '$MAGIC_CMD'; then
+ _LT_PATH_MAGIC
+ fi
+ ;;
+esac
+
+# Use C for the default configuration in the libtool script
+LT_SUPPORTED_TAG([CC])
+_LT_LANG_C_CONFIG
+_LT_LANG_DEFAULT_CONFIG
+_LT_CONFIG_COMMANDS
+])# _LT_SETUP
+
+
+# _LT_PREPARE_SED_QUOTE_VARS
+# --------------------------
+# Define a few sed substitution that help us do robust quoting.
+m4_defun([_LT_PREPARE_SED_QUOTE_VARS],
+[# Backslashify metacharacters that are still active within
+# double-quoted strings.
+sed_quote_subst='s/\([["`$\\]]\)/\\\1/g'
+
+# Same as above, but do not quote variable references.
+double_quote_subst='s/\([["`\\]]\)/\\\1/g'
+
+# Sed substitution to delay expansion of an escaped shell variable in a
+# double_quote_subst'ed string.
+delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g'
+
+# Sed substitution to delay expansion of an escaped single quote.
+delay_single_quote_subst='s/'\''/'\'\\\\\\\'\''/g'
+
+# Sed substitution to avoid accidental globbing in evaled expressions
+no_glob_subst='s/\*/\\\*/g'
+])
+
+# _LT_PROG_LTMAIN
+# ---------------
+# Note that this code is called both from 'configure', and 'config.status'
+# now that we use AC_CONFIG_COMMANDS to generate libtool. Notably,
+# 'config.status' has no value for ac_aux_dir unless we are using Automake,
+# so we pass a copy along to make sure it has a sensible value anyway.
+m4_defun([_LT_PROG_LTMAIN],
+[m4_ifdef([AC_REQUIRE_AUX_FILE], [AC_REQUIRE_AUX_FILE([ltmain.sh])])dnl
+_LT_CONFIG_LIBTOOL_INIT([ac_aux_dir='$ac_aux_dir'])
+ltmain=$ac_aux_dir/ltmain.sh
+])# _LT_PROG_LTMAIN
+
+
+## ------------------------------------- ##
+## Accumulate code for creating libtool. ##
+## ------------------------------------- ##
+
+# So that we can recreate a full libtool script including additional
+# tags, we accumulate the chunks of code to send to AC_CONFIG_COMMANDS
+# in macros and then make a single call at the end using the 'libtool'
+# label.
+
+
+# _LT_CONFIG_LIBTOOL_INIT([INIT-COMMANDS])
+# ----------------------------------------
+# Register INIT-COMMANDS to be passed to AC_CONFIG_COMMANDS later.
+m4_define([_LT_CONFIG_LIBTOOL_INIT],
+[m4_ifval([$1],
+ [m4_append([_LT_OUTPUT_LIBTOOL_INIT],
+ [$1
+])])])
+
+# Initialize.
+m4_define([_LT_OUTPUT_LIBTOOL_INIT])
+
+
+# _LT_CONFIG_LIBTOOL([COMMANDS])
+# ------------------------------
+# Register COMMANDS to be passed to AC_CONFIG_COMMANDS later.
+m4_define([_LT_CONFIG_LIBTOOL],
+[m4_ifval([$1],
+ [m4_append([_LT_OUTPUT_LIBTOOL_COMMANDS],
+ [$1
+])])])
+
+# Initialize.
+m4_define([_LT_OUTPUT_LIBTOOL_COMMANDS])
+
+
+# _LT_CONFIG_SAVE_COMMANDS([COMMANDS], [INIT_COMMANDS])
+# -----------------------------------------------------
+m4_defun([_LT_CONFIG_SAVE_COMMANDS],
+[_LT_CONFIG_LIBTOOL([$1])
+_LT_CONFIG_LIBTOOL_INIT([$2])
+])
+
+
+# _LT_FORMAT_COMMENT([COMMENT])
+# -----------------------------
+# Add leading comment marks to the start of each line, and a trailing
+# full-stop to the whole comment if one is not present already.
+m4_define([_LT_FORMAT_COMMENT],
+[m4_ifval([$1], [
+m4_bpatsubst([m4_bpatsubst([$1], [^ *], [# ])],
+ [['`$\]], [\\\&])]m4_bmatch([$1], [[!?.]$], [], [.])
+)])
+
+
+
+## ------------------------ ##
+## FIXME: Eliminate VARNAME ##
+## ------------------------ ##
+
+
+# _LT_DECL([CONFIGNAME], VARNAME, VALUE, [DESCRIPTION], [IS-TAGGED?])
+# -------------------------------------------------------------------
+# CONFIGNAME is the name given to the value in the libtool script.
+# VARNAME is the (base) name used in the configure script.
+# VALUE may be 0, 1 or 2 for a computed quote escaped value based on
+# VARNAME. Any other value will be used directly.
+m4_define([_LT_DECL],
+[lt_if_append_uniq([lt_decl_varnames], [$2], [, ],
+ [lt_dict_add_subkey([lt_decl_dict], [$2], [libtool_name],
+ [m4_ifval([$1], [$1], [$2])])
+ lt_dict_add_subkey([lt_decl_dict], [$2], [value], [$3])
+ m4_ifval([$4],
+ [lt_dict_add_subkey([lt_decl_dict], [$2], [description], [$4])])
+ lt_dict_add_subkey([lt_decl_dict], [$2],
+ [tagged?], [m4_ifval([$5], [yes], [no])])])
+])
+
+
+# _LT_TAGDECL([CONFIGNAME], VARNAME, VALUE, [DESCRIPTION])
+# --------------------------------------------------------
+m4_define([_LT_TAGDECL], [_LT_DECL([$1], [$2], [$3], [$4], [yes])])
+
+
+# lt_decl_tag_varnames([SEPARATOR], [VARNAME1...])
+# ------------------------------------------------
+m4_define([lt_decl_tag_varnames],
+[_lt_decl_filter([tagged?], [yes], $@)])
+
+
+# _lt_decl_filter(SUBKEY, VALUE, [SEPARATOR], [VARNAME1..])
+# ---------------------------------------------------------
+m4_define([_lt_decl_filter],
+[m4_case([$#],
+ [0], [m4_fatal([$0: too few arguments: $#])],
+ [1], [m4_fatal([$0: too few arguments: $#: $1])],
+ [2], [lt_dict_filter([lt_decl_dict], [$1], [$2], [], lt_decl_varnames)],
+ [3], [lt_dict_filter([lt_decl_dict], [$1], [$2], [$3], lt_decl_varnames)],
+ [lt_dict_filter([lt_decl_dict], $@)])[]dnl
+])
+
+
+# lt_decl_quote_varnames([SEPARATOR], [VARNAME1...])
+# --------------------------------------------------
+m4_define([lt_decl_quote_varnames],
+[_lt_decl_filter([value], [1], $@)])
+
+
+# lt_decl_dquote_varnames([SEPARATOR], [VARNAME1...])
+# ---------------------------------------------------
+m4_define([lt_decl_dquote_varnames],
+[_lt_decl_filter([value], [2], $@)])
+
+
+# lt_decl_varnames_tagged([SEPARATOR], [VARNAME1...])
+# ---------------------------------------------------
+m4_define([lt_decl_varnames_tagged],
+[m4_assert([$# <= 2])dnl
+_$0(m4_quote(m4_default([$1], [[, ]])),
+ m4_ifval([$2], [[$2]], [m4_dquote(lt_decl_tag_varnames)]),
+ m4_split(m4_normalize(m4_quote(_LT_TAGS)), [ ]))])
+m4_define([_lt_decl_varnames_tagged],
+[m4_ifval([$3], [lt_combine([$1], [$2], [_], $3)])])
+
+
+# lt_decl_all_varnames([SEPARATOR], [VARNAME1...])
+# ------------------------------------------------
+m4_define([lt_decl_all_varnames],
+[_$0(m4_quote(m4_default([$1], [[, ]])),
+ m4_if([$2], [],
+ m4_quote(lt_decl_varnames),
+ m4_quote(m4_shift($@))))[]dnl
+])
+m4_define([_lt_decl_all_varnames],
+[lt_join($@, lt_decl_varnames_tagged([$1],
+ lt_decl_tag_varnames([[, ]], m4_shift($@))))dnl
+])
+
+
+# _LT_CONFIG_STATUS_DECLARE([VARNAME])
+# ------------------------------------
+# Quote a variable value, and forward it to 'config.status' so that its
+# declaration there will have the same value as in 'configure'. VARNAME
+# must have a single quote delimited value for this to work.
+m4_define([_LT_CONFIG_STATUS_DECLARE],
+[$1='`$ECHO "$][$1" | $SED "$delay_single_quote_subst"`'])
+
+
+# _LT_CONFIG_STATUS_DECLARATIONS
+# ------------------------------
+# We delimit libtool config variables with single quotes, so when
+# we write them to config.status, we have to be sure to quote all
+# embedded single quotes properly. In configure, this macro expands
+# each variable declared with _LT_DECL (and _LT_TAGDECL) into:
+#
+# <var>='`$ECHO "$<var>" | $SED "$delay_single_quote_subst"`'
+m4_defun([_LT_CONFIG_STATUS_DECLARATIONS],
+[m4_foreach([_lt_var], m4_quote(lt_decl_all_varnames),
+ [m4_n([_LT_CONFIG_STATUS_DECLARE(_lt_var)])])])
+
+
+# _LT_LIBTOOL_TAGS
+# ----------------
+# Output comment and list of tags supported by the script
+m4_defun([_LT_LIBTOOL_TAGS],
+[_LT_FORMAT_COMMENT([The names of the tagged configurations supported by this script])dnl
+available_tags='_LT_TAGS'dnl
+])
+
+
+# _LT_LIBTOOL_DECLARE(VARNAME, [TAG])
+# -----------------------------------
+# Extract the dictionary values for VARNAME (optionally with TAG) and
+# expand to a commented shell variable setting:
+#
+# # Some comment about what VAR is for.
+# visible_name=$lt_internal_name
+m4_define([_LT_LIBTOOL_DECLARE],
+[_LT_FORMAT_COMMENT(m4_quote(lt_dict_fetch([lt_decl_dict], [$1],
+ [description])))[]dnl
+m4_pushdef([_libtool_name],
+ m4_quote(lt_dict_fetch([lt_decl_dict], [$1], [libtool_name])))[]dnl
+m4_case(m4_quote(lt_dict_fetch([lt_decl_dict], [$1], [value])),
+ [0], [_libtool_name=[$]$1],
+ [1], [_libtool_name=$lt_[]$1],
+ [2], [_libtool_name=$lt_[]$1],
+ [_libtool_name=lt_dict_fetch([lt_decl_dict], [$1], [value])])[]dnl
+m4_ifval([$2], [_$2])[]m4_popdef([_libtool_name])[]dnl
+])
+
+
+# _LT_LIBTOOL_CONFIG_VARS
+# -----------------------
+# Produce commented declarations of non-tagged libtool config variables
+# suitable for insertion in the LIBTOOL CONFIG section of the 'libtool'
+# script. Tagged libtool config variables (even for the LIBTOOL CONFIG
+# section) are produced by _LT_LIBTOOL_TAG_VARS.
+m4_defun([_LT_LIBTOOL_CONFIG_VARS],
+[m4_foreach([_lt_var],
+ m4_quote(_lt_decl_filter([tagged?], [no], [], lt_decl_varnames)),
+ [m4_n([_LT_LIBTOOL_DECLARE(_lt_var)])])])
+
+
+# _LT_LIBTOOL_TAG_VARS(TAG)
+# -------------------------
+m4_define([_LT_LIBTOOL_TAG_VARS],
+[m4_foreach([_lt_var], m4_quote(lt_decl_tag_varnames),
+ [m4_n([_LT_LIBTOOL_DECLARE(_lt_var, [$1])])])])
+
+
+# _LT_TAGVAR(VARNAME, [TAGNAME])
+# ------------------------------
+m4_define([_LT_TAGVAR], [m4_ifval([$2], [$1_$2], [$1])])
+
+
+# _LT_CONFIG_COMMANDS
+# -------------------
+# Send accumulated output to $CONFIG_STATUS. Thanks to the lists of
+# variables for single and double quote escaping we saved from calls
+# to _LT_DECL, we can put quote escaped variables declarations
+# into 'config.status', and then the shell code to quote escape them in
+# for loops in 'config.status'. Finally, any additional code accumulated
+# from calls to _LT_CONFIG_LIBTOOL_INIT is expanded.
+m4_defun([_LT_CONFIG_COMMANDS],
+[AC_PROVIDE_IFELSE([LT_OUTPUT],
+ dnl If the libtool generation code has been placed in $CONFIG_LT,
+ dnl instead of duplicating it all over again into config.status,
+ dnl then we will have config.status run $CONFIG_LT later, so it
+ dnl needs to know what name is stored there:
+ [AC_CONFIG_COMMANDS([libtool],
+ [$SHELL $CONFIG_LT || AS_EXIT(1)], [CONFIG_LT='$CONFIG_LT'])],
+ dnl If the libtool generation code is destined for config.status,
+ dnl expand the accumulated commands and init code now:
+ [AC_CONFIG_COMMANDS([libtool],
+ [_LT_OUTPUT_LIBTOOL_COMMANDS], [_LT_OUTPUT_LIBTOOL_COMMANDS_INIT])])
+])#_LT_CONFIG_COMMANDS
+
+
+# Initialize.
+m4_define([_LT_OUTPUT_LIBTOOL_COMMANDS_INIT],
+[
+
+# The HP-UX ksh and POSIX shell print the target directory to stdout
+# if CDPATH is set.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+sed_quote_subst='$sed_quote_subst'
+double_quote_subst='$double_quote_subst'
+delay_variable_subst='$delay_variable_subst'
+_LT_CONFIG_STATUS_DECLARATIONS
+LTCC='$LTCC'
+LTCFLAGS='$LTCFLAGS'
+compiler='$compiler_DEFAULT'
+
+# A function that is used when there is no print builtin or printf.
+func_fallback_echo ()
+{
+ eval 'cat <<_LTECHO_EOF
+\$[]1
+_LTECHO_EOF'
+}
+
+# Quote evaled strings.
+for var in lt_decl_all_varnames([[ \
+]], lt_decl_quote_varnames); do
+ case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in
+ *[[\\\\\\\`\\"\\\$]]*)
+ eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED \\"\\\$sed_quote_subst\\"\\\`\\\\\\"" ## exclude from sc_prohibit_nested_quotes
+ ;;
+ *)
+ eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\""
+ ;;
+ esac
+done
+
+# Double-quote double-evaled strings.
+for var in lt_decl_all_varnames([[ \
+]], lt_decl_dquote_varnames); do
+ case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in
+ *[[\\\\\\\`\\"\\\$]]*)
+ eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\"" ## exclude from sc_prohibit_nested_quotes
+ ;;
+ *)
+ eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\""
+ ;;
+ esac
+done
+
+_LT_OUTPUT_LIBTOOL_INIT
+])
+
+# _LT_GENERATED_FILE_INIT(FILE, [COMMENT])
+# ------------------------------------
+# Generate a child script FILE with all initialization necessary to
+# reuse the environment learned by the parent script, and make the
+# file executable. If COMMENT is supplied, it is inserted after the
+# '#!' sequence but before initialization text begins. After this
+# macro, additional text can be appended to FILE to form the body of
+# the child script. The macro ends with non-zero status if the
+# file could not be fully written (such as if the disk is full).
+m4_ifdef([AS_INIT_GENERATED],
+[m4_defun([_LT_GENERATED_FILE_INIT],[AS_INIT_GENERATED($@)])],
+[m4_defun([_LT_GENERATED_FILE_INIT],
+[m4_require([AS_PREPARE])]dnl
+[m4_pushdef([AS_MESSAGE_LOG_FD])]dnl
+[lt_write_fail=0
+cat >$1 <<_ASEOF || lt_write_fail=1
+#! $SHELL
+# Generated by $as_me.
+$2
+SHELL=\${CONFIG_SHELL-$SHELL}
+export SHELL
+_ASEOF
+cat >>$1 <<\_ASEOF || lt_write_fail=1
+AS_SHELL_SANITIZE
+_AS_PREPARE
+exec AS_MESSAGE_FD>&1
+_ASEOF
+test 0 = "$lt_write_fail" && chmod +x $1[]dnl
+m4_popdef([AS_MESSAGE_LOG_FD])])])# _LT_GENERATED_FILE_INIT
+
+# LT_OUTPUT
+# ---------
+# This macro allows early generation of the libtool script (before
+# AC_OUTPUT is called), incase it is used in configure for compilation
+# tests.
+AC_DEFUN([LT_OUTPUT],
+[: ${CONFIG_LT=./config.lt}
+AC_MSG_NOTICE([creating $CONFIG_LT])
+_LT_GENERATED_FILE_INIT(["$CONFIG_LT"],
+[# Run this file to recreate a libtool stub with the current configuration.])
+
+cat >>"$CONFIG_LT" <<\_LTEOF
+lt_cl_silent=false
+exec AS_MESSAGE_LOG_FD>>config.log
+{
+ echo
+ AS_BOX([Running $as_me.])
+} >&AS_MESSAGE_LOG_FD
+
+lt_cl_help="\
+'$as_me' creates a local libtool stub from the current configuration,
+for use in further configure time tests before the real libtool is
+generated.
+
+Usage: $[0] [[OPTIONS]]
+
+ -h, --help print this help, then exit
+ -V, --version print version number, then exit
+ -q, --quiet do not print progress messages
+ -d, --debug don't remove temporary files
+
+Report bugs to <bug-libtool@gnu.org>."
+
+lt_cl_version="\
+m4_ifset([AC_PACKAGE_NAME], [AC_PACKAGE_NAME ])config.lt[]dnl
+m4_ifset([AC_PACKAGE_VERSION], [ AC_PACKAGE_VERSION])
+configured by $[0], generated by m4_PACKAGE_STRING.
+
+Copyright (C) 2011 Free Software Foundation, Inc.
+This config.lt script is free software; the Free Software Foundation
+gives unlimited permision to copy, distribute and modify it."
+
+while test 0 != $[#]
+do
+ case $[1] in
+ --version | --v* | -V )
+ echo "$lt_cl_version"; exit 0 ;;
+ --help | --h* | -h )
+ echo "$lt_cl_help"; exit 0 ;;
+ --debug | --d* | -d )
+ debug=: ;;
+ --quiet | --q* | --silent | --s* | -q )
+ lt_cl_silent=: ;;
+
+ -*) AC_MSG_ERROR([unrecognized option: $[1]
+Try '$[0] --help' for more information.]) ;;
+
+ *) AC_MSG_ERROR([unrecognized argument: $[1]
+Try '$[0] --help' for more information.]) ;;
+ esac
+ shift
+done
+
+if $lt_cl_silent; then
+ exec AS_MESSAGE_FD>/dev/null
+fi
+_LTEOF
+
+cat >>"$CONFIG_LT" <<_LTEOF
+_LT_OUTPUT_LIBTOOL_COMMANDS_INIT
+_LTEOF
+
+cat >>"$CONFIG_LT" <<\_LTEOF
+AC_MSG_NOTICE([creating $ofile])
+_LT_OUTPUT_LIBTOOL_COMMANDS
+AS_EXIT(0)
+_LTEOF
+chmod +x "$CONFIG_LT"
+
+# configure is writing to config.log, but config.lt does its own redirection,
+# appending to config.log, which fails on DOS, as config.log is still kept
+# open by configure. Here we exec the FD to /dev/null, effectively closing
+# config.log, so it can be properly (re)opened and appended to by config.lt.
+lt_cl_success=:
+test yes = "$silent" &&
+ lt_config_lt_args="$lt_config_lt_args --quiet"
+exec AS_MESSAGE_LOG_FD>/dev/null
+$SHELL "$CONFIG_LT" $lt_config_lt_args || lt_cl_success=false
+exec AS_MESSAGE_LOG_FD>>config.log
+$lt_cl_success || AS_EXIT(1)
+])# LT_OUTPUT
+
+
+# _LT_CONFIG(TAG)
+# ---------------
+# If TAG is the built-in tag, create an initial libtool script with a
+# default configuration from the untagged config vars. Otherwise add code
+# to config.status for appending the configuration named by TAG from the
+# matching tagged config vars.
+m4_defun([_LT_CONFIG],
+[m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+_LT_CONFIG_SAVE_COMMANDS([
+ m4_define([_LT_TAG], m4_if([$1], [], [C], [$1]))dnl
+ m4_if(_LT_TAG, [C], [
+ # See if we are running on zsh, and set the options that allow our
+ # commands through without removal of \ escapes.
+ if test -n "${ZSH_VERSION+set}"; then
+ setopt NO_GLOB_SUBST
+ fi
+
+ cfgfile=${ofile}T
+ trap "$RM \"$cfgfile\"; exit 1" 1 2 15
+ $RM "$cfgfile"
+
+ cat <<_LT_EOF >> "$cfgfile"
+#! $SHELL
+# Generated automatically by $as_me ($PACKAGE) $VERSION
+# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`:
+# NOTE: Changes made to this file will be lost: look at ltmain.sh.
+
+# Provide generalized library-building support services.
+# Written by Gordon Matzigkeit, 1996
+
+_LT_COPYING
+_LT_LIBTOOL_TAGS
+
+# Configured defaults for sys_lib_dlsearch_path munging.
+: \${LT_SYS_LIBRARY_PATH="$configure_time_lt_sys_library_path"}
+
+# ### BEGIN LIBTOOL CONFIG
+_LT_LIBTOOL_CONFIG_VARS
+_LT_LIBTOOL_TAG_VARS
+# ### END LIBTOOL CONFIG
+
+_LT_EOF
+
+ cat <<'_LT_EOF' >> "$cfgfile"
+
+# ### BEGIN FUNCTIONS SHARED WITH CONFIGURE
+
+_LT_PREPARE_MUNGE_PATH_LIST
+_LT_PREPARE_CC_BASENAME
+
+# ### END FUNCTIONS SHARED WITH CONFIGURE
+
+_LT_EOF
+
+ case $host_os in
+ aix3*)
+ cat <<\_LT_EOF >> "$cfgfile"
+# AIX sometimes has problems with the GCC collect2 program. For some
+# reason, if we set the COLLECT_NAMES environment variable, the problems
+# vanish in a puff of smoke.
+if test set != "${COLLECT_NAMES+set}"; then
+ COLLECT_NAMES=
+ export COLLECT_NAMES
+fi
+_LT_EOF
+ ;;
+ esac
+
+ _LT_PROG_LTMAIN
+
+ # We use sed instead of cat because bash on DJGPP gets confused if
+ # if finds mixed CR/LF and LF-only lines. Since sed operates in
+ # text mode, it properly converts lines to CR/LF. This bash problem
+ # is reportedly fixed, but why not run on old versions too?
+ sed '$q' "$ltmain" >> "$cfgfile" \
+ || (rm -f "$cfgfile"; exit 1)
+
+ mv -f "$cfgfile" "$ofile" ||
+ (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile")
+ chmod +x "$ofile"
+],
+[cat <<_LT_EOF >> "$ofile"
+
+dnl Unfortunately we have to use $1 here, since _LT_TAG is not expanded
+dnl in a comment (ie after a #).
+# ### BEGIN LIBTOOL TAG CONFIG: $1
+_LT_LIBTOOL_TAG_VARS(_LT_TAG)
+# ### END LIBTOOL TAG CONFIG: $1
+_LT_EOF
+])dnl /m4_if
+],
+[m4_if([$1], [], [
+ PACKAGE='$PACKAGE'
+ VERSION='$VERSION'
+ RM='$RM'
+ ofile='$ofile'], [])
+])dnl /_LT_CONFIG_SAVE_COMMANDS
+])# _LT_CONFIG
+
+
+# LT_SUPPORTED_TAG(TAG)
+# ---------------------
+# Trace this macro to discover what tags are supported by the libtool
+# --tag option, using:
+# autoconf --trace 'LT_SUPPORTED_TAG:$1'
+AC_DEFUN([LT_SUPPORTED_TAG], [])
+
+
+# C support is built-in for now
+m4_define([_LT_LANG_C_enabled], [])
+m4_define([_LT_TAGS], [])
+
+
+# LT_LANG(LANG)
+# -------------
+# Enable libtool support for the given language if not already enabled.
+AC_DEFUN([LT_LANG],
+[AC_BEFORE([$0], [LT_OUTPUT])dnl
+m4_case([$1],
+ [C], [_LT_LANG(C)],
+ [C++], [_LT_LANG(CXX)],
+ [Go], [_LT_LANG(GO)],
+ [Java], [_LT_LANG(GCJ)],
+ [Fortran 77], [_LT_LANG(F77)],
+ [Fortran], [_LT_LANG(FC)],
+ [Windows Resource], [_LT_LANG(RC)],
+ [m4_ifdef([_LT_LANG_]$1[_CONFIG],
+ [_LT_LANG($1)],
+ [m4_fatal([$0: unsupported language: "$1"])])])dnl
+])# LT_LANG
+
+
+# _LT_LANG(LANGNAME)
+# ------------------
+m4_defun([_LT_LANG],
+[m4_ifdef([_LT_LANG_]$1[_enabled], [],
+ [LT_SUPPORTED_TAG([$1])dnl
+ m4_append([_LT_TAGS], [$1 ])dnl
+ m4_define([_LT_LANG_]$1[_enabled], [])dnl
+ _LT_LANG_$1_CONFIG($1)])dnl
+])# _LT_LANG
+
+
+m4_ifndef([AC_PROG_GO], [
+############################################################
+# NOTE: This macro has been submitted for inclusion into #
+# GNU Autoconf as AC_PROG_GO. When it is available in #
+# a released version of Autoconf we should remove this #
+# macro and use it instead. #
+############################################################
+m4_defun([AC_PROG_GO],
+[AC_LANG_PUSH(Go)dnl
+AC_ARG_VAR([GOC], [Go compiler command])dnl
+AC_ARG_VAR([GOFLAGS], [Go compiler flags])dnl
+_AC_ARG_VAR_LDFLAGS()dnl
+AC_CHECK_TOOL(GOC, gccgo)
+if test -z "$GOC"; then
+ if test -n "$ac_tool_prefix"; then
+ AC_CHECK_PROG(GOC, [${ac_tool_prefix}gccgo], [${ac_tool_prefix}gccgo])
+ fi
+fi
+if test -z "$GOC"; then
+ AC_CHECK_PROG(GOC, gccgo, gccgo, false)
+fi
+])#m4_defun
+])#m4_ifndef
+
+
+# _LT_LANG_DEFAULT_CONFIG
+# -----------------------
+m4_defun([_LT_LANG_DEFAULT_CONFIG],
+[AC_PROVIDE_IFELSE([AC_PROG_CXX],
+ [LT_LANG(CXX)],
+ [m4_define([AC_PROG_CXX], defn([AC_PROG_CXX])[LT_LANG(CXX)])])
+
+AC_PROVIDE_IFELSE([AC_PROG_F77],
+ [LT_LANG(F77)],
+ [m4_define([AC_PROG_F77], defn([AC_PROG_F77])[LT_LANG(F77)])])
+
+AC_PROVIDE_IFELSE([AC_PROG_FC],
+ [LT_LANG(FC)],
+ [m4_define([AC_PROG_FC], defn([AC_PROG_FC])[LT_LANG(FC)])])
+
+dnl The call to [A][M_PROG_GCJ] is quoted like that to stop aclocal
+dnl pulling things in needlessly.
+AC_PROVIDE_IFELSE([AC_PROG_GCJ],
+ [LT_LANG(GCJ)],
+ [AC_PROVIDE_IFELSE([A][M_PROG_GCJ],
+ [LT_LANG(GCJ)],
+ [AC_PROVIDE_IFELSE([LT_PROG_GCJ],
+ [LT_LANG(GCJ)],
+ [m4_ifdef([AC_PROG_GCJ],
+ [m4_define([AC_PROG_GCJ], defn([AC_PROG_GCJ])[LT_LANG(GCJ)])])
+ m4_ifdef([A][M_PROG_GCJ],
+ [m4_define([A][M_PROG_GCJ], defn([A][M_PROG_GCJ])[LT_LANG(GCJ)])])
+ m4_ifdef([LT_PROG_GCJ],
+ [m4_define([LT_PROG_GCJ], defn([LT_PROG_GCJ])[LT_LANG(GCJ)])])])])])
+
+AC_PROVIDE_IFELSE([AC_PROG_GO],
+ [LT_LANG(GO)],
+ [m4_define([AC_PROG_GO], defn([AC_PROG_GO])[LT_LANG(GO)])])
+
+AC_PROVIDE_IFELSE([LT_PROG_RC],
+ [LT_LANG(RC)],
+ [m4_define([LT_PROG_RC], defn([LT_PROG_RC])[LT_LANG(RC)])])
+])# _LT_LANG_DEFAULT_CONFIG
+
+# Obsolete macros:
+AU_DEFUN([AC_LIBTOOL_CXX], [LT_LANG(C++)])
+AU_DEFUN([AC_LIBTOOL_F77], [LT_LANG(Fortran 77)])
+AU_DEFUN([AC_LIBTOOL_FC], [LT_LANG(Fortran)])
+AU_DEFUN([AC_LIBTOOL_GCJ], [LT_LANG(Java)])
+AU_DEFUN([AC_LIBTOOL_RC], [LT_LANG(Windows Resource)])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_LIBTOOL_CXX], [])
+dnl AC_DEFUN([AC_LIBTOOL_F77], [])
+dnl AC_DEFUN([AC_LIBTOOL_FC], [])
+dnl AC_DEFUN([AC_LIBTOOL_GCJ], [])
+dnl AC_DEFUN([AC_LIBTOOL_RC], [])
+
+
+# _LT_TAG_COMPILER
+# ----------------
+m4_defun([_LT_TAG_COMPILER],
+[AC_REQUIRE([AC_PROG_CC])dnl
+
+_LT_DECL([LTCC], [CC], [1], [A C compiler])dnl
+_LT_DECL([LTCFLAGS], [CFLAGS], [1], [LTCC compiler flags])dnl
+_LT_TAGDECL([CC], [compiler], [1], [A language specific compiler])dnl
+_LT_TAGDECL([with_gcc], [GCC], [0], [Is the compiler the GNU compiler?])dnl
+
+# If no C compiler was specified, use CC.
+LTCC=${LTCC-"$CC"}
+
+# If no C compiler flags were specified, use CFLAGS.
+LTCFLAGS=${LTCFLAGS-"$CFLAGS"}
+
+# Allow CC to be a program name with arguments.
+compiler=$CC
+])# _LT_TAG_COMPILER
+
+
+# _LT_COMPILER_BOILERPLATE
+# ------------------------
+# Check for compiler boilerplate output or warnings with
+# the simple compiler test code.
+m4_defun([_LT_COMPILER_BOILERPLATE],
+[m4_require([_LT_DECL_SED])dnl
+ac_outfile=conftest.$ac_objext
+echo "$lt_simple_compile_test_code" >conftest.$ac_ext
+eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err
+_lt_compiler_boilerplate=`cat conftest.err`
+$RM conftest*
+])# _LT_COMPILER_BOILERPLATE
+
+
+# _LT_LINKER_BOILERPLATE
+# ----------------------
+# Check for linker boilerplate output or warnings with
+# the simple link test code.
+m4_defun([_LT_LINKER_BOILERPLATE],
+[m4_require([_LT_DECL_SED])dnl
+ac_outfile=conftest.$ac_objext
+echo "$lt_simple_link_test_code" >conftest.$ac_ext
+eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err
+_lt_linker_boilerplate=`cat conftest.err`
+$RM -r conftest*
+])# _LT_LINKER_BOILERPLATE
+
+# _LT_REQUIRED_DARWIN_CHECKS
+# -------------------------
+m4_defun_once([_LT_REQUIRED_DARWIN_CHECKS],[
+ case $host_os in
+ rhapsody* | darwin*)
+ AC_CHECK_TOOL([DSYMUTIL], [dsymutil], [:])
+ AC_CHECK_TOOL([NMEDIT], [nmedit], [:])
+ AC_CHECK_TOOL([LIPO], [lipo], [:])
+ AC_CHECK_TOOL([OTOOL], [otool], [:])
+ AC_CHECK_TOOL([OTOOL64], [otool64], [:])
+ _LT_DECL([], [DSYMUTIL], [1],
+ [Tool to manipulate archived DWARF debug symbol files on Mac OS X])
+ _LT_DECL([], [NMEDIT], [1],
+ [Tool to change global to local symbols on Mac OS X])
+ _LT_DECL([], [LIPO], [1],
+ [Tool to manipulate fat objects and archives on Mac OS X])
+ _LT_DECL([], [OTOOL], [1],
+ [ldd/readelf like tool for Mach-O binaries on Mac OS X])
+ _LT_DECL([], [OTOOL64], [1],
+ [ldd/readelf like tool for 64 bit Mach-O binaries on Mac OS X 10.4])
+
+ AC_CACHE_CHECK([for -single_module linker flag],[lt_cv_apple_cc_single_mod],
+ [lt_cv_apple_cc_single_mod=no
+ if test -z "$LT_MULTI_MODULE"; then
+ # By default we will add the -single_module flag. You can override
+ # by either setting the environment variable LT_MULTI_MODULE
+ # non-empty at configure time, or by adding -multi_module to the
+ # link flags.
+ rm -rf libconftest.dylib*
+ echo "int foo(void){return 1;}" > conftest.c
+ echo "$LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \
+-dynamiclib -Wl,-single_module conftest.c" >&AS_MESSAGE_LOG_FD
+ $LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \
+ -dynamiclib -Wl,-single_module conftest.c 2>conftest.err
+ _lt_result=$?
+ # If there is a non-empty error log, and "single_module"
+ # appears in it, assume the flag caused a linker warning
+ if test -s conftest.err && $GREP single_module conftest.err; then
+ cat conftest.err >&AS_MESSAGE_LOG_FD
+ # Otherwise, if the output was created with a 0 exit code from
+ # the compiler, it worked.
+ elif test -f libconftest.dylib && test 0 = "$_lt_result"; then
+ lt_cv_apple_cc_single_mod=yes
+ else
+ cat conftest.err >&AS_MESSAGE_LOG_FD
+ fi
+ rm -rf libconftest.dylib*
+ rm -f conftest.*
+ fi])
+
+ AC_CACHE_CHECK([for -exported_symbols_list linker flag],
+ [lt_cv_ld_exported_symbols_list],
+ [lt_cv_ld_exported_symbols_list=no
+ save_LDFLAGS=$LDFLAGS
+ echo "_main" > conftest.sym
+ LDFLAGS="$LDFLAGS -Wl,-exported_symbols_list,conftest.sym"
+ AC_LINK_IFELSE([AC_LANG_PROGRAM([],[])],
+ [lt_cv_ld_exported_symbols_list=yes],
+ [lt_cv_ld_exported_symbols_list=no])
+ LDFLAGS=$save_LDFLAGS
+ ])
+
+ AC_CACHE_CHECK([for -force_load linker flag],[lt_cv_ld_force_load],
+ [lt_cv_ld_force_load=no
+ cat > conftest.c << _LT_EOF
+int forced_loaded() { return 2;}
+_LT_EOF
+ echo "$LTCC $LTCFLAGS -c -o conftest.o conftest.c" >&AS_MESSAGE_LOG_FD
+ $LTCC $LTCFLAGS -c -o conftest.o conftest.c 2>&AS_MESSAGE_LOG_FD
+ echo "$AR cru libconftest.a conftest.o" >&AS_MESSAGE_LOG_FD
+ $AR cru libconftest.a conftest.o 2>&AS_MESSAGE_LOG_FD
+ echo "$RANLIB libconftest.a" >&AS_MESSAGE_LOG_FD
+ $RANLIB libconftest.a 2>&AS_MESSAGE_LOG_FD
+ cat > conftest.c << _LT_EOF
+int main() { return 0;}
+_LT_EOF
+ echo "$LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a" >&AS_MESSAGE_LOG_FD
+ $LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a 2>conftest.err
+ _lt_result=$?
+ if test -s conftest.err && $GREP force_load conftest.err; then
+ cat conftest.err >&AS_MESSAGE_LOG_FD
+ elif test -f conftest && test 0 = "$_lt_result" && $GREP forced_load conftest >/dev/null 2>&1; then
+ lt_cv_ld_force_load=yes
+ else
+ cat conftest.err >&AS_MESSAGE_LOG_FD
+ fi
+ rm -f conftest.err libconftest.a conftest conftest.c
+ rm -rf conftest.dSYM
+ ])
+ case $host_os in
+ rhapsody* | darwin1.[[012]])
+ _lt_dar_allow_undefined='$wl-undefined ${wl}suppress' ;;
+ darwin1.*)
+ _lt_dar_allow_undefined='$wl-flat_namespace $wl-undefined ${wl}suppress' ;;
+ darwin*) # darwin 5.x on
+ # if running on 10.5 or later, the deployment target defaults
+ # to the OS version, if on x86, and 10.4, the deployment
+ # target defaults to 10.4. Don't you love it?
+ case ${MACOSX_DEPLOYMENT_TARGET-10.0},$host in
+ 10.0,*86*-darwin8*|10.0,*-darwin[[91]]*)
+ _lt_dar_allow_undefined='$wl-undefined ${wl}dynamic_lookup' ;;
+ 10.[[012]][[,.]]*)
+ _lt_dar_allow_undefined='$wl-flat_namespace $wl-undefined ${wl}suppress' ;;
+ 10.*)
+ _lt_dar_allow_undefined='$wl-undefined ${wl}dynamic_lookup' ;;
+ esac
+ ;;
+ esac
+ if test yes = "$lt_cv_apple_cc_single_mod"; then
+ _lt_dar_single_mod='$single_module'
+ fi
+ if test yes = "$lt_cv_ld_exported_symbols_list"; then
+ _lt_dar_export_syms=' $wl-exported_symbols_list,$output_objdir/$libname-symbols.expsym'
+ else
+ _lt_dar_export_syms='~$NMEDIT -s $output_objdir/$libname-symbols.expsym $lib'
+ fi
+ if test : != "$DSYMUTIL" && test no = "$lt_cv_ld_force_load"; then
+ _lt_dsymutil='~$DSYMUTIL $lib || :'
+ else
+ _lt_dsymutil=
+ fi
+ ;;
+ esac
+])
+
+
+# _LT_DARWIN_LINKER_FEATURES([TAG])
+# ---------------------------------
+# Checks for linker and compiler features on darwin
+m4_defun([_LT_DARWIN_LINKER_FEATURES],
+[
+ m4_require([_LT_REQUIRED_DARWIN_CHECKS])
+ _LT_TAGVAR(archive_cmds_need_lc, $1)=no
+ _LT_TAGVAR(hardcode_direct, $1)=no
+ _LT_TAGVAR(hardcode_automatic, $1)=yes
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported
+ if test yes = "$lt_cv_ld_force_load"; then
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience $wl-force_load,$conv\"; done; func_echo_all \"$new_convenience\"`'
+ m4_case([$1], [F77], [_LT_TAGVAR(compiler_needs_object, $1)=yes],
+ [FC], [_LT_TAGVAR(compiler_needs_object, $1)=yes])
+ else
+ _LT_TAGVAR(whole_archive_flag_spec, $1)=''
+ fi
+ _LT_TAGVAR(link_all_deplibs, $1)=yes
+ _LT_TAGVAR(allow_undefined_flag, $1)=$_lt_dar_allow_undefined
+ case $cc_basename in
+ ifort*|nagfor*) _lt_dar_can_shared=yes ;;
+ *) _lt_dar_can_shared=$GCC ;;
+ esac
+ if test yes = "$_lt_dar_can_shared"; then
+ output_verbose_link_cmd=func_echo_all
+ _LT_TAGVAR(archive_cmds, $1)="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod$_lt_dsymutil"
+ _LT_TAGVAR(module_cmds, $1)="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags$_lt_dsymutil"
+ _LT_TAGVAR(archive_expsym_cmds, $1)="sed 's|^|_|' < \$export_symbols > \$output_objdir/\$libname-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod$_lt_dar_export_syms$_lt_dsymutil"
+ _LT_TAGVAR(module_expsym_cmds, $1)="sed -e 's|^|_|' < \$export_symbols > \$output_objdir/\$libname-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags$_lt_dar_export_syms$_lt_dsymutil"
+ m4_if([$1], [CXX],
+[ if test yes != "$lt_cv_apple_cc_single_mod"; then
+ _LT_TAGVAR(archive_cmds, $1)="\$CC -r -keep_private_externs -nostdlib -o \$lib-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$lib-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring$_lt_dsymutil"
+ _LT_TAGVAR(archive_expsym_cmds, $1)="sed 's|^|_|' < \$export_symbols > \$output_objdir/\$libname-symbols.expsym~\$CC -r -keep_private_externs -nostdlib -o \$lib-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$lib-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring$_lt_dar_export_syms$_lt_dsymutil"
+ fi
+],[])
+ else
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ fi
+])
+
+# _LT_SYS_MODULE_PATH_AIX([TAGNAME])
+# ----------------------------------
+# Links a minimal program and checks the executable
+# for the system default hardcoded library path. In most cases,
+# this is /usr/lib:/lib, but when the MPI compilers are used
+# the location of the communication and MPI libs are included too.
+# If we don't find anything, use the default library path according
+# to the aix ld manual.
+# Store the results from the different compilers for each TAGNAME.
+# Allow to override them for all tags through lt_cv_aix_libpath.
+m4_defun([_LT_SYS_MODULE_PATH_AIX],
+[m4_require([_LT_DECL_SED])dnl
+if test set = "${lt_cv_aix_libpath+set}"; then
+ aix_libpath=$lt_cv_aix_libpath
+else
+ AC_CACHE_VAL([_LT_TAGVAR([lt_cv_aix_libpath_], [$1])],
+ [AC_LINK_IFELSE([AC_LANG_PROGRAM],[
+ lt_aix_libpath_sed='[
+ /Import File Strings/,/^$/ {
+ /^0/ {
+ s/^0 *\([^ ]*\) *$/\1/
+ p
+ }
+ }]'
+ _LT_TAGVAR([lt_cv_aix_libpath_], [$1])=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
+ # Check for a 64-bit object if we didn't find anything.
+ if test -z "$_LT_TAGVAR([lt_cv_aix_libpath_], [$1])"; then
+ _LT_TAGVAR([lt_cv_aix_libpath_], [$1])=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
+ fi],[])
+ if test -z "$_LT_TAGVAR([lt_cv_aix_libpath_], [$1])"; then
+ _LT_TAGVAR([lt_cv_aix_libpath_], [$1])=/usr/lib:/lib
+ fi
+ ])
+ aix_libpath=$_LT_TAGVAR([lt_cv_aix_libpath_], [$1])
+fi
+])# _LT_SYS_MODULE_PATH_AIX
+
+
+# _LT_SHELL_INIT(ARG)
+# -------------------
+m4_define([_LT_SHELL_INIT],
+[m4_divert_text([M4SH-INIT], [$1
+])])# _LT_SHELL_INIT
+
+
+
+# _LT_PROG_ECHO_BACKSLASH
+# -----------------------
+# Find how we can fake an echo command that does not interpret backslash.
+# In particular, with Autoconf 2.60 or later we add some code to the start
+# of the generated configure script that will find a shell with a builtin
+# printf (that we can use as an echo command).
+m4_defun([_LT_PROG_ECHO_BACKSLASH],
+[ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO
+ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO
+
+AC_MSG_CHECKING([how to print strings])
+# Test print first, because it will be a builtin if present.
+if test "X`( print -r -- -n ) 2>/dev/null`" = X-n && \
+ test "X`print -r -- $ECHO 2>/dev/null`" = "X$ECHO"; then
+ ECHO='print -r --'
+elif test "X`printf %s $ECHO 2>/dev/null`" = "X$ECHO"; then
+ ECHO='printf %s\n'
+else
+ # Use this function as a fallback that always works.
+ func_fallback_echo ()
+ {
+ eval 'cat <<_LTECHO_EOF
+$[]1
+_LTECHO_EOF'
+ }
+ ECHO='func_fallback_echo'
+fi
+
+# func_echo_all arg...
+# Invoke $ECHO with all args, space-separated.
+func_echo_all ()
+{
+ $ECHO "$*"
+}
+
+case $ECHO in
+ printf*) AC_MSG_RESULT([printf]) ;;
+ print*) AC_MSG_RESULT([print -r]) ;;
+ *) AC_MSG_RESULT([cat]) ;;
+esac
+
+m4_ifdef([_AS_DETECT_SUGGESTED],
+[_AS_DETECT_SUGGESTED([
+ test -n "${ZSH_VERSION+set}${BASH_VERSION+set}" || (
+ ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+ ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO
+ ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO
+ PATH=/empty FPATH=/empty; export PATH FPATH
+ test "X`printf %s $ECHO`" = "X$ECHO" \
+ || test "X`print -r -- $ECHO`" = "X$ECHO" )])])
+
+_LT_DECL([], [SHELL], [1], [Shell to use when invoking shell scripts])
+_LT_DECL([], [ECHO], [1], [An echo program that protects backslashes])
+])# _LT_PROG_ECHO_BACKSLASH
+
+
+# _LT_WITH_SYSROOT
+# ----------------
+AC_DEFUN([_LT_WITH_SYSROOT],
+[AC_MSG_CHECKING([for sysroot])
+AC_ARG_WITH([sysroot],
+[AS_HELP_STRING([--with-sysroot@<:@=DIR@:>@],
+ [Search for dependent libraries within DIR (or the compiler's sysroot
+ if not specified).])],
+[], [with_sysroot=no])
+
+dnl lt_sysroot will always be passed unquoted. We quote it here
+dnl in case the user passed a directory name.
+lt_sysroot=
+case $with_sysroot in #(
+ yes)
+ if test yes = "$GCC"; then
+ lt_sysroot=`$CC --print-sysroot 2>/dev/null`
+ fi
+ ;; #(
+ /*)
+ lt_sysroot=`echo "$with_sysroot" | sed -e "$sed_quote_subst"`
+ ;; #(
+ no|'')
+ ;; #(
+ *)
+ AC_MSG_RESULT([$with_sysroot])
+ AC_MSG_ERROR([The sysroot must be an absolute path.])
+ ;;
+esac
+
+ AC_MSG_RESULT([${lt_sysroot:-no}])
+_LT_DECL([], [lt_sysroot], [0], [The root where to search for ]dnl
+[dependent libraries, and where our libraries should be installed.])])
+
+# _LT_ENABLE_LOCK
+# ---------------
+m4_defun([_LT_ENABLE_LOCK],
+[AC_ARG_ENABLE([libtool-lock],
+ [AS_HELP_STRING([--disable-libtool-lock],
+ [avoid locking (might break parallel builds)])])
+test no = "$enable_libtool_lock" || enable_libtool_lock=yes
+
+# Some flags need to be propagated to the compiler or linker for good
+# libtool support.
+case $host in
+ia64-*-hpux*)
+ # Find out what ABI is being produced by ac_compile, and set mode
+ # options accordingly.
+ echo 'int i;' > conftest.$ac_ext
+ if AC_TRY_EVAL(ac_compile); then
+ case `/usr/bin/file conftest.$ac_objext` in
+ *ELF-32*)
+ HPUX_IA64_MODE=32
+ ;;
+ *ELF-64*)
+ HPUX_IA64_MODE=64
+ ;;
+ esac
+ fi
+ rm -rf conftest*
+ ;;
+*-*-irix6*)
+ # Find out what ABI is being produced by ac_compile, and set linker
+ # options accordingly.
+ echo '[#]line '$LINENO' "configure"' > conftest.$ac_ext
+ if AC_TRY_EVAL(ac_compile); then
+ if test yes = "$lt_cv_prog_gnu_ld"; then
+ case `/usr/bin/file conftest.$ac_objext` in
+ *32-bit*)
+ LD="${LD-ld} -melf32bsmip"
+ ;;
+ *N32*)
+ LD="${LD-ld} -melf32bmipn32"
+ ;;
+ *64-bit*)
+ LD="${LD-ld} -melf64bmip"
+ ;;
+ esac
+ else
+ case `/usr/bin/file conftest.$ac_objext` in
+ *32-bit*)
+ LD="${LD-ld} -32"
+ ;;
+ *N32*)
+ LD="${LD-ld} -n32"
+ ;;
+ *64-bit*)
+ LD="${LD-ld} -64"
+ ;;
+ esac
+ fi
+ fi
+ rm -rf conftest*
+ ;;
+
+mips64*-*linux*)
+ # Find out what ABI is being produced by ac_compile, and set linker
+ # options accordingly.
+ echo '[#]line '$LINENO' "configure"' > conftest.$ac_ext
+ if AC_TRY_EVAL(ac_compile); then
+ emul=elf
+ case `/usr/bin/file conftest.$ac_objext` in
+ *32-bit*)
+ emul="${emul}32"
+ ;;
+ *64-bit*)
+ emul="${emul}64"
+ ;;
+ esac
+ case `/usr/bin/file conftest.$ac_objext` in
+ *MSB*)
+ emul="${emul}btsmip"
+ ;;
+ *LSB*)
+ emul="${emul}ltsmip"
+ ;;
+ esac
+ case `/usr/bin/file conftest.$ac_objext` in
+ *N32*)
+ emul="${emul}n32"
+ ;;
+ esac
+ LD="${LD-ld} -m $emul"
+ fi
+ rm -rf conftest*
+ ;;
+
+x86_64-*kfreebsd*-gnu|x86_64-*linux*|powerpc*-*linux*| \
+s390*-*linux*|s390*-*tpf*|sparc*-*linux*)
+ # Find out what ABI is being produced by ac_compile, and set linker
+ # options accordingly. Note that the listed cases only cover the
+ # situations where additional linker options are needed (such as when
+ # doing 32-bit compilation for a host where ld defaults to 64-bit, or
+ # vice versa); the common cases where no linker options are needed do
+ # not appear in the list.
+ echo 'int i;' > conftest.$ac_ext
+ if AC_TRY_EVAL(ac_compile); then
+ case `/usr/bin/file conftest.o` in
+ *32-bit*)
+ case $host in
+ x86_64-*kfreebsd*-gnu)
+ LD="${LD-ld} -m elf_i386_fbsd"
+ ;;
+ x86_64-*linux*)
+ case `/usr/bin/file conftest.o` in
+ *x86-64*)
+ LD="${LD-ld} -m elf32_x86_64"
+ ;;
+ *)
+ LD="${LD-ld} -m elf_i386"
+ ;;
+ esac
+ ;;
+ powerpc64le-*linux*)
+ LD="${LD-ld} -m elf32lppclinux"
+ ;;
+ powerpc64-*linux*)
+ LD="${LD-ld} -m elf32ppclinux"
+ ;;
+ s390x-*linux*)
+ LD="${LD-ld} -m elf_s390"
+ ;;
+ sparc64-*linux*)
+ LD="${LD-ld} -m elf32_sparc"
+ ;;
+ esac
+ ;;
+ *64-bit*)
+ case $host in
+ x86_64-*kfreebsd*-gnu)
+ LD="${LD-ld} -m elf_x86_64_fbsd"
+ ;;
+ x86_64-*linux*)
+ LD="${LD-ld} -m elf_x86_64"
+ ;;
+ powerpcle-*linux*)
+ LD="${LD-ld} -m elf64lppc"
+ ;;
+ powerpc-*linux*)
+ LD="${LD-ld} -m elf64ppc"
+ ;;
+ s390*-*linux*|s390*-*tpf*)
+ LD="${LD-ld} -m elf64_s390"
+ ;;
+ sparc*-*linux*)
+ LD="${LD-ld} -m elf64_sparc"
+ ;;
+ esac
+ ;;
+ esac
+ fi
+ rm -rf conftest*
+ ;;
+
+*-*-sco3.2v5*)
+ # On SCO OpenServer 5, we need -belf to get full-featured binaries.
+ SAVE_CFLAGS=$CFLAGS
+ CFLAGS="$CFLAGS -belf"
+ AC_CACHE_CHECK([whether the C compiler needs -belf], lt_cv_cc_needs_belf,
+ [AC_LANG_PUSH(C)
+ AC_LINK_IFELSE([AC_LANG_PROGRAM([[]],[[]])],[lt_cv_cc_needs_belf=yes],[lt_cv_cc_needs_belf=no])
+ AC_LANG_POP])
+ if test yes != "$lt_cv_cc_needs_belf"; then
+ # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf
+ CFLAGS=$SAVE_CFLAGS
+ fi
+ ;;
+*-*solaris*)
+ # Find out what ABI is being produced by ac_compile, and set linker
+ # options accordingly.
+ echo 'int i;' > conftest.$ac_ext
+ if AC_TRY_EVAL(ac_compile); then
+ case `/usr/bin/file conftest.o` in
+ *64-bit*)
+ case $lt_cv_prog_gnu_ld in
+ yes*)
+ case $host in
+ i?86-*-solaris*|x86_64-*-solaris*)
+ LD="${LD-ld} -m elf_x86_64"
+ ;;
+ sparc*-*-solaris*)
+ LD="${LD-ld} -m elf64_sparc"
+ ;;
+ esac
+ # GNU ld 2.21 introduced _sol2 emulations. Use them if available.
+ if ${LD-ld} -V | grep _sol2 >/dev/null 2>&1; then
+ LD=${LD-ld}_sol2
+ fi
+ ;;
+ *)
+ if ${LD-ld} -64 -r -o conftest2.o conftest.o >/dev/null 2>&1; then
+ LD="${LD-ld} -64"
+ fi
+ ;;
+ esac
+ ;;
+ esac
+ fi
+ rm -rf conftest*
+ ;;
+esac
+
+need_locks=$enable_libtool_lock
+])# _LT_ENABLE_LOCK
+
+
+# _LT_PROG_AR
+# -----------
+m4_defun([_LT_PROG_AR],
+[AC_CHECK_TOOLS(AR, [ar], false)
+: ${AR=ar}
+: ${AR_FLAGS=cru}
+_LT_DECL([], [AR], [1], [The archiver])
+_LT_DECL([], [AR_FLAGS], [1], [Flags to create an archive])
+
+AC_CACHE_CHECK([for archiver @FILE support], [lt_cv_ar_at_file],
+ [lt_cv_ar_at_file=no
+ AC_COMPILE_IFELSE([AC_LANG_PROGRAM],
+ [echo conftest.$ac_objext > conftest.lst
+ lt_ar_try='$AR $AR_FLAGS libconftest.a @conftest.lst >&AS_MESSAGE_LOG_FD'
+ AC_TRY_EVAL([lt_ar_try])
+ if test 0 -eq "$ac_status"; then
+ # Ensure the archiver fails upon bogus file names.
+ rm -f conftest.$ac_objext libconftest.a
+ AC_TRY_EVAL([lt_ar_try])
+ if test 0 -ne "$ac_status"; then
+ lt_cv_ar_at_file=@
+ fi
+ fi
+ rm -f conftest.* libconftest.a
+ ])
+ ])
+
+if test no = "$lt_cv_ar_at_file"; then
+ archiver_list_spec=
+else
+ archiver_list_spec=$lt_cv_ar_at_file
+fi
+_LT_DECL([], [archiver_list_spec], [1],
+ [How to feed a file listing to the archiver])
+])# _LT_PROG_AR
+
+
+# _LT_CMD_OLD_ARCHIVE
+# -------------------
+m4_defun([_LT_CMD_OLD_ARCHIVE],
+[_LT_PROG_AR
+
+AC_CHECK_TOOL(STRIP, strip, :)
+test -z "$STRIP" && STRIP=:
+_LT_DECL([], [STRIP], [1], [A symbol stripping program])
+
+AC_CHECK_TOOL(RANLIB, ranlib, :)
+test -z "$RANLIB" && RANLIB=:
+_LT_DECL([], [RANLIB], [1],
+ [Commands used to install an old-style archive])
+
+# Determine commands to create old-style static archives.
+old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs'
+old_postinstall_cmds='chmod 644 $oldlib'
+old_postuninstall_cmds=
+
+if test -n "$RANLIB"; then
+ case $host_os in
+ bitrig* | openbsd*)
+ old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$tool_oldlib"
+ ;;
+ *)
+ old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$tool_oldlib"
+ ;;
+ esac
+ old_archive_cmds="$old_archive_cmds~\$RANLIB \$tool_oldlib"
+fi
+
+case $host_os in
+ darwin*)
+ lock_old_archive_extraction=yes ;;
+ *)
+ lock_old_archive_extraction=no ;;
+esac
+_LT_DECL([], [old_postinstall_cmds], [2])
+_LT_DECL([], [old_postuninstall_cmds], [2])
+_LT_TAGDECL([], [old_archive_cmds], [2],
+ [Commands used to build an old-style archive])
+_LT_DECL([], [lock_old_archive_extraction], [0],
+ [Whether to use a lock for old archive extraction])
+])# _LT_CMD_OLD_ARCHIVE
+
+
+# _LT_COMPILER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS,
+# [OUTPUT-FILE], [ACTION-SUCCESS], [ACTION-FAILURE])
+# ----------------------------------------------------------------
+# Check whether the given compiler option works
+AC_DEFUN([_LT_COMPILER_OPTION],
+[m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+m4_require([_LT_DECL_SED])dnl
+AC_CACHE_CHECK([$1], [$2],
+ [$2=no
+ m4_if([$4], , [ac_outfile=conftest.$ac_objext], [ac_outfile=$4])
+ echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+ lt_compiler_flag="$3" ## exclude from sc_useless_quotes_in_assignment
+ # Insert the option either (1) after the last *FLAGS variable, or
+ # (2) before a word containing "conftest.", or (3) at the end.
+ # Note that $ac_compile itself does not contain backslashes and begins
+ # with a dollar sign (not a hyphen), so the echo should work correctly.
+ # The option is referenced via a variable to avoid confusing sed.
+ lt_compile=`echo "$ac_compile" | $SED \
+ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
+ -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \
+ -e 's:$: $lt_compiler_flag:'`
+ (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&AS_MESSAGE_LOG_FD)
+ (eval "$lt_compile" 2>conftest.err)
+ ac_status=$?
+ cat conftest.err >&AS_MESSAGE_LOG_FD
+ echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD
+ if (exit $ac_status) && test -s "$ac_outfile"; then
+ # The compiler can only warn and ignore the option if not recognized
+ # So say no if there are warnings other than the usual output.
+ $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp
+ $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
+ if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then
+ $2=yes
+ fi
+ fi
+ $RM conftest*
+])
+
+if test yes = "[$]$2"; then
+ m4_if([$5], , :, [$5])
+else
+ m4_if([$6], , :, [$6])
+fi
+])# _LT_COMPILER_OPTION
+
+# Old name:
+AU_ALIAS([AC_LIBTOOL_COMPILER_OPTION], [_LT_COMPILER_OPTION])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_LIBTOOL_COMPILER_OPTION], [])
+
+
+# _LT_LINKER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS,
+# [ACTION-SUCCESS], [ACTION-FAILURE])
+# ----------------------------------------------------
+# Check whether the given linker option works
+AC_DEFUN([_LT_LINKER_OPTION],
+[m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+m4_require([_LT_DECL_SED])dnl
+AC_CACHE_CHECK([$1], [$2],
+ [$2=no
+ save_LDFLAGS=$LDFLAGS
+ LDFLAGS="$LDFLAGS $3"
+ echo "$lt_simple_link_test_code" > conftest.$ac_ext
+ if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then
+ # The linker can only warn and ignore the option if not recognized
+ # So say no if there are warnings
+ if test -s conftest.err; then
+ # Append any errors to the config.log.
+ cat conftest.err 1>&AS_MESSAGE_LOG_FD
+ $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp
+ $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
+ if diff conftest.exp conftest.er2 >/dev/null; then
+ $2=yes
+ fi
+ else
+ $2=yes
+ fi
+ fi
+ $RM -r conftest*
+ LDFLAGS=$save_LDFLAGS
+])
+
+if test yes = "[$]$2"; then
+ m4_if([$4], , :, [$4])
+else
+ m4_if([$5], , :, [$5])
+fi
+])# _LT_LINKER_OPTION
+
+# Old name:
+AU_ALIAS([AC_LIBTOOL_LINKER_OPTION], [_LT_LINKER_OPTION])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_LIBTOOL_LINKER_OPTION], [])
+
+
+# LT_CMD_MAX_LEN
+#---------------
+AC_DEFUN([LT_CMD_MAX_LEN],
+[AC_REQUIRE([AC_CANONICAL_HOST])dnl
+# find the maximum length of command line arguments
+AC_MSG_CHECKING([the maximum length of command line arguments])
+AC_CACHE_VAL([lt_cv_sys_max_cmd_len], [dnl
+ i=0
+ teststring=ABCD
+
+ case $build_os in
+ msdosdjgpp*)
+ # On DJGPP, this test can blow up pretty badly due to problems in libc
+ # (any single argument exceeding 2000 bytes causes a buffer overrun
+ # during glob expansion). Even if it were fixed, the result of this
+ # check would be larger than it should be.
+ lt_cv_sys_max_cmd_len=12288; # 12K is about right
+ ;;
+
+ gnu*)
+ # Under GNU Hurd, this test is not required because there is
+ # no limit to the length of command line arguments.
+ # Libtool will interpret -1 as no limit whatsoever
+ lt_cv_sys_max_cmd_len=-1;
+ ;;
+
+ cygwin* | mingw* | cegcc*)
+ # On Win9x/ME, this test blows up -- it succeeds, but takes
+ # about 5 minutes as the teststring grows exponentially.
+ # Worse, since 9x/ME are not pre-emptively multitasking,
+ # you end up with a "frozen" computer, even though with patience
+ # the test eventually succeeds (with a max line length of 256k).
+ # Instead, let's just punt: use the minimum linelength reported by
+ # all of the supported platforms: 8192 (on NT/2K/XP).
+ lt_cv_sys_max_cmd_len=8192;
+ ;;
+
+ mint*)
+ # On MiNT this can take a long time and run out of memory.
+ lt_cv_sys_max_cmd_len=8192;
+ ;;
+
+ amigaos*)
+ # On AmigaOS with pdksh, this test takes hours, literally.
+ # So we just punt and use a minimum line length of 8192.
+ lt_cv_sys_max_cmd_len=8192;
+ ;;
+
+ bitrig* | darwin* | dragonfly* | freebsd* | netbsd* | openbsd*)
+ # This has been around since 386BSD, at least. Likely further.
+ if test -x /sbin/sysctl; then
+ lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax`
+ elif test -x /usr/sbin/sysctl; then
+ lt_cv_sys_max_cmd_len=`/usr/sbin/sysctl -n kern.argmax`
+ else
+ lt_cv_sys_max_cmd_len=65536 # usable default for all BSDs
+ fi
+ # And add a safety zone
+ lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4`
+ lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3`
+ ;;
+
+ interix*)
+ # We know the value 262144 and hardcode it with a safety zone (like BSD)
+ lt_cv_sys_max_cmd_len=196608
+ ;;
+
+ os2*)
+ # The test takes a long time on OS/2.
+ lt_cv_sys_max_cmd_len=8192
+ ;;
+
+ osf*)
+ # Dr. Hans Ekkehard Plesser reports seeing a kernel panic running configure
+ # due to this test when exec_disable_arg_limit is 1 on Tru64. It is not
+ # nice to cause kernel panics so lets avoid the loop below.
+ # First set a reasonable default.
+ lt_cv_sys_max_cmd_len=16384
+ #
+ if test -x /sbin/sysconfig; then
+ case `/sbin/sysconfig -q proc exec_disable_arg_limit` in
+ *1*) lt_cv_sys_max_cmd_len=-1 ;;
+ esac
+ fi
+ ;;
+ sco3.2v5*)
+ lt_cv_sys_max_cmd_len=102400
+ ;;
+ sysv5* | sco5v6* | sysv4.2uw2*)
+ kargmax=`grep ARG_MAX /etc/conf/cf.d/stune 2>/dev/null`
+ if test -n "$kargmax"; then
+ lt_cv_sys_max_cmd_len=`echo $kargmax | sed 's/.*[[ ]]//'`
+ else
+ lt_cv_sys_max_cmd_len=32768
+ fi
+ ;;
+ *)
+ lt_cv_sys_max_cmd_len=`(getconf ARG_MAX) 2> /dev/null`
+ if test -n "$lt_cv_sys_max_cmd_len" && \
+ test undefined != "$lt_cv_sys_max_cmd_len"; then
+ lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4`
+ lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3`
+ else
+ # Make teststring a little bigger before we do anything with it.
+ # a 1K string should be a reasonable start.
+ for i in 1 2 3 4 5 6 7 8; do
+ teststring=$teststring$teststring
+ done
+ SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}}
+ # If test is not a shell built-in, we'll probably end up computing a
+ # maximum length that is only half of the actual maximum length, but
+ # we can't tell.
+ while { test X`env echo "$teststring$teststring" 2>/dev/null` \
+ = "X$teststring$teststring"; } >/dev/null 2>&1 &&
+ test 17 != "$i" # 1/2 MB should be enough
+ do
+ i=`expr $i + 1`
+ teststring=$teststring$teststring
+ done
+ # Only check the string length outside the loop.
+ lt_cv_sys_max_cmd_len=`expr "X$teststring" : ".*" 2>&1`
+ teststring=
+ # Add a significant safety factor because C++ compilers can tack on
+ # massive amounts of additional arguments before passing them to the
+ # linker. It appears as though 1/2 is a usable value.
+ lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2`
+ fi
+ ;;
+ esac
+])
+if test -n "$lt_cv_sys_max_cmd_len"; then
+ AC_MSG_RESULT($lt_cv_sys_max_cmd_len)
+else
+ AC_MSG_RESULT(none)
+fi
+max_cmd_len=$lt_cv_sys_max_cmd_len
+_LT_DECL([], [max_cmd_len], [0],
+ [What is the maximum length of a command?])
+])# LT_CMD_MAX_LEN
+
+# Old name:
+AU_ALIAS([AC_LIBTOOL_SYS_MAX_CMD_LEN], [LT_CMD_MAX_LEN])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_LIBTOOL_SYS_MAX_CMD_LEN], [])
+
+
+# _LT_HEADER_DLFCN
+# ----------------
+m4_defun([_LT_HEADER_DLFCN],
+[AC_CHECK_HEADERS([dlfcn.h], [], [], [AC_INCLUDES_DEFAULT])dnl
+])# _LT_HEADER_DLFCN
+
+
+# _LT_TRY_DLOPEN_SELF (ACTION-IF-TRUE, ACTION-IF-TRUE-W-USCORE,
+# ACTION-IF-FALSE, ACTION-IF-CROSS-COMPILING)
+# ----------------------------------------------------------------
+m4_defun([_LT_TRY_DLOPEN_SELF],
+[m4_require([_LT_HEADER_DLFCN])dnl
+if test yes = "$cross_compiling"; then :
+ [$4]
+else
+ lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
+ lt_status=$lt_dlunknown
+ cat > conftest.$ac_ext <<_LT_EOF
+[#line $LINENO "configure"
+#include "confdefs.h"
+
+#if HAVE_DLFCN_H
+#include <dlfcn.h>
+#endif
+
+#include <stdio.h>
+
+#ifdef RTLD_GLOBAL
+# define LT_DLGLOBAL RTLD_GLOBAL
+#else
+# ifdef DL_GLOBAL
+# define LT_DLGLOBAL DL_GLOBAL
+# else
+# define LT_DLGLOBAL 0
+# endif
+#endif
+
+/* We may have to define LT_DLLAZY_OR_NOW in the command line if we
+ find out it does not work in some platform. */
+#ifndef LT_DLLAZY_OR_NOW
+# ifdef RTLD_LAZY
+# define LT_DLLAZY_OR_NOW RTLD_LAZY
+# else
+# ifdef DL_LAZY
+# define LT_DLLAZY_OR_NOW DL_LAZY
+# else
+# ifdef RTLD_NOW
+# define LT_DLLAZY_OR_NOW RTLD_NOW
+# else
+# ifdef DL_NOW
+# define LT_DLLAZY_OR_NOW DL_NOW
+# else
+# define LT_DLLAZY_OR_NOW 0
+# endif
+# endif
+# endif
+# endif
+#endif
+
+/* When -fvisibility=hidden is used, assume the code has been annotated
+ correspondingly for the symbols needed. */
+#if defined __GNUC__ && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3))
+int fnord () __attribute__((visibility("default")));
+#endif
+
+int fnord () { return 42; }
+int main ()
+{
+ void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW);
+ int status = $lt_dlunknown;
+
+ if (self)
+ {
+ if (dlsym (self,"fnord")) status = $lt_dlno_uscore;
+ else
+ {
+ if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore;
+ else puts (dlerror ());
+ }
+ /* dlclose (self); */
+ }
+ else
+ puts (dlerror ());
+
+ return status;
+}]
+_LT_EOF
+ if AC_TRY_EVAL(ac_link) && test -s "conftest$ac_exeext" 2>/dev/null; then
+ (./conftest; exit; ) >&AS_MESSAGE_LOG_FD 2>/dev/null
+ lt_status=$?
+ case x$lt_status in
+ x$lt_dlno_uscore) $1 ;;
+ x$lt_dlneed_uscore) $2 ;;
+ x$lt_dlunknown|x*) $3 ;;
+ esac
+ else :
+ # compilation failed
+ $3
+ fi
+fi
+rm -fr conftest*
+])# _LT_TRY_DLOPEN_SELF
+
+
+# LT_SYS_DLOPEN_SELF
+# ------------------
+AC_DEFUN([LT_SYS_DLOPEN_SELF],
+[m4_require([_LT_HEADER_DLFCN])dnl
+if test yes != "$enable_dlopen"; then
+ enable_dlopen=unknown
+ enable_dlopen_self=unknown
+ enable_dlopen_self_static=unknown
+else
+ lt_cv_dlopen=no
+ lt_cv_dlopen_libs=
+
+ case $host_os in
+ beos*)
+ lt_cv_dlopen=load_add_on
+ lt_cv_dlopen_libs=
+ lt_cv_dlopen_self=yes
+ ;;
+
+ mingw* | pw32* | cegcc*)
+ lt_cv_dlopen=LoadLibrary
+ lt_cv_dlopen_libs=
+ ;;
+
+ cygwin*)
+ lt_cv_dlopen=dlopen
+ lt_cv_dlopen_libs=
+ ;;
+
+ darwin*)
+ # if libdl is installed we need to link against it
+ AC_CHECK_LIB([dl], [dlopen],
+ [lt_cv_dlopen=dlopen lt_cv_dlopen_libs=-ldl],[
+ lt_cv_dlopen=dyld
+ lt_cv_dlopen_libs=
+ lt_cv_dlopen_self=yes
+ ])
+ ;;
+
+ tpf*)
+ # Don't try to run any link tests for TPF. We know it's impossible
+ # because TPF is a cross-compiler, and we know how we open DSOs.
+ lt_cv_dlopen=dlopen
+ lt_cv_dlopen_libs=
+ lt_cv_dlopen_self=no
+ ;;
+
+ *)
+ AC_CHECK_FUNC([shl_load],
+ [lt_cv_dlopen=shl_load],
+ [AC_CHECK_LIB([dld], [shl_load],
+ [lt_cv_dlopen=shl_load lt_cv_dlopen_libs=-ldld],
+ [AC_CHECK_FUNC([dlopen],
+ [lt_cv_dlopen=dlopen],
+ [AC_CHECK_LIB([dl], [dlopen],
+ [lt_cv_dlopen=dlopen lt_cv_dlopen_libs=-ldl],
+ [AC_CHECK_LIB([svld], [dlopen],
+ [lt_cv_dlopen=dlopen lt_cv_dlopen_libs=-lsvld],
+ [AC_CHECK_LIB([dld], [dld_link],
+ [lt_cv_dlopen=dld_link lt_cv_dlopen_libs=-ldld])
+ ])
+ ])
+ ])
+ ])
+ ])
+ ;;
+ esac
+
+ if test no = "$lt_cv_dlopen"; then
+ enable_dlopen=no
+ else
+ enable_dlopen=yes
+ fi
+
+ case $lt_cv_dlopen in
+ dlopen)
+ save_CPPFLAGS=$CPPFLAGS
+ test yes = "$ac_cv_header_dlfcn_h" && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H"
+
+ save_LDFLAGS=$LDFLAGS
+ wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\"
+
+ save_LIBS=$LIBS
+ LIBS="$lt_cv_dlopen_libs $LIBS"
+
+ AC_CACHE_CHECK([whether a program can dlopen itself],
+ lt_cv_dlopen_self, [dnl
+ _LT_TRY_DLOPEN_SELF(
+ lt_cv_dlopen_self=yes, lt_cv_dlopen_self=yes,
+ lt_cv_dlopen_self=no, lt_cv_dlopen_self=cross)
+ ])
+
+ if test yes = "$lt_cv_dlopen_self"; then
+ wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\"
+ AC_CACHE_CHECK([whether a statically linked program can dlopen itself],
+ lt_cv_dlopen_self_static, [dnl
+ _LT_TRY_DLOPEN_SELF(
+ lt_cv_dlopen_self_static=yes, lt_cv_dlopen_self_static=yes,
+ lt_cv_dlopen_self_static=no, lt_cv_dlopen_self_static=cross)
+ ])
+ fi
+
+ CPPFLAGS=$save_CPPFLAGS
+ LDFLAGS=$save_LDFLAGS
+ LIBS=$save_LIBS
+ ;;
+ esac
+
+ case $lt_cv_dlopen_self in
+ yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;;
+ *) enable_dlopen_self=unknown ;;
+ esac
+
+ case $lt_cv_dlopen_self_static in
+ yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;;
+ *) enable_dlopen_self_static=unknown ;;
+ esac
+fi
+_LT_DECL([dlopen_support], [enable_dlopen], [0],
+ [Whether dlopen is supported])
+_LT_DECL([dlopen_self], [enable_dlopen_self], [0],
+ [Whether dlopen of programs is supported])
+_LT_DECL([dlopen_self_static], [enable_dlopen_self_static], [0],
+ [Whether dlopen of statically linked programs is supported])
+])# LT_SYS_DLOPEN_SELF
+
+# Old name:
+AU_ALIAS([AC_LIBTOOL_DLOPEN_SELF], [LT_SYS_DLOPEN_SELF])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_LIBTOOL_DLOPEN_SELF], [])
+
+
+# _LT_COMPILER_C_O([TAGNAME])
+# ---------------------------
+# Check to see if options -c and -o are simultaneously supported by compiler.
+# This macro does not hard code the compiler like AC_PROG_CC_C_O.
+m4_defun([_LT_COMPILER_C_O],
+[m4_require([_LT_DECL_SED])dnl
+m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+m4_require([_LT_TAG_COMPILER])dnl
+AC_CACHE_CHECK([if $compiler supports -c -o file.$ac_objext],
+ [_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)],
+ [_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=no
+ $RM -r conftest 2>/dev/null
+ mkdir conftest
+ cd conftest
+ mkdir out
+ echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+
+ lt_compiler_flag="-o out/conftest2.$ac_objext"
+ # Insert the option either (1) after the last *FLAGS variable, or
+ # (2) before a word containing "conftest.", or (3) at the end.
+ # Note that $ac_compile itself does not contain backslashes and begins
+ # with a dollar sign (not a hyphen), so the echo should work correctly.
+ lt_compile=`echo "$ac_compile" | $SED \
+ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
+ -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \
+ -e 's:$: $lt_compiler_flag:'`
+ (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&AS_MESSAGE_LOG_FD)
+ (eval "$lt_compile" 2>out/conftest.err)
+ ac_status=$?
+ cat out/conftest.err >&AS_MESSAGE_LOG_FD
+ echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD
+ if (exit $ac_status) && test -s out/conftest2.$ac_objext
+ then
+ # The compiler can only warn and ignore the option if not recognized
+ # So say no if there are warnings
+ $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp
+ $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2
+ if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then
+ _LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes
+ fi
+ fi
+ chmod u+w . 2>&AS_MESSAGE_LOG_FD
+ $RM conftest*
+ # SGI C++ compiler will create directory out/ii_files/ for
+ # template instantiation
+ test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files
+ $RM out/* && rmdir out
+ cd ..
+ $RM -r conftest
+ $RM conftest*
+])
+_LT_TAGDECL([compiler_c_o], [lt_cv_prog_compiler_c_o], [1],
+ [Does compiler simultaneously support -c and -o options?])
+])# _LT_COMPILER_C_O
+
+
+# _LT_COMPILER_FILE_LOCKS([TAGNAME])
+# ----------------------------------
+# Check to see if we can do hard links to lock some files if needed
+m4_defun([_LT_COMPILER_FILE_LOCKS],
+[m4_require([_LT_ENABLE_LOCK])dnl
+m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+_LT_COMPILER_C_O([$1])
+
+hard_links=nottested
+if test no = "$_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)" && test no != "$need_locks"; then
+ # do not overwrite the value of need_locks provided by the user
+ AC_MSG_CHECKING([if we can lock with hard links])
+ hard_links=yes
+ $RM conftest*
+ ln conftest.a conftest.b 2>/dev/null && hard_links=no
+ touch conftest.a
+ ln conftest.a conftest.b 2>&5 || hard_links=no
+ ln conftest.a conftest.b 2>/dev/null && hard_links=no
+ AC_MSG_RESULT([$hard_links])
+ if test no = "$hard_links"; then
+ AC_MSG_WARN(['$CC' does not support '-c -o', so 'make -j' may be unsafe])
+ need_locks=warn
+ fi
+else
+ need_locks=no
+fi
+_LT_DECL([], [need_locks], [1], [Must we lock files when doing compilation?])
+])# _LT_COMPILER_FILE_LOCKS
+
+
+# _LT_CHECK_OBJDIR
+# ----------------
+m4_defun([_LT_CHECK_OBJDIR],
+[AC_CACHE_CHECK([for objdir], [lt_cv_objdir],
+[rm -f .libs 2>/dev/null
+mkdir .libs 2>/dev/null
+if test -d .libs; then
+ lt_cv_objdir=.libs
+else
+ # MS-DOS does not allow filenames that begin with a dot.
+ lt_cv_objdir=_libs
+fi
+rmdir .libs 2>/dev/null])
+objdir=$lt_cv_objdir
+_LT_DECL([], [objdir], [0],
+ [The name of the directory that contains temporary libtool files])dnl
+m4_pattern_allow([LT_OBJDIR])dnl
+AC_DEFINE_UNQUOTED([LT_OBJDIR], "$lt_cv_objdir/",
+ [Define to the sub-directory where libtool stores uninstalled libraries.])
+])# _LT_CHECK_OBJDIR
+
+
+# _LT_LINKER_HARDCODE_LIBPATH([TAGNAME])
+# --------------------------------------
+# Check hardcoding attributes.
+m4_defun([_LT_LINKER_HARDCODE_LIBPATH],
+[AC_MSG_CHECKING([how to hardcode library paths into programs])
+_LT_TAGVAR(hardcode_action, $1)=
+if test -n "$_LT_TAGVAR(hardcode_libdir_flag_spec, $1)" ||
+ test -n "$_LT_TAGVAR(runpath_var, $1)" ||
+ test yes = "$_LT_TAGVAR(hardcode_automatic, $1)"; then
+
+ # We can hardcode non-existent directories.
+ if test no != "$_LT_TAGVAR(hardcode_direct, $1)" &&
+ # If the only mechanism to avoid hardcoding is shlibpath_var, we
+ # have to relink, otherwise we might link with an installed library
+ # when we should be linking with a yet-to-be-installed one
+ ## test no != "$_LT_TAGVAR(hardcode_shlibpath_var, $1)" &&
+ test no != "$_LT_TAGVAR(hardcode_minus_L, $1)"; then
+ # Linking always hardcodes the temporary library directory.
+ _LT_TAGVAR(hardcode_action, $1)=relink
+ else
+ # We can link without hardcoding, and we can hardcode nonexisting dirs.
+ _LT_TAGVAR(hardcode_action, $1)=immediate
+ fi
+else
+ # We cannot hardcode anything, or else we can only hardcode existing
+ # directories.
+ _LT_TAGVAR(hardcode_action, $1)=unsupported
+fi
+AC_MSG_RESULT([$_LT_TAGVAR(hardcode_action, $1)])
+
+if test relink = "$_LT_TAGVAR(hardcode_action, $1)" ||
+ test yes = "$_LT_TAGVAR(inherit_rpath, $1)"; then
+ # Fast installation is not supported
+ enable_fast_install=no
+elif test yes = "$shlibpath_overrides_runpath" ||
+ test no = "$enable_shared"; then
+ # Fast installation is not necessary
+ enable_fast_install=needless
+fi
+_LT_TAGDECL([], [hardcode_action], [0],
+ [How to hardcode a shared library path into an executable])
+])# _LT_LINKER_HARDCODE_LIBPATH
+
+
+# _LT_CMD_STRIPLIB
+# ----------------
+m4_defun([_LT_CMD_STRIPLIB],
+[m4_require([_LT_DECL_EGREP])
+striplib=
+old_striplib=
+AC_MSG_CHECKING([whether stripping libraries is possible])
+if test -n "$STRIP" && $STRIP -V 2>&1 | $GREP "GNU strip" >/dev/null; then
+ test -z "$old_striplib" && old_striplib="$STRIP --strip-debug"
+ test -z "$striplib" && striplib="$STRIP --strip-unneeded"
+ AC_MSG_RESULT([yes])
+else
+# FIXME - insert some real tests, host_os isn't really good enough
+ case $host_os in
+ darwin*)
+ if test -n "$STRIP"; then
+ striplib="$STRIP -x"
+ old_striplib="$STRIP -S"
+ AC_MSG_RESULT([yes])
+ else
+ AC_MSG_RESULT([no])
+ fi
+ ;;
+ *)
+ AC_MSG_RESULT([no])
+ ;;
+ esac
+fi
+_LT_DECL([], [old_striplib], [1], [Commands to strip libraries])
+_LT_DECL([], [striplib], [1])
+])# _LT_CMD_STRIPLIB
+
+
+# _LT_PREPARE_MUNGE_PATH_LIST
+# ---------------------------
+# Make sure func_munge_path_list() is defined correctly.
+m4_defun([_LT_PREPARE_MUNGE_PATH_LIST],
+[[# func_munge_path_list VARIABLE PATH
+# -----------------------------------
+# VARIABLE is name of variable containing _space_ separated list of
+# directories to be munged by the contents of PATH, which is string
+# having a format:
+# "DIR[:DIR]:"
+# string "DIR[ DIR]" will be prepended to VARIABLE
+# ":DIR[:DIR]"
+# string "DIR[ DIR]" will be appended to VARIABLE
+# "DIRP[:DIRP]::[DIRA:]DIRA"
+# string "DIRP[ DIRP]" will be prepended to VARIABLE and string
+# "DIRA[ DIRA]" will be appended to VARIABLE
+# "DIR[:DIR]"
+# VARIABLE will be replaced by "DIR[ DIR]"
+func_munge_path_list ()
+{
+ case x@S|@2 in
+ x)
+ ;;
+ *:)
+ eval @S|@1=\"`$ECHO @S|@2 | $SED 's/:/ /g'` \@S|@@S|@1\"
+ ;;
+ x:*)
+ eval @S|@1=\"\@S|@@S|@1 `$ECHO @S|@2 | $SED 's/:/ /g'`\"
+ ;;
+ *::*)
+ eval @S|@1=\"\@S|@@S|@1\ `$ECHO @S|@2 | $SED -e 's/.*:://' -e 's/:/ /g'`\"
+ eval @S|@1=\"`$ECHO @S|@2 | $SED -e 's/::.*//' -e 's/:/ /g'`\ \@S|@@S|@1\"
+ ;;
+ *)
+ eval @S|@1=\"`$ECHO @S|@2 | $SED 's/:/ /g'`\"
+ ;;
+ esac
+}
+]])# _LT_PREPARE_PATH_LIST
+
+
+# _LT_SYS_DYNAMIC_LINKER([TAG])
+# -----------------------------
+# PORTME Fill in your ld.so characteristics
+m4_defun([_LT_SYS_DYNAMIC_LINKER],
+[AC_REQUIRE([AC_CANONICAL_HOST])dnl
+m4_require([_LT_DECL_EGREP])dnl
+m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+m4_require([_LT_DECL_OBJDUMP])dnl
+m4_require([_LT_DECL_SED])dnl
+m4_require([_LT_CHECK_SHELL_FEATURES])dnl
+m4_require([_LT_PREPARE_MUNGE_PATH_LIST])dnl
+AC_MSG_CHECKING([dynamic linker characteristics])
+m4_if([$1],
+ [], [
+if test yes = "$GCC"; then
+ case $host_os in
+ darwin*) lt_awk_arg='/^libraries:/,/LR/' ;;
+ *) lt_awk_arg='/^libraries:/' ;;
+ esac
+ case $host_os in
+ mingw* | cegcc*) lt_sed_strip_eq='s|=\([[A-Za-z]]:\)|\1|g' ;;
+ *) lt_sed_strip_eq='s|=/|/|g' ;;
+ esac
+ lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e $lt_sed_strip_eq`
+ case $lt_search_path_spec in
+ *\;*)
+ # if the path contains ";" then we assume it to be the separator
+ # otherwise default to the standard path separator (i.e. ":") - it is
+ # assumed that no part of a normal pathname contains ";" but that should
+ # okay in the real world where ";" in dirpaths is itself problematic.
+ lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED 's/;/ /g'`
+ ;;
+ *)
+ lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED "s/$PATH_SEPARATOR/ /g"`
+ ;;
+ esac
+ # Ok, now we have the path, separated by spaces, we can step through it
+ # and add multilib dir if necessary...
+ lt_tmp_lt_search_path_spec=
+ lt_multi_os_dir=/`$CC $CPPFLAGS $CFLAGS $LDFLAGS -print-multi-os-directory 2>/dev/null`
+ # ...but if some path component already ends with the multilib dir we assume
+ # that all is fine and trust -print-search-dirs as is (GCC 4.2? or newer).
+ case "$lt_multi_os_dir; $lt_search_path_spec " in
+ "/; "* | "/.; "* | "/./; "* | *"$lt_multi_os_dir "* | *"$lt_multi_os_dir/ "*)
+ lt_multi_os_dir=
+ ;;
+ esac
+ for lt_sys_path in $lt_search_path_spec; do
+ if test -d "$lt_sys_path$lt_multi_os_dir"; then
+ lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path$lt_multi_os_dir"
+ elif test -n "$lt_multi_os_dir"; then
+ test -d "$lt_sys_path" && \
+ lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path"
+ fi
+ done
+ lt_search_path_spec=`$ECHO "$lt_tmp_lt_search_path_spec" | awk '
+BEGIN {RS = " "; FS = "/|\n";} {
+ lt_foo = "";
+ lt_count = 0;
+ for (lt_i = NF; lt_i > 0; lt_i--) {
+ if ($lt_i != "" && $lt_i != ".") {
+ if ($lt_i == "..") {
+ lt_count++;
+ } else {
+ if (lt_count == 0) {
+ lt_foo = "/" $lt_i lt_foo;
+ } else {
+ lt_count--;
+ }
+ }
+ }
+ }
+ if (lt_foo != "") { lt_freq[[lt_foo]]++; }
+ if (lt_freq[[lt_foo]] == 1) { print lt_foo; }
+}'`
+ # AWK program above erroneously prepends '/' to C:/dos/paths
+ # for these hosts.
+ case $host_os in
+ mingw* | cegcc*) lt_search_path_spec=`$ECHO "$lt_search_path_spec" |\
+ $SED 's|/\([[A-Za-z]]:\)|\1|g'` ;;
+ esac
+ sys_lib_search_path_spec=`$ECHO "$lt_search_path_spec" | $lt_NL2SP`
+else
+ sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib"
+fi])
+library_names_spec=
+libname_spec='lib$name'
+soname_spec=
+shrext_cmds=.so
+postinstall_cmds=
+postuninstall_cmds=
+finish_cmds=
+finish_eval=
+shlibpath_var=
+shlibpath_overrides_runpath=unknown
+version_type=none
+dynamic_linker="$host_os ld.so"
+sys_lib_dlsearch_path_spec="/lib /usr/lib"
+need_lib_prefix=unknown
+hardcode_into_libs=no
+
+# when you set need_version to no, make sure it does not cause -set_version
+# flags to be left without arguments
+need_version=unknown
+
+AC_ARG_VAR([LT_SYS_LIBRARY_PATH],
+[User-defined run-time library search path.])
+
+case $host_os in
+aix3*)
+ version_type=linux # correct to gnu/linux during the next big refactor
+ library_names_spec='$libname$release$shared_ext$versuffix $libname.a'
+ shlibpath_var=LIBPATH
+
+ # AIX 3 has no versioning support, so we append a major version to the name.
+ soname_spec='$libname$release$shared_ext$major'
+ ;;
+
+aix[[4-9]]*)
+ version_type=linux # correct to gnu/linux during the next big refactor
+ need_lib_prefix=no
+ need_version=no
+ hardcode_into_libs=yes
+ if test ia64 = "$host_cpu"; then
+ # AIX 5 supports IA64
+ library_names_spec='$libname$release$shared_ext$major $libname$release$shared_ext$versuffix $libname$shared_ext'
+ shlibpath_var=LD_LIBRARY_PATH
+ else
+ # With GCC up to 2.95.x, collect2 would create an import file
+ # for dependence libraries. The import file would start with
+ # the line '#! .'. This would cause the generated library to
+ # depend on '.', always an invalid library. This was fixed in
+ # development snapshots of GCC prior to 3.0.
+ case $host_os in
+ aix4 | aix4.[[01]] | aix4.[[01]].*)
+ if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)'
+ echo ' yes '
+ echo '#endif'; } | $CC -E - | $GREP yes > /dev/null; then
+ :
+ else
+ can_build_shared=no
+ fi
+ ;;
+ esac
+ # Using Import Files as archive members, it is possible to support
+ # filename-based versioning of shared library archives on AIX. While
+ # this would work for both with and without runtime linking, it will
+ # prevent static linking of such archives. So we do filename-based
+ # shared library versioning with .so extension only, which is used
+ # when both runtime linking and shared linking is enabled.
+ # Unfortunately, runtime linking may impact performance, so we do
+ # not want this to be the default eventually. Also, we use the
+ # versioned .so libs for executables only if there is the -brtl
+ # linker flag in LDFLAGS as well, or --with-aix-soname=svr4 only.
+ # To allow for filename-based versioning support, we need to create
+ # libNAME.so.V as an archive file, containing:
+ # *) an Import File, referring to the versioned filename of the
+ # archive as well as the shared archive member, telling the
+ # bitwidth (32 or 64) of that shared object, and providing the
+ # list of exported symbols of that shared object, eventually
+ # decorated with the 'weak' keyword
+ # *) the shared object with the F_LOADONLY flag set, to really avoid
+ # it being seen by the linker.
+ # At run time we better use the real file rather than another symlink,
+ # but for link time we create the symlink libNAME.so -> libNAME.so.V
+
+ case $with_aix_soname,$aix_use_runtimelinking in
+ # AIX (on Power*) has no versioning support, so currently we cannot hardcode correct
+ # soname into executable. Probably we can add versioning support to
+ # collect2, so additional links can be useful in future.
+ aix,yes) # traditional libtool
+ dynamic_linker='AIX unversionable lib.so'
+ # If using run time linking (on AIX 4.2 or later) use lib<name>.so
+ # instead of lib<name>.a to let people know that these are not
+ # typical AIX shared libraries.
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ ;;
+ aix,no) # traditional AIX only
+ dynamic_linker='AIX lib.a[(]lib.so.V[)]'
+ # We preserve .a as extension for shared libraries through AIX4.2
+ # and later when we are not doing run time linking.
+ library_names_spec='$libname$release.a $libname.a'
+ soname_spec='$libname$release$shared_ext$major'
+ ;;
+ svr4,*) # full svr4 only
+ dynamic_linker="AIX lib.so.V[(]$shared_archive_member_spec.o[)]"
+ library_names_spec='$libname$release$shared_ext$major $libname$shared_ext'
+ # We do not specify a path in Import Files, so LIBPATH fires.
+ shlibpath_overrides_runpath=yes
+ ;;
+ *,yes) # both, prefer svr4
+ dynamic_linker="AIX lib.so.V[(]$shared_archive_member_spec.o[)], lib.a[(]lib.so.V[)]"
+ library_names_spec='$libname$release$shared_ext$major $libname$shared_ext'
+ # unpreferred sharedlib libNAME.a needs extra handling
+ postinstall_cmds='test -n "$linkname" || linkname="$realname"~func_stripname "" ".so" "$linkname"~$install_shared_prog "$dir/$func_stripname_result.$libext" "$destdir/$func_stripname_result.$libext"~test -z "$tstripme" || test -z "$striplib" || $striplib "$destdir/$func_stripname_result.$libext"'
+ postuninstall_cmds='for n in $library_names $old_library; do :; done~func_stripname "" ".so" "$n"~test "$func_stripname_result" = "$n" || func_append rmfiles " $odir/$func_stripname_result.$libext"'
+ # We do not specify a path in Import Files, so LIBPATH fires.
+ shlibpath_overrides_runpath=yes
+ ;;
+ *,no) # both, prefer aix
+ dynamic_linker="AIX lib.a[(]lib.so.V[)], lib.so.V[(]$shared_archive_member_spec.o[)]"
+ library_names_spec='$libname$release.a $libname.a'
+ soname_spec='$libname$release$shared_ext$major'
+ # unpreferred sharedlib libNAME.so.V and symlink libNAME.so need extra handling
+ postinstall_cmds='test -z "$dlname" || $install_shared_prog $dir/$dlname $destdir/$dlname~test -z "$tstripme" || test -z "$striplib" || $striplib $destdir/$dlname~test -n "$linkname" || linkname=$realname~func_stripname "" ".a" "$linkname"~(cd "$destdir" && $LN_S -f $dlname $func_stripname_result.so)'
+ postuninstall_cmds='test -z "$dlname" || func_append rmfiles " $odir/$dlname"~for n in $old_library $library_names; do :; done~func_stripname "" ".a" "$n"~func_append rmfiles " $odir/$func_stripname_result.so"'
+ ;;
+ esac
+ shlibpath_var=LIBPATH
+ fi
+ ;;
+
+amigaos*)
+ case $host_cpu in
+ powerpc)
+ # Since July 2007 AmigaOS4 officially supports .so libraries.
+ # When compiling the executable, add -use-dynld -Lsobjs: to the compileline.
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ ;;
+ m68k)
+ library_names_spec='$libname.ixlibrary $libname.a'
+ # Create ${libname}_ixlibrary.a entries in /sys/libs.
+ finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`func_echo_all "$lib" | $SED '\''s%^.*/\([[^/]]*\)\.ixlibrary$%\1%'\''`; $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done'
+ ;;
+ esac
+ ;;
+
+beos*)
+ library_names_spec='$libname$shared_ext'
+ dynamic_linker="$host_os ld.so"
+ shlibpath_var=LIBRARY_PATH
+ ;;
+
+bsdi[[45]]*)
+ version_type=linux # correct to gnu/linux during the next big refactor
+ need_version=no
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ soname_spec='$libname$release$shared_ext$major'
+ finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir'
+ shlibpath_var=LD_LIBRARY_PATH
+ sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib"
+ sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib"
+ # the default ld.so.conf also contains /usr/contrib/lib and
+ # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow
+ # libtool to hard-code these into programs
+ ;;
+
+cygwin* | mingw* | pw32* | cegcc*)
+ version_type=windows
+ shrext_cmds=.dll
+ need_version=no
+ need_lib_prefix=no
+
+ case $GCC,$cc_basename in
+ yes,*)
+ # gcc
+ library_names_spec='$libname.dll.a'
+ # DLL is installed to $(libdir)/../bin by postinstall_cmds
+ postinstall_cmds='base_file=`basename \$file`~
+ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\$base_file'\''i; echo \$dlname'\''`~
+ dldir=$destdir/`dirname \$dlpath`~
+ test -d \$dldir || mkdir -p \$dldir~
+ $install_prog $dir/$dlname \$dldir/$dlname~
+ chmod a+x \$dldir/$dlname~
+ if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then
+ eval '\''$striplib \$dldir/$dlname'\'' || exit \$?;
+ fi'
+ postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~
+ dlpath=$dir/\$dldll~
+ $RM \$dlpath'
+ shlibpath_overrides_runpath=yes
+
+ case $host_os in
+ cygwin*)
+ # Cygwin DLLs use 'cyg' prefix rather than 'lib'
+ soname_spec='`echo $libname | sed -e 's/^lib/cyg/'``echo $release | $SED -e 's/[[.]]/-/g'`$versuffix$shared_ext'
+m4_if([$1], [],[
+ sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/lib/w32api"])
+ ;;
+ mingw* | cegcc*)
+ # MinGW DLLs use traditional 'lib' prefix
+ soname_spec='$libname`echo $release | $SED -e 's/[[.]]/-/g'`$versuffix$shared_ext'
+ ;;
+ pw32*)
+ # pw32 DLLs use 'pw' prefix rather than 'lib'
+ library_names_spec='`echo $libname | sed -e 's/^lib/pw/'``echo $release | $SED -e 's/[[.]]/-/g'`$versuffix$shared_ext'
+ ;;
+ esac
+ dynamic_linker='Win32 ld.exe'
+ ;;
+
+ *,cl*)
+ # Native MSVC
+ libname_spec='$name'
+ soname_spec='$libname`echo $release | $SED -e 's/[[.]]/-/g'`$versuffix$shared_ext'
+ library_names_spec='$libname.dll.lib'
+
+ case $build_os in
+ mingw*)
+ sys_lib_search_path_spec=
+ lt_save_ifs=$IFS
+ IFS=';'
+ for lt_path in $LIB
+ do
+ IFS=$lt_save_ifs
+ # Let DOS variable expansion print the short 8.3 style file name.
+ lt_path=`cd "$lt_path" 2>/dev/null && cmd //C "for %i in (".") do @echo %~si"`
+ sys_lib_search_path_spec="$sys_lib_search_path_spec $lt_path"
+ done
+ IFS=$lt_save_ifs
+ # Convert to MSYS style.
+ sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | sed -e 's|\\\\|/|g' -e 's| \\([[a-zA-Z]]\\):| /\\1|g' -e 's|^ ||'`
+ ;;
+ cygwin*)
+ # Convert to unix form, then to dos form, then back to unix form
+ # but this time dos style (no spaces!) so that the unix form looks
+ # like /cygdrive/c/PROGRA~1:/cygdr...
+ sys_lib_search_path_spec=`cygpath --path --unix "$LIB"`
+ sys_lib_search_path_spec=`cygpath --path --dos "$sys_lib_search_path_spec" 2>/dev/null`
+ sys_lib_search_path_spec=`cygpath --path --unix "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"`
+ ;;
+ *)
+ sys_lib_search_path_spec=$LIB
+ if $ECHO "$sys_lib_search_path_spec" | [$GREP ';[c-zC-Z]:/' >/dev/null]; then
+ # It is most probably a Windows format PATH.
+ sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'`
+ else
+ sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"`
+ fi
+ # FIXME: find the short name or the path components, as spaces are
+ # common. (e.g. "Program Files" -> "PROGRA~1")
+ ;;
+ esac
+
+ # DLL is installed to $(libdir)/../bin by postinstall_cmds
+ postinstall_cmds='base_file=`basename \$file`~
+ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\$base_file'\''i; echo \$dlname'\''`~
+ dldir=$destdir/`dirname \$dlpath`~
+ test -d \$dldir || mkdir -p \$dldir~
+ $install_prog $dir/$dlname \$dldir/$dlname'
+ postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~
+ dlpath=$dir/\$dldll~
+ $RM \$dlpath'
+ shlibpath_overrides_runpath=yes
+ dynamic_linker='Win32 link.exe'
+ ;;
+
+ *)
+ # Assume MSVC wrapper
+ library_names_spec='$libname`echo $release | $SED -e 's/[[.]]/-/g'`$versuffix$shared_ext $libname.lib'
+ dynamic_linker='Win32 ld.exe'
+ ;;
+ esac
+ # FIXME: first we should search . and the directory the executable is in
+ shlibpath_var=PATH
+ ;;
+
+darwin* | rhapsody*)
+ dynamic_linker="$host_os dyld"
+ version_type=darwin
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='$libname$release$major$shared_ext $libname$shared_ext'
+ soname_spec='$libname$release$major$shared_ext'
+ shlibpath_overrides_runpath=yes
+ shlibpath_var=DYLD_LIBRARY_PATH
+ shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`'
+m4_if([$1], [],[
+ sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/local/lib"])
+ sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib'
+ ;;
+
+dgux*)
+ version_type=linux # correct to gnu/linux during the next big refactor
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ soname_spec='$libname$release$shared_ext$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ ;;
+
+freebsd* | dragonfly*)
+ # DragonFly does not have aout. When/if they implement a new
+ # versioning mechanism, adjust this.
+ if test -x /usr/bin/objformat; then
+ objformat=`/usr/bin/objformat`
+ else
+ case $host_os in
+ freebsd[[23]].*) objformat=aout ;;
+ *) objformat=elf ;;
+ esac
+ fi
+ version_type=freebsd-$objformat
+ case $version_type in
+ freebsd-elf*)
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ soname_spec='$libname$release$shared_ext$major'
+ need_version=no
+ need_lib_prefix=no
+ ;;
+ freebsd-*)
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix'
+ need_version=yes
+ ;;
+ esac
+ shlibpath_var=LD_LIBRARY_PATH
+ case $host_os in
+ freebsd2.*)
+ shlibpath_overrides_runpath=yes
+ ;;
+ freebsd3.[[01]]* | freebsdelf3.[[01]]*)
+ shlibpath_overrides_runpath=yes
+ hardcode_into_libs=yes
+ ;;
+ freebsd3.[[2-9]]* | freebsdelf3.[[2-9]]* | \
+ freebsd4.[[0-5]] | freebsdelf4.[[0-5]] | freebsd4.1.1 | freebsdelf4.1.1)
+ shlibpath_overrides_runpath=no
+ hardcode_into_libs=yes
+ ;;
+ *) # from 4.6 on, and DragonFly
+ shlibpath_overrides_runpath=yes
+ hardcode_into_libs=yes
+ ;;
+ esac
+ ;;
+
+haiku*)
+ version_type=linux # correct to gnu/linux during the next big refactor
+ need_lib_prefix=no
+ need_version=no
+ dynamic_linker="$host_os runtime_loader"
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ soname_spec='$libname$release$shared_ext$major'
+ shlibpath_var=LIBRARY_PATH
+ shlibpath_overrides_runpath=no
+ sys_lib_dlsearch_path_spec='/boot/home/config/lib /boot/common/lib /boot/system/lib'
+ hardcode_into_libs=yes
+ ;;
+
+hpux9* | hpux10* | hpux11*)
+ # Give a soname corresponding to the major version so that dld.sl refuses to
+ # link against other versions.
+ version_type=sunos
+ need_lib_prefix=no
+ need_version=no
+ case $host_cpu in
+ ia64*)
+ shrext_cmds='.so'
+ hardcode_into_libs=yes
+ dynamic_linker="$host_os dld.so"
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ soname_spec='$libname$release$shared_ext$major'
+ if test 32 = "$HPUX_IA64_MODE"; then
+ sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib"
+ sys_lib_dlsearch_path_spec=/usr/lib/hpux32
+ else
+ sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64"
+ sys_lib_dlsearch_path_spec=/usr/lib/hpux64
+ fi
+ ;;
+ hppa*64*)
+ shrext_cmds='.sl'
+ hardcode_into_libs=yes
+ dynamic_linker="$host_os dld.sl"
+ shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH
+ shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ soname_spec='$libname$release$shared_ext$major'
+ sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64"
+ sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
+ ;;
+ *)
+ shrext_cmds='.sl'
+ dynamic_linker="$host_os dld.sl"
+ shlibpath_var=SHLIB_PATH
+ shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ soname_spec='$libname$release$shared_ext$major'
+ ;;
+ esac
+ # HP-UX runs *really* slowly unless shared libraries are mode 555, ...
+ postinstall_cmds='chmod 555 $lib'
+ # or fails outright, so override atomically:
+ install_override_mode=555
+ ;;
+
+interix[[3-9]]*)
+ version_type=linux # correct to gnu/linux during the next big refactor
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ soname_spec='$libname$release$shared_ext$major'
+ dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=no
+ hardcode_into_libs=yes
+ ;;
+
+irix5* | irix6* | nonstopux*)
+ case $host_os in
+ nonstopux*) version_type=nonstopux ;;
+ *)
+ if test yes = "$lt_cv_prog_gnu_ld"; then
+ version_type=linux # correct to gnu/linux during the next big refactor
+ else
+ version_type=irix
+ fi ;;
+ esac
+ need_lib_prefix=no
+ need_version=no
+ soname_spec='$libname$release$shared_ext$major'
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$release$shared_ext $libname$shared_ext'
+ case $host_os in
+ irix5* | nonstopux*)
+ libsuff= shlibsuff=
+ ;;
+ *)
+ case $LD in # libtool.m4 will add one of these switches to LD
+ *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ")
+ libsuff= shlibsuff= libmagic=32-bit;;
+ *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ")
+ libsuff=32 shlibsuff=N32 libmagic=N32;;
+ *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ")
+ libsuff=64 shlibsuff=64 libmagic=64-bit;;
+ *) libsuff= shlibsuff= libmagic=never-match;;
+ esac
+ ;;
+ esac
+ shlibpath_var=LD_LIBRARY${shlibsuff}_PATH
+ shlibpath_overrides_runpath=no
+ sys_lib_search_path_spec="/usr/lib$libsuff /lib$libsuff /usr/local/lib$libsuff"
+ sys_lib_dlsearch_path_spec="/usr/lib$libsuff /lib$libsuff"
+ hardcode_into_libs=yes
+ ;;
+
+# No shared lib support for Linux oldld, aout, or coff.
+linux*oldld* | linux*aout* | linux*coff*)
+ dynamic_linker=no
+ ;;
+
+linux*android*)
+ version_type=none # Android doesn't support versioned libraries.
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='$libname$release$shared_ext'
+ soname_spec='$libname$release$shared_ext'
+ finish_cmds=
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+
+ # This implies no fast_install, which is unacceptable.
+ # Some rework will be needed to allow for fast_install
+ # before this can be enabled.
+ hardcode_into_libs=yes
+
+ dynamic_linker='Android linker'
+ # Don't embed -rpath directories since the linker doesn't support them.
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+ ;;
+
+# This must be glibc/ELF.
+linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*)
+ version_type=linux # correct to gnu/linux during the next big refactor
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ soname_spec='$libname$release$shared_ext$major'
+ finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=no
+
+ # Some binutils ld are patched to set DT_RUNPATH
+ AC_CACHE_VAL([lt_cv_shlibpath_overrides_runpath],
+ [lt_cv_shlibpath_overrides_runpath=no
+ save_LDFLAGS=$LDFLAGS
+ save_libdir=$libdir
+ eval "libdir=/foo; wl=\"$_LT_TAGVAR(lt_prog_compiler_wl, $1)\"; \
+ LDFLAGS=\"\$LDFLAGS $_LT_TAGVAR(hardcode_libdir_flag_spec, $1)\""
+ AC_LINK_IFELSE([AC_LANG_PROGRAM([],[])],
+ [AS_IF([ ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null],
+ [lt_cv_shlibpath_overrides_runpath=yes])])
+ LDFLAGS=$save_LDFLAGS
+ libdir=$save_libdir
+ ])
+ shlibpath_overrides_runpath=$lt_cv_shlibpath_overrides_runpath
+
+ # This implies no fast_install, which is unacceptable.
+ # Some rework will be needed to allow for fast_install
+ # before this can be enabled.
+ hardcode_into_libs=yes
+
+ # Ideally, we could use ldconfig to report *all* directores which are
+ # searched for libraries, however this is still not possible. Aside from not
+ # being certain /sbin/ldconfig is available, command
+ # 'ldconfig -N -X -v | grep ^/' on 64bit Fedora does not report /usr/lib64,
+ # even though it is searched at run-time. Try to do the best guess by
+ # appending ld.so.conf contents (and includes) to the search path.
+ if test -f /etc/ld.so.conf; then
+ lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \[$]2)); skip = 1; } { if (!skip) print \[$]0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[ ]*hwcap[ ]/d;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;s/"//g;/^$/d' | tr '\n' ' '`
+ sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra"
+ fi
+
+ # We used to test for /lib/ld.so.1 and disable shared libraries on
+ # powerpc, because MkLinux only supported shared libraries with the
+ # GNU dynamic linker. Since this was broken with cross compilers,
+ # most powerpc-linux boxes support dynamic linking these days and
+ # people can always --disable-shared, the test was removed, and we
+ # assume the GNU/Linux dynamic linker is in use.
+ dynamic_linker='GNU/Linux ld.so'
+ ;;
+
+netbsdelf*-gnu)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=no
+ hardcode_into_libs=yes
+ dynamic_linker='NetBSD ld.elf_so'
+ ;;
+
+netbsd*)
+ version_type=sunos
+ need_lib_prefix=no
+ need_version=no
+ if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix'
+ finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
+ dynamic_linker='NetBSD (a.out) ld.so'
+ else
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ soname_spec='$libname$release$shared_ext$major'
+ dynamic_linker='NetBSD ld.elf_so'
+ fi
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ hardcode_into_libs=yes
+ ;;
+
+newsos6)
+ version_type=linux # correct to gnu/linux during the next big refactor
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ ;;
+
+*nto* | *qnx*)
+ version_type=qnx
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ soname_spec='$libname$release$shared_ext$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=no
+ hardcode_into_libs=yes
+ dynamic_linker='ldqnx.so'
+ ;;
+
+openbsd* | bitrig*)
+ version_type=sunos
+ sys_lib_dlsearch_path_spec=/usr/lib
+ need_lib_prefix=no
+ if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`"; then
+ need_version=no
+ else
+ need_version=yes
+ fi
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix'
+ finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ ;;
+
+os2*)
+ libname_spec='$name'
+ version_type=windows
+ shrext_cmds=.dll
+ need_version=no
+ need_lib_prefix=no
+ # OS/2 can only load a DLL with a base name of 8 characters or less.
+ soname_spec='`test -n "$os2dllname" && libname="$os2dllname";
+ v=$($ECHO $release$versuffix | tr -d .-);
+ n=$($ECHO $libname | cut -b -$((8 - ${#v})) | tr . _);
+ $ECHO $n$v`$shared_ext'
+ library_names_spec='${libname}_dll.$libext'
+ dynamic_linker='OS/2 ld.exe'
+ shlibpath_var=BEGINLIBPATH
+ sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib"
+ sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
+ postinstall_cmds='base_file=`basename \$file`~
+ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\$base_file'\''i; $ECHO \$dlname'\''`~
+ dldir=$destdir/`dirname \$dlpath`~
+ test -d \$dldir || mkdir -p \$dldir~
+ $install_prog $dir/$dlname \$dldir/$dlname~
+ chmod a+x \$dldir/$dlname~
+ if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then
+ eval '\''$striplib \$dldir/$dlname'\'' || exit \$?;
+ fi'
+ postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; $ECHO \$dlname'\''`~
+ dlpath=$dir/\$dldll~
+ $RM \$dlpath'
+ ;;
+
+osf3* | osf4* | osf5*)
+ version_type=osf
+ need_lib_prefix=no
+ need_version=no
+ soname_spec='$libname$release$shared_ext$major'
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ shlibpath_var=LD_LIBRARY_PATH
+ sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib"
+ sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
+ ;;
+
+rdos*)
+ dynamic_linker=no
+ ;;
+
+solaris*)
+ version_type=linux # correct to gnu/linux during the next big refactor
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ soname_spec='$libname$release$shared_ext$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ hardcode_into_libs=yes
+ # ldd complains unless libraries are executable
+ postinstall_cmds='chmod +x $lib'
+ ;;
+
+sunos4*)
+ version_type=sunos
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix'
+ finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ if test yes = "$with_gnu_ld"; then
+ need_lib_prefix=no
+ fi
+ need_version=yes
+ ;;
+
+sysv4 | sysv4.3*)
+ version_type=linux # correct to gnu/linux during the next big refactor
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ soname_spec='$libname$release$shared_ext$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ case $host_vendor in
+ sni)
+ shlibpath_overrides_runpath=no
+ need_lib_prefix=no
+ runpath_var=LD_RUN_PATH
+ ;;
+ siemens)
+ need_lib_prefix=no
+ ;;
+ motorola)
+ need_lib_prefix=no
+ need_version=no
+ shlibpath_overrides_runpath=no
+ sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib'
+ ;;
+ esac
+ ;;
+
+sysv4*MP*)
+ if test -d /usr/nec; then
+ version_type=linux # correct to gnu/linux during the next big refactor
+ library_names_spec='$libname$shared_ext.$versuffix $libname$shared_ext.$major $libname$shared_ext'
+ soname_spec='$libname$shared_ext.$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ fi
+ ;;
+
+sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*)
+ version_type=sco
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext $libname$shared_ext'
+ soname_spec='$libname$release$shared_ext$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ hardcode_into_libs=yes
+ if test yes = "$with_gnu_ld"; then
+ sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib'
+ else
+ sys_lib_search_path_spec='/usr/ccs/lib /usr/lib'
+ case $host_os in
+ sco3.2v5*)
+ sys_lib_search_path_spec="$sys_lib_search_path_spec /lib"
+ ;;
+ esac
+ fi
+ sys_lib_dlsearch_path_spec='/usr/lib'
+ ;;
+
+tpf*)
+ # TPF is a cross-target only. Preferred cross-host = GNU/Linux.
+ version_type=linux # correct to gnu/linux during the next big refactor
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=no
+ hardcode_into_libs=yes
+ ;;
+
+uts4*)
+ version_type=linux # correct to gnu/linux during the next big refactor
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ soname_spec='$libname$release$shared_ext$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ ;;
+
+*)
+ dynamic_linker=no
+ ;;
+esac
+AC_MSG_RESULT([$dynamic_linker])
+test no = "$dynamic_linker" && can_build_shared=no
+
+variables_saved_for_relink="PATH $shlibpath_var $runpath_var"
+if test yes = "$GCC"; then
+ variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH"
+fi
+
+if test set = "${lt_cv_sys_lib_search_path_spec+set}"; then
+ sys_lib_search_path_spec=$lt_cv_sys_lib_search_path_spec
+fi
+
+if test set = "${lt_cv_sys_lib_dlsearch_path_spec+set}"; then
+ sys_lib_dlsearch_path_spec=$lt_cv_sys_lib_dlsearch_path_spec
+fi
+
+# remember unaugmented sys_lib_dlsearch_path content for libtool script decls...
+configure_time_dlsearch_path=$sys_lib_dlsearch_path_spec
+
+# ... but it needs LT_SYS_LIBRARY_PATH munging for other configure-time code
+func_munge_path_list sys_lib_dlsearch_path_spec "$LT_SYS_LIBRARY_PATH"
+
+# to be used as default LT_SYS_LIBRARY_PATH value in generated libtool
+configure_time_lt_sys_library_path=$LT_SYS_LIBRARY_PATH
+
+_LT_DECL([], [variables_saved_for_relink], [1],
+ [Variables whose values should be saved in libtool wrapper scripts and
+ restored at link time])
+_LT_DECL([], [need_lib_prefix], [0],
+ [Do we need the "lib" prefix for modules?])
+_LT_DECL([], [need_version], [0], [Do we need a version for libraries?])
+_LT_DECL([], [version_type], [0], [Library versioning type])
+_LT_DECL([], [runpath_var], [0], [Shared library runtime path variable])
+_LT_DECL([], [shlibpath_var], [0],[Shared library path variable])
+_LT_DECL([], [shlibpath_overrides_runpath], [0],
+ [Is shlibpath searched before the hard-coded library search path?])
+_LT_DECL([], [libname_spec], [1], [Format of library name prefix])
+_LT_DECL([], [library_names_spec], [1],
+ [[List of archive names. First name is the real one, the rest are links.
+ The last name is the one that the linker finds with -lNAME]])
+_LT_DECL([], [soname_spec], [1],
+ [[The coded name of the library, if different from the real name]])
+_LT_DECL([], [install_override_mode], [1],
+ [Permission mode override for installation of shared libraries])
+_LT_DECL([], [postinstall_cmds], [2],
+ [Command to use after installation of a shared archive])
+_LT_DECL([], [postuninstall_cmds], [2],
+ [Command to use after uninstallation of a shared archive])
+_LT_DECL([], [finish_cmds], [2],
+ [Commands used to finish a libtool library installation in a directory])
+_LT_DECL([], [finish_eval], [1],
+ [[As "finish_cmds", except a single script fragment to be evaled but
+ not shown]])
+_LT_DECL([], [hardcode_into_libs], [0],
+ [Whether we should hardcode library paths into libraries])
+_LT_DECL([], [sys_lib_search_path_spec], [2],
+ [Compile-time system search path for libraries])
+_LT_DECL([sys_lib_dlsearch_path_spec], [configure_time_dlsearch_path], [2],
+ [Detected run-time system search path for libraries])
+_LT_DECL([], [configure_time_lt_sys_library_path], [2],
+ [Explicit LT_SYS_LIBRARY_PATH set during ./configure time])
+])# _LT_SYS_DYNAMIC_LINKER
+
+
+# _LT_PATH_TOOL_PREFIX(TOOL)
+# --------------------------
+# find a file program that can recognize shared library
+AC_DEFUN([_LT_PATH_TOOL_PREFIX],
+[m4_require([_LT_DECL_EGREP])dnl
+AC_MSG_CHECKING([for $1])
+AC_CACHE_VAL(lt_cv_path_MAGIC_CMD,
+[case $MAGIC_CMD in
+[[\\/*] | ?:[\\/]*])
+ lt_cv_path_MAGIC_CMD=$MAGIC_CMD # Let the user override the test with a path.
+ ;;
+*)
+ lt_save_MAGIC_CMD=$MAGIC_CMD
+ lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR
+dnl $ac_dummy forces splitting on constant user-supplied paths.
+dnl POSIX.2 word splitting is done only on the output of word expansions,
+dnl not every word. This closes a longstanding sh security hole.
+ ac_dummy="m4_if([$2], , $PATH, [$2])"
+ for ac_dir in $ac_dummy; do
+ IFS=$lt_save_ifs
+ test -z "$ac_dir" && ac_dir=.
+ if test -f "$ac_dir/$1"; then
+ lt_cv_path_MAGIC_CMD=$ac_dir/"$1"
+ if test -n "$file_magic_test_file"; then
+ case $deplibs_check_method in
+ "file_magic "*)
+ file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"`
+ MAGIC_CMD=$lt_cv_path_MAGIC_CMD
+ if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null |
+ $EGREP "$file_magic_regex" > /dev/null; then
+ :
+ else
+ cat <<_LT_EOF 1>&2
+
+*** Warning: the command libtool uses to detect shared libraries,
+*** $file_magic_cmd, produces output that libtool cannot recognize.
+*** The result is that libtool may fail to recognize shared libraries
+*** as such. This will affect the creation of libtool libraries that
+*** depend on shared libraries, but programs linked with such libtool
+*** libraries will work regardless of this problem. Nevertheless, you
+*** may want to report the problem to your system manager and/or to
+*** bug-libtool@gnu.org
+
+_LT_EOF
+ fi ;;
+ esac
+ fi
+ break
+ fi
+ done
+ IFS=$lt_save_ifs
+ MAGIC_CMD=$lt_save_MAGIC_CMD
+ ;;
+esac])
+MAGIC_CMD=$lt_cv_path_MAGIC_CMD
+if test -n "$MAGIC_CMD"; then
+ AC_MSG_RESULT($MAGIC_CMD)
+else
+ AC_MSG_RESULT(no)
+fi
+_LT_DECL([], [MAGIC_CMD], [0],
+ [Used to examine libraries when file_magic_cmd begins with "file"])dnl
+])# _LT_PATH_TOOL_PREFIX
+
+# Old name:
+AU_ALIAS([AC_PATH_TOOL_PREFIX], [_LT_PATH_TOOL_PREFIX])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_PATH_TOOL_PREFIX], [])
+
+
+# _LT_PATH_MAGIC
+# --------------
+# find a file program that can recognize a shared library
+m4_defun([_LT_PATH_MAGIC],
+[_LT_PATH_TOOL_PREFIX(${ac_tool_prefix}file, /usr/bin$PATH_SEPARATOR$PATH)
+if test -z "$lt_cv_path_MAGIC_CMD"; then
+ if test -n "$ac_tool_prefix"; then
+ _LT_PATH_TOOL_PREFIX(file, /usr/bin$PATH_SEPARATOR$PATH)
+ else
+ MAGIC_CMD=:
+ fi
+fi
+])# _LT_PATH_MAGIC
+
+
+# LT_PATH_LD
+# ----------
+# find the pathname to the GNU or non-GNU linker
+AC_DEFUN([LT_PATH_LD],
+[AC_REQUIRE([AC_PROG_CC])dnl
+AC_REQUIRE([AC_CANONICAL_HOST])dnl
+AC_REQUIRE([AC_CANONICAL_BUILD])dnl
+m4_require([_LT_DECL_SED])dnl
+m4_require([_LT_DECL_EGREP])dnl
+m4_require([_LT_PROG_ECHO_BACKSLASH])dnl
+
+AC_ARG_WITH([gnu-ld],
+ [AS_HELP_STRING([--with-gnu-ld],
+ [assume the C compiler uses GNU ld @<:@default=no@:>@])],
+ [test no = "$withval" || with_gnu_ld=yes],
+ [with_gnu_ld=no])dnl
+
+ac_prog=ld
+if test yes = "$GCC"; then
+ # Check if gcc -print-prog-name=ld gives a path.
+ AC_MSG_CHECKING([for ld used by $CC])
+ case $host in
+ *-*-mingw*)
+ # gcc leaves a trailing carriage return, which upsets mingw
+ ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;;
+ *)
+ ac_prog=`($CC -print-prog-name=ld) 2>&5` ;;
+ esac
+ case $ac_prog in
+ # Accept absolute paths.
+ [[\\/]]* | ?:[[\\/]]*)
+ re_direlt='/[[^/]][[^/]]*/\.\./'
+ # Canonicalize the pathname of ld
+ ac_prog=`$ECHO "$ac_prog"| $SED 's%\\\\%/%g'`
+ while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do
+ ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"`
+ done
+ test -z "$LD" && LD=$ac_prog
+ ;;
+ "")
+ # If it fails, then pretend we aren't using GCC.
+ ac_prog=ld
+ ;;
+ *)
+ # If it is relative, then search for the first ld in PATH.
+ with_gnu_ld=unknown
+ ;;
+ esac
+elif test yes = "$with_gnu_ld"; then
+ AC_MSG_CHECKING([for GNU ld])
+else
+ AC_MSG_CHECKING([for non-GNU ld])
+fi
+AC_CACHE_VAL(lt_cv_path_LD,
+[if test -z "$LD"; then
+ lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR
+ for ac_dir in $PATH; do
+ IFS=$lt_save_ifs
+ test -z "$ac_dir" && ac_dir=.
+ if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then
+ lt_cv_path_LD=$ac_dir/$ac_prog
+ # Check to see if the program is GNU ld. I'd rather use --version,
+ # but apparently some variants of GNU ld only accept -v.
+ # Break only if it was the GNU/non-GNU ld that we prefer.
+ case `"$lt_cv_path_LD" -v 2>&1 </dev/null` in
+ *GNU* | *'with BFD'*)
+ test no != "$with_gnu_ld" && break
+ ;;
+ *)
+ test yes != "$with_gnu_ld" && break
+ ;;
+ esac
+ fi
+ done
+ IFS=$lt_save_ifs
+else
+ lt_cv_path_LD=$LD # Let the user override the test with a path.
+fi])
+LD=$lt_cv_path_LD
+if test -n "$LD"; then
+ AC_MSG_RESULT($LD)
+else
+ AC_MSG_RESULT(no)
+fi
+test -z "$LD" && AC_MSG_ERROR([no acceptable ld found in \$PATH])
+_LT_PATH_LD_GNU
+AC_SUBST([LD])
+
+_LT_TAGDECL([], [LD], [1], [The linker used to build libraries])
+])# LT_PATH_LD
+
+# Old names:
+AU_ALIAS([AM_PROG_LD], [LT_PATH_LD])
+AU_ALIAS([AC_PROG_LD], [LT_PATH_LD])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AM_PROG_LD], [])
+dnl AC_DEFUN([AC_PROG_LD], [])
+
+
+# _LT_PATH_LD_GNU
+#- --------------
+m4_defun([_LT_PATH_LD_GNU],
+[AC_CACHE_CHECK([if the linker ($LD) is GNU ld], lt_cv_prog_gnu_ld,
+[# I'd rather use --version here, but apparently some GNU lds only accept -v.
+case `$LD -v 2>&1 </dev/null` in
+*GNU* | *'with BFD'*)
+ lt_cv_prog_gnu_ld=yes
+ ;;
+*)
+ lt_cv_prog_gnu_ld=no
+ ;;
+esac])
+with_gnu_ld=$lt_cv_prog_gnu_ld
+])# _LT_PATH_LD_GNU
+
+
+# _LT_CMD_RELOAD
+# --------------
+# find reload flag for linker
+# -- PORTME Some linkers may need a different reload flag.
+m4_defun([_LT_CMD_RELOAD],
+[AC_CACHE_CHECK([for $LD option to reload object files],
+ lt_cv_ld_reload_flag,
+ [lt_cv_ld_reload_flag='-r'])
+reload_flag=$lt_cv_ld_reload_flag
+case $reload_flag in
+"" | " "*) ;;
+*) reload_flag=" $reload_flag" ;;
+esac
+reload_cmds='$LD$reload_flag -o $output$reload_objs'
+case $host_os in
+ cygwin* | mingw* | pw32* | cegcc*)
+ if test yes != "$GCC"; then
+ reload_cmds=false
+ fi
+ ;;
+ darwin*)
+ if test yes = "$GCC"; then
+ reload_cmds='$LTCC $LTCFLAGS -nostdlib $wl-r -o $output$reload_objs'
+ else
+ reload_cmds='$LD$reload_flag -o $output$reload_objs'
+ fi
+ ;;
+esac
+_LT_TAGDECL([], [reload_flag], [1], [How to create reloadable object files])dnl
+_LT_TAGDECL([], [reload_cmds], [2])dnl
+])# _LT_CMD_RELOAD
+
+
+# _LT_PATH_DD
+# -----------
+# find a working dd
+m4_defun([_LT_PATH_DD],
+[AC_CACHE_CHECK([for a working dd], [ac_cv_path_lt_DD],
+[printf 0123456789abcdef0123456789abcdef >conftest.i
+cat conftest.i conftest.i >conftest2.i
+: ${lt_DD:=$DD}
+AC_PATH_PROGS_FEATURE_CHECK([lt_DD], [dd],
+[if "$ac_path_lt_DD" bs=32 count=1 <conftest2.i >conftest.out 2>/dev/null; then
+ cmp -s conftest.i conftest.out \
+ && ac_cv_path_lt_DD="$ac_path_lt_DD" ac_path_lt_DD_found=:
+fi])
+rm -f conftest.i conftest2.i conftest.out])
+])# _LT_PATH_DD
+
+
+# _LT_CMD_TRUNCATE
+# ----------------
+# find command to truncate a binary pipe
+m4_defun([_LT_CMD_TRUNCATE],
+[m4_require([_LT_PATH_DD])
+AC_CACHE_CHECK([how to truncate binary pipes], [lt_cv_truncate_bin],
+[printf 0123456789abcdef0123456789abcdef >conftest.i
+cat conftest.i conftest.i >conftest2.i
+lt_cv_truncate_bin=
+if "$ac_cv_path_lt_DD" bs=32 count=1 <conftest2.i >conftest.out 2>/dev/null; then
+ cmp -s conftest.i conftest.out \
+ && lt_cv_truncate_bin="$ac_cv_path_lt_DD bs=4096 count=1"
+fi
+rm -f conftest.i conftest2.i conftest.out
+test -z "$lt_cv_truncate_bin" && lt_cv_truncate_bin="$SED -e 4q"])
+_LT_DECL([lt_truncate_bin], [lt_cv_truncate_bin], [1],
+ [Command to truncate a binary pipe])
+])# _LT_CMD_TRUNCATE
+
+
+# _LT_CHECK_MAGIC_METHOD
+# ----------------------
+# how to check for library dependencies
+# -- PORTME fill in with the dynamic library characteristics
+m4_defun([_LT_CHECK_MAGIC_METHOD],
+[m4_require([_LT_DECL_EGREP])
+m4_require([_LT_DECL_OBJDUMP])
+AC_CACHE_CHECK([how to recognize dependent libraries],
+lt_cv_deplibs_check_method,
+[lt_cv_file_magic_cmd='$MAGIC_CMD'
+lt_cv_file_magic_test_file=
+lt_cv_deplibs_check_method='unknown'
+# Need to set the preceding variable on all platforms that support
+# interlibrary dependencies.
+# 'none' -- dependencies not supported.
+# 'unknown' -- same as none, but documents that we really don't know.
+# 'pass_all' -- all dependencies passed with no checks.
+# 'test_compile' -- check by making test program.
+# 'file_magic [[regex]]' -- check by looking for files in library path
+# that responds to the $file_magic_cmd with a given extended regex.
+# If you have 'file' or equivalent on your system and you're not sure
+# whether 'pass_all' will *always* work, you probably want this one.
+
+case $host_os in
+aix[[4-9]]*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+beos*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+bsdi[[45]]*)
+ lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (shared object|dynamic lib)'
+ lt_cv_file_magic_cmd='/usr/bin/file -L'
+ lt_cv_file_magic_test_file=/shlib/libc.so
+ ;;
+
+cygwin*)
+ # func_win32_libid is a shell function defined in ltmain.sh
+ lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL'
+ lt_cv_file_magic_cmd='func_win32_libid'
+ ;;
+
+mingw* | pw32*)
+ # Base MSYS/MinGW do not provide the 'file' command needed by
+ # func_win32_libid shell function, so use a weaker test based on 'objdump',
+ # unless we find 'file', for example because we are cross-compiling.
+ if ( file / ) >/dev/null 2>&1; then
+ lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL'
+ lt_cv_file_magic_cmd='func_win32_libid'
+ else
+ # Keep this pattern in sync with the one in func_win32_libid.
+ lt_cv_deplibs_check_method='file_magic file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64)'
+ lt_cv_file_magic_cmd='$OBJDUMP -f'
+ fi
+ ;;
+
+cegcc*)
+ # use the weaker test based on 'objdump'. See mingw*.
+ lt_cv_deplibs_check_method='file_magic file format pe-arm-.*little(.*architecture: arm)?'
+ lt_cv_file_magic_cmd='$OBJDUMP -f'
+ ;;
+
+darwin* | rhapsody*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+freebsd* | dragonfly*)
+ if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then
+ case $host_cpu in
+ i*86 )
+ # Not sure whether the presence of OpenBSD here was a mistake.
+ # Let's accept both of them until this is cleared up.
+ lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD|DragonFly)/i[[3-9]]86 (compact )?demand paged shared library'
+ lt_cv_file_magic_cmd=/usr/bin/file
+ lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*`
+ ;;
+ esac
+ else
+ lt_cv_deplibs_check_method=pass_all
+ fi
+ ;;
+
+haiku*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+hpux10.20* | hpux11*)
+ lt_cv_file_magic_cmd=/usr/bin/file
+ case $host_cpu in
+ ia64*)
+ lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|ELF-[[0-9]][[0-9]]) shared object file - IA64'
+ lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so
+ ;;
+ hppa*64*)
+ [lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF[ -][0-9][0-9])(-bit)?( [LM]SB)? shared object( file)?[, -]* PA-RISC [0-9]\.[0-9]']
+ lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl
+ ;;
+ *)
+ lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|PA-RISC[[0-9]]\.[[0-9]]) shared library'
+ lt_cv_file_magic_test_file=/usr/lib/libc.sl
+ ;;
+ esac
+ ;;
+
+interix[[3-9]]*)
+ # PIC code is broken on Interix 3.x, that's why |\.a not |_pic\.a here
+ lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|\.a)$'
+ ;;
+
+irix5* | irix6* | nonstopux*)
+ case $LD in
+ *-32|*"-32 ") libmagic=32-bit;;
+ *-n32|*"-n32 ") libmagic=N32;;
+ *-64|*"-64 ") libmagic=64-bit;;
+ *) libmagic=never-match;;
+ esac
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+# This must be glibc/ELF.
+linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+netbsd* | netbsdelf*-gnu)
+ if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then
+ lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$'
+ else
+ lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|_pic\.a)$'
+ fi
+ ;;
+
+newos6*)
+ lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (executable|dynamic lib)'
+ lt_cv_file_magic_cmd=/usr/bin/file
+ lt_cv_file_magic_test_file=/usr/lib/libnls.so
+ ;;
+
+*nto* | *qnx*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+openbsd* | bitrig*)
+ if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`"; then
+ lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|\.so|_pic\.a)$'
+ else
+ lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$'
+ fi
+ ;;
+
+osf3* | osf4* | osf5*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+rdos*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+solaris*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+sysv4 | sysv4.3*)
+ case $host_vendor in
+ motorola)
+ lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (shared object|dynamic lib) M[[0-9]][[0-9]]* Version [[0-9]]'
+ lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*`
+ ;;
+ ncr)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+ sequent)
+ lt_cv_file_magic_cmd='/bin/file'
+ lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB (shared object|dynamic lib )'
+ ;;
+ sni)
+ lt_cv_file_magic_cmd='/bin/file'
+ lt_cv_deplibs_check_method="file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB dynamic lib"
+ lt_cv_file_magic_test_file=/lib/libc.so
+ ;;
+ siemens)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+ pc)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+ esac
+ ;;
+
+tpf*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+os2*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+esac
+])
+
+file_magic_glob=
+want_nocaseglob=no
+if test "$build" = "$host"; then
+ case $host_os in
+ mingw* | pw32*)
+ if ( shopt | grep nocaseglob ) >/dev/null 2>&1; then
+ want_nocaseglob=yes
+ else
+ file_magic_glob=`echo aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ | $SED -e "s/\(..\)/s\/[[\1]]\/[[\1]]\/g;/g"`
+ fi
+ ;;
+ esac
+fi
+
+file_magic_cmd=$lt_cv_file_magic_cmd
+deplibs_check_method=$lt_cv_deplibs_check_method
+test -z "$deplibs_check_method" && deplibs_check_method=unknown
+
+_LT_DECL([], [deplibs_check_method], [1],
+ [Method to check whether dependent libraries are shared objects])
+_LT_DECL([], [file_magic_cmd], [1],
+ [Command to use when deplibs_check_method = "file_magic"])
+_LT_DECL([], [file_magic_glob], [1],
+ [How to find potential files when deplibs_check_method = "file_magic"])
+_LT_DECL([], [want_nocaseglob], [1],
+ [Find potential files using nocaseglob when deplibs_check_method = "file_magic"])
+])# _LT_CHECK_MAGIC_METHOD
+
+
+# LT_PATH_NM
+# ----------
+# find the pathname to a BSD- or MS-compatible name lister
+AC_DEFUN([LT_PATH_NM],
+[AC_REQUIRE([AC_PROG_CC])dnl
+AC_CACHE_CHECK([for BSD- or MS-compatible name lister (nm)], lt_cv_path_NM,
+[if test -n "$NM"; then
+ # Let the user override the test.
+ lt_cv_path_NM=$NM
+else
+ lt_nm_to_check=${ac_tool_prefix}nm
+ if test -n "$ac_tool_prefix" && test "$build" = "$host"; then
+ lt_nm_to_check="$lt_nm_to_check nm"
+ fi
+ for lt_tmp_nm in $lt_nm_to_check; do
+ lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR
+ for ac_dir in $PATH /usr/ccs/bin/elf /usr/ccs/bin /usr/ucb /bin; do
+ IFS=$lt_save_ifs
+ test -z "$ac_dir" && ac_dir=.
+ tmp_nm=$ac_dir/$lt_tmp_nm
+ if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext"; then
+ # Check to see if the nm accepts a BSD-compat flag.
+ # Adding the 'sed 1q' prevents false positives on HP-UX, which says:
+ # nm: unknown option "B" ignored
+ # Tru64's nm complains that /dev/null is an invalid object file
+ # MSYS converts /dev/null to NUL, MinGW nm treats NUL as empty
+ case $build_os in
+ mingw*) lt_bad_file=conftest.nm/nofile ;;
+ *) lt_bad_file=/dev/null ;;
+ esac
+ case `"$tmp_nm" -B $lt_bad_file 2>&1 | sed '1q'` in
+ *$lt_bad_file* | *'Invalid file or object type'*)
+ lt_cv_path_NM="$tmp_nm -B"
+ break 2
+ ;;
+ *)
+ case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in
+ */dev/null*)
+ lt_cv_path_NM="$tmp_nm -p"
+ break 2
+ ;;
+ *)
+ lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but
+ continue # so that we can try to find one that supports BSD flags
+ ;;
+ esac
+ ;;
+ esac
+ fi
+ done
+ IFS=$lt_save_ifs
+ done
+ : ${lt_cv_path_NM=no}
+fi])
+if test no != "$lt_cv_path_NM"; then
+ NM=$lt_cv_path_NM
+else
+ # Didn't find any BSD compatible name lister, look for dumpbin.
+ if test -n "$DUMPBIN"; then :
+ # Let the user override the test.
+ else
+ AC_CHECK_TOOLS(DUMPBIN, [dumpbin "link -dump"], :)
+ case `$DUMPBIN -symbols -headers /dev/null 2>&1 | sed '1q'` in
+ *COFF*)
+ DUMPBIN="$DUMPBIN -symbols -headers"
+ ;;
+ *)
+ DUMPBIN=:
+ ;;
+ esac
+ fi
+ AC_SUBST([DUMPBIN])
+ if test : != "$DUMPBIN"; then
+ NM=$DUMPBIN
+ fi
+fi
+test -z "$NM" && NM=nm
+AC_SUBST([NM])
+_LT_DECL([], [NM], [1], [A BSD- or MS-compatible name lister])dnl
+
+AC_CACHE_CHECK([the name lister ($NM) interface], [lt_cv_nm_interface],
+ [lt_cv_nm_interface="BSD nm"
+ echo "int some_variable = 0;" > conftest.$ac_ext
+ (eval echo "\"\$as_me:$LINENO: $ac_compile\"" >&AS_MESSAGE_LOG_FD)
+ (eval "$ac_compile" 2>conftest.err)
+ cat conftest.err >&AS_MESSAGE_LOG_FD
+ (eval echo "\"\$as_me:$LINENO: $NM \\\"conftest.$ac_objext\\\"\"" >&AS_MESSAGE_LOG_FD)
+ (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out)
+ cat conftest.err >&AS_MESSAGE_LOG_FD
+ (eval echo "\"\$as_me:$LINENO: output\"" >&AS_MESSAGE_LOG_FD)
+ cat conftest.out >&AS_MESSAGE_LOG_FD
+ if $GREP 'External.*some_variable' conftest.out > /dev/null; then
+ lt_cv_nm_interface="MS dumpbin"
+ fi
+ rm -f conftest*])
+])# LT_PATH_NM
+
+# Old names:
+AU_ALIAS([AM_PROG_NM], [LT_PATH_NM])
+AU_ALIAS([AC_PROG_NM], [LT_PATH_NM])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AM_PROG_NM], [])
+dnl AC_DEFUN([AC_PROG_NM], [])
+
+# _LT_CHECK_SHAREDLIB_FROM_LINKLIB
+# --------------------------------
+# how to determine the name of the shared library
+# associated with a specific link library.
+# -- PORTME fill in with the dynamic library characteristics
+m4_defun([_LT_CHECK_SHAREDLIB_FROM_LINKLIB],
+[m4_require([_LT_DECL_EGREP])
+m4_require([_LT_DECL_OBJDUMP])
+m4_require([_LT_DECL_DLLTOOL])
+AC_CACHE_CHECK([how to associate runtime and link libraries],
+lt_cv_sharedlib_from_linklib_cmd,
+[lt_cv_sharedlib_from_linklib_cmd='unknown'
+
+case $host_os in
+cygwin* | mingw* | pw32* | cegcc*)
+ # two different shell functions defined in ltmain.sh;
+ # decide which one to use based on capabilities of $DLLTOOL
+ case `$DLLTOOL --help 2>&1` in
+ *--identify-strict*)
+ lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib
+ ;;
+ *)
+ lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib_fallback
+ ;;
+ esac
+ ;;
+*)
+ # fallback: assume linklib IS sharedlib
+ lt_cv_sharedlib_from_linklib_cmd=$ECHO
+ ;;
+esac
+])
+sharedlib_from_linklib_cmd=$lt_cv_sharedlib_from_linklib_cmd
+test -z "$sharedlib_from_linklib_cmd" && sharedlib_from_linklib_cmd=$ECHO
+
+_LT_DECL([], [sharedlib_from_linklib_cmd], [1],
+ [Command to associate shared and link libraries])
+])# _LT_CHECK_SHAREDLIB_FROM_LINKLIB
+
+
+# _LT_PATH_MANIFEST_TOOL
+# ----------------------
+# locate the manifest tool
+m4_defun([_LT_PATH_MANIFEST_TOOL],
+[AC_CHECK_TOOL(MANIFEST_TOOL, mt, :)
+test -z "$MANIFEST_TOOL" && MANIFEST_TOOL=mt
+AC_CACHE_CHECK([if $MANIFEST_TOOL is a manifest tool], [lt_cv_path_mainfest_tool],
+ [lt_cv_path_mainfest_tool=no
+ echo "$as_me:$LINENO: $MANIFEST_TOOL '-?'" >&AS_MESSAGE_LOG_FD
+ $MANIFEST_TOOL '-?' 2>conftest.err > conftest.out
+ cat conftest.err >&AS_MESSAGE_LOG_FD
+ if $GREP 'Manifest Tool' conftest.out > /dev/null; then
+ lt_cv_path_mainfest_tool=yes
+ fi
+ rm -f conftest*])
+if test yes != "$lt_cv_path_mainfest_tool"; then
+ MANIFEST_TOOL=:
+fi
+_LT_DECL([], [MANIFEST_TOOL], [1], [Manifest tool])dnl
+])# _LT_PATH_MANIFEST_TOOL
+
+
+# _LT_DLL_DEF_P([FILE])
+# ---------------------
+# True iff FILE is a Windows DLL '.def' file.
+# Keep in sync with func_dll_def_p in the libtool script
+AC_DEFUN([_LT_DLL_DEF_P],
+[dnl
+ test DEF = "`$SED -n dnl
+ -e '\''s/^[[ ]]*//'\'' dnl Strip leading whitespace
+ -e '\''/^\(;.*\)*$/d'\'' dnl Delete empty lines and comments
+ -e '\''s/^\(EXPORTS\|LIBRARY\)\([[ ]].*\)*$/DEF/p'\'' dnl
+ -e q dnl Only consider the first "real" line
+ $1`" dnl
+])# _LT_DLL_DEF_P
+
+
+# LT_LIB_M
+# --------
+# check for math library
+AC_DEFUN([LT_LIB_M],
+[AC_REQUIRE([AC_CANONICAL_HOST])dnl
+LIBM=
+case $host in
+*-*-beos* | *-*-cegcc* | *-*-cygwin* | *-*-haiku* | *-*-pw32* | *-*-darwin*)
+ # These system don't have libm, or don't need it
+ ;;
+*-ncr-sysv4.3*)
+ AC_CHECK_LIB(mw, _mwvalidcheckl, LIBM=-lmw)
+ AC_CHECK_LIB(m, cos, LIBM="$LIBM -lm")
+ ;;
+*)
+ AC_CHECK_LIB(m, cos, LIBM=-lm)
+ ;;
+esac
+AC_SUBST([LIBM])
+])# LT_LIB_M
+
+# Old name:
+AU_ALIAS([AC_CHECK_LIBM], [LT_LIB_M])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_CHECK_LIBM], [])
+
+
+# _LT_COMPILER_NO_RTTI([TAGNAME])
+# -------------------------------
+m4_defun([_LT_COMPILER_NO_RTTI],
+[m4_require([_LT_TAG_COMPILER])dnl
+
+_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=
+
+if test yes = "$GCC"; then
+ case $cc_basename in
+ nvcc*)
+ _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -Xcompiler -fno-builtin' ;;
+ *)
+ _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin' ;;
+ esac
+
+ _LT_COMPILER_OPTION([if $compiler supports -fno-rtti -fno-exceptions],
+ lt_cv_prog_compiler_rtti_exceptions,
+ [-fno-rtti -fno-exceptions], [],
+ [_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)="$_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1) -fno-rtti -fno-exceptions"])
+fi
+_LT_TAGDECL([no_builtin_flag], [lt_prog_compiler_no_builtin_flag], [1],
+ [Compiler flag to turn off builtin functions])
+])# _LT_COMPILER_NO_RTTI
+
+
+# _LT_CMD_GLOBAL_SYMBOLS
+# ----------------------
+m4_defun([_LT_CMD_GLOBAL_SYMBOLS],
+[AC_REQUIRE([AC_CANONICAL_HOST])dnl
+AC_REQUIRE([AC_PROG_CC])dnl
+AC_REQUIRE([AC_PROG_AWK])dnl
+AC_REQUIRE([LT_PATH_NM])dnl
+AC_REQUIRE([LT_PATH_LD])dnl
+m4_require([_LT_DECL_SED])dnl
+m4_require([_LT_DECL_EGREP])dnl
+m4_require([_LT_TAG_COMPILER])dnl
+
+# Check for command to grab the raw symbol name followed by C symbol from nm.
+AC_MSG_CHECKING([command to parse $NM output from $compiler object])
+AC_CACHE_VAL([lt_cv_sys_global_symbol_pipe],
+[
+# These are sane defaults that work on at least a few old systems.
+# [They come from Ultrix. What could be older than Ultrix?!! ;)]
+
+# Character class describing NM global symbol codes.
+symcode='[[BCDEGRST]]'
+
+# Regexp to match symbols that can be accessed directly from C.
+sympat='\([[_A-Za-z]][[_A-Za-z0-9]]*\)'
+
+# Define system-specific variables.
+case $host_os in
+aix*)
+ symcode='[[BCDT]]'
+ ;;
+cygwin* | mingw* | pw32* | cegcc*)
+ symcode='[[ABCDGISTW]]'
+ ;;
+hpux*)
+ if test ia64 = "$host_cpu"; then
+ symcode='[[ABCDEGRST]]'
+ fi
+ ;;
+irix* | nonstopux*)
+ symcode='[[BCDEGRST]]'
+ ;;
+osf*)
+ symcode='[[BCDEGQRST]]'
+ ;;
+solaris*)
+ symcode='[[BDRT]]'
+ ;;
+sco3.2v5*)
+ symcode='[[DT]]'
+ ;;
+sysv4.2uw2*)
+ symcode='[[DT]]'
+ ;;
+sysv5* | sco5v6* | unixware* | OpenUNIX*)
+ symcode='[[ABDT]]'
+ ;;
+sysv4)
+ symcode='[[DFNSTU]]'
+ ;;
+esac
+
+# If we're using GNU nm, then use its standard symbol codes.
+case `$NM -V 2>&1` in
+*GNU* | *'with BFD'*)
+ symcode='[[ABCDGIRSTW]]' ;;
+esac
+
+if test "$lt_cv_nm_interface" = "MS dumpbin"; then
+ # Gets list of data symbols to import.
+ lt_cv_sys_global_symbol_to_import="sed -n -e 's/^I .* \(.*\)$/\1/p'"
+ # Adjust the below global symbol transforms to fixup imported variables.
+ lt_cdecl_hook=" -e 's/^I .* \(.*\)$/extern __declspec(dllimport) char \1;/p'"
+ lt_c_name_hook=" -e 's/^I .* \(.*\)$/ {\"\1\", (void *) 0},/p'"
+ lt_c_name_lib_hook="\
+ -e 's/^I .* \(lib.*\)$/ {\"\1\", (void *) 0},/p'\
+ -e 's/^I .* \(.*\)$/ {\"lib\1\", (void *) 0},/p'"
+else
+ # Disable hooks by default.
+ lt_cv_sys_global_symbol_to_import=
+ lt_cdecl_hook=
+ lt_c_name_hook=
+ lt_c_name_lib_hook=
+fi
+
+# Transform an extracted symbol line into a proper C declaration.
+# Some systems (esp. on ia64) link data and code symbols differently,
+# so use this general approach.
+lt_cv_sys_global_symbol_to_cdecl="sed -n"\
+$lt_cdecl_hook\
+" -e 's/^T .* \(.*\)$/extern int \1();/p'"\
+" -e 's/^$symcode$symcode* .* \(.*\)$/extern char \1;/p'"
+
+# Transform an extracted symbol line into symbol name and symbol address
+lt_cv_sys_global_symbol_to_c_name_address="sed -n"\
+$lt_c_name_hook\
+" -e 's/^: \(.*\) .*$/ {\"\1\", (void *) 0},/p'"\
+" -e 's/^$symcode$symcode* .* \(.*\)$/ {\"\1\", (void *) \&\1},/p'"
+
+# Transform an extracted symbol line into symbol name with lib prefix and
+# symbol address.
+lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="sed -n"\
+$lt_c_name_lib_hook\
+" -e 's/^: \(.*\) .*$/ {\"\1\", (void *) 0},/p'"\
+" -e 's/^$symcode$symcode* .* \(lib.*\)$/ {\"\1\", (void *) \&\1},/p'"\
+" -e 's/^$symcode$symcode* .* \(.*\)$/ {\"lib\1\", (void *) \&\1},/p'"
+
+# Handle CRLF in mingw tool chain
+opt_cr=
+case $build_os in
+mingw*)
+ opt_cr=`$ECHO 'x\{0,1\}' | tr x '\015'` # option cr in regexp
+ ;;
+esac
+
+# Try without a prefix underscore, then with it.
+for ac_symprfx in "" "_"; do
+
+ # Transform symcode, sympat, and symprfx into a raw symbol and a C symbol.
+ symxfrm="\\1 $ac_symprfx\\2 \\2"
+
+ # Write the raw and C identifiers.
+ if test "$lt_cv_nm_interface" = "MS dumpbin"; then
+ # Fake it for dumpbin and say T for any non-static function,
+ # D for any global variable and I for any imported variable.
+ # Also find C++ and __fastcall symbols from MSVC++,
+ # which start with @ or ?.
+ lt_cv_sys_global_symbol_pipe="$AWK ['"\
+" {last_section=section; section=\$ 3};"\
+" /^COFF SYMBOL TABLE/{for(i in hide) delete hide[i]};"\
+" /Section length .*#relocs.*(pick any)/{hide[last_section]=1};"\
+" /^ *Symbol name *: /{split(\$ 0,sn,\":\"); si=substr(sn[2],2)};"\
+" /^ *Type *: code/{print \"T\",si,substr(si,length(prfx))};"\
+" /^ *Type *: data/{print \"I\",si,substr(si,length(prfx))};"\
+" \$ 0!~/External *\|/{next};"\
+" / 0+ UNDEF /{next}; / UNDEF \([^|]\)*()/{next};"\
+" {if(hide[section]) next};"\
+" {f=\"D\"}; \$ 0~/\(\).*\|/{f=\"T\"};"\
+" {split(\$ 0,a,/\||\r/); split(a[2],s)};"\
+" s[1]~/^[@?]/{print f,s[1],s[1]; next};"\
+" s[1]~prfx {split(s[1],t,\"@\"); print f,t[1],substr(t[1],length(prfx))}"\
+" ' prfx=^$ac_symprfx]"
+ else
+ lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[[ ]]\($symcode$symcode*\)[[ ]][[ ]]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'"
+ fi
+ lt_cv_sys_global_symbol_pipe="$lt_cv_sys_global_symbol_pipe | sed '/ __gnu_lto/d'"
+
+ # Check to see that the pipe works correctly.
+ pipe_works=no
+
+ rm -f conftest*
+ cat > conftest.$ac_ext <<_LT_EOF
+#ifdef __cplusplus
+extern "C" {
+#endif
+char nm_test_var;
+void nm_test_func(void);
+void nm_test_func(void){}
+#ifdef __cplusplus
+}
+#endif
+int main(){nm_test_var='a';nm_test_func();return(0);}
+_LT_EOF
+
+ if AC_TRY_EVAL(ac_compile); then
+ # Now try to grab the symbols.
+ nlist=conftest.nm
+ if AC_TRY_EVAL(NM conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist) && test -s "$nlist"; then
+ # Try sorting and uniquifying the output.
+ if sort "$nlist" | uniq > "$nlist"T; then
+ mv -f "$nlist"T "$nlist"
+ else
+ rm -f "$nlist"T
+ fi
+
+ # Make sure that we snagged all the symbols we need.
+ if $GREP ' nm_test_var$' "$nlist" >/dev/null; then
+ if $GREP ' nm_test_func$' "$nlist" >/dev/null; then
+ cat <<_LT_EOF > conftest.$ac_ext
+/* Keep this code in sync between libtool.m4, ltmain, lt_system.h, and tests. */
+#if defined _WIN32 || defined __CYGWIN__ || defined _WIN32_WCE
+/* DATA imports from DLLs on WIN32 can't be const, because runtime
+ relocations are performed -- see ld's documentation on pseudo-relocs. */
+# define LT@&t@_DLSYM_CONST
+#elif defined __osf__
+/* This system does not cope well with relocations in const data. */
+# define LT@&t@_DLSYM_CONST
+#else
+# define LT@&t@_DLSYM_CONST const
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+_LT_EOF
+ # Now generate the symbol file.
+ eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | $GREP -v main >> conftest.$ac_ext'
+
+ cat <<_LT_EOF >> conftest.$ac_ext
+
+/* The mapping between symbol names and symbols. */
+LT@&t@_DLSYM_CONST struct {
+ const char *name;
+ void *address;
+}
+lt__PROGRAM__LTX_preloaded_symbols[[]] =
+{
+ { "@PROGRAM@", (void *) 0 },
+_LT_EOF
+ $SED "s/^$symcode$symcode* .* \(.*\)$/ {\"\1\", (void *) \&\1},/" < "$nlist" | $GREP -v main >> conftest.$ac_ext
+ cat <<\_LT_EOF >> conftest.$ac_ext
+ {0, (void *) 0}
+};
+
+/* This works around a problem in FreeBSD linker */
+#ifdef FREEBSD_WORKAROUND
+static const void *lt_preloaded_setup() {
+ return lt__PROGRAM__LTX_preloaded_symbols;
+}
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+_LT_EOF
+ # Now try linking the two files.
+ mv conftest.$ac_objext conftstm.$ac_objext
+ lt_globsym_save_LIBS=$LIBS
+ lt_globsym_save_CFLAGS=$CFLAGS
+ LIBS=conftstm.$ac_objext
+ CFLAGS="$CFLAGS$_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)"
+ if AC_TRY_EVAL(ac_link) && test -s conftest$ac_exeext; then
+ pipe_works=yes
+ fi
+ LIBS=$lt_globsym_save_LIBS
+ CFLAGS=$lt_globsym_save_CFLAGS
+ else
+ echo "cannot find nm_test_func in $nlist" >&AS_MESSAGE_LOG_FD
+ fi
+ else
+ echo "cannot find nm_test_var in $nlist" >&AS_MESSAGE_LOG_FD
+ fi
+ else
+ echo "cannot run $lt_cv_sys_global_symbol_pipe" >&AS_MESSAGE_LOG_FD
+ fi
+ else
+ echo "$progname: failed program was:" >&AS_MESSAGE_LOG_FD
+ cat conftest.$ac_ext >&5
+ fi
+ rm -rf conftest* conftst*
+
+ # Do not use the global_symbol_pipe unless it works.
+ if test yes = "$pipe_works"; then
+ break
+ else
+ lt_cv_sys_global_symbol_pipe=
+ fi
+done
+])
+if test -z "$lt_cv_sys_global_symbol_pipe"; then
+ lt_cv_sys_global_symbol_to_cdecl=
+fi
+if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then
+ AC_MSG_RESULT(failed)
+else
+ AC_MSG_RESULT(ok)
+fi
+
+# Response file support.
+if test "$lt_cv_nm_interface" = "MS dumpbin"; then
+ nm_file_list_spec='@'
+elif $NM --help 2>/dev/null | grep '[[@]]FILE' >/dev/null; then
+ nm_file_list_spec='@'
+fi
+
+_LT_DECL([global_symbol_pipe], [lt_cv_sys_global_symbol_pipe], [1],
+ [Take the output of nm and produce a listing of raw symbols and C names])
+_LT_DECL([global_symbol_to_cdecl], [lt_cv_sys_global_symbol_to_cdecl], [1],
+ [Transform the output of nm in a proper C declaration])
+_LT_DECL([global_symbol_to_import], [lt_cv_sys_global_symbol_to_import], [1],
+ [Transform the output of nm into a list of symbols to manually relocate])
+_LT_DECL([global_symbol_to_c_name_address],
+ [lt_cv_sys_global_symbol_to_c_name_address], [1],
+ [Transform the output of nm in a C name address pair])
+_LT_DECL([global_symbol_to_c_name_address_lib_prefix],
+ [lt_cv_sys_global_symbol_to_c_name_address_lib_prefix], [1],
+ [Transform the output of nm in a C name address pair when lib prefix is needed])
+_LT_DECL([nm_interface], [lt_cv_nm_interface], [1],
+ [The name lister interface])
+_LT_DECL([], [nm_file_list_spec], [1],
+ [Specify filename containing input files for $NM])
+]) # _LT_CMD_GLOBAL_SYMBOLS
+
+
+# _LT_COMPILER_PIC([TAGNAME])
+# ---------------------------
+m4_defun([_LT_COMPILER_PIC],
+[m4_require([_LT_TAG_COMPILER])dnl
+_LT_TAGVAR(lt_prog_compiler_wl, $1)=
+_LT_TAGVAR(lt_prog_compiler_pic, $1)=
+_LT_TAGVAR(lt_prog_compiler_static, $1)=
+
+m4_if([$1], [CXX], [
+ # C++ specific cases for pic, static, wl, etc.
+ if test yes = "$GXX"; then
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
+
+ case $host_os in
+ aix*)
+ # All AIX code is PIC.
+ if test ia64 = "$host_cpu"; then
+ # AIX 5 now supports IA64 processor
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ fi
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+ ;;
+
+ amigaos*)
+ case $host_cpu in
+ powerpc)
+ # see comment about AmigaOS4 .so support
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+ ;;
+ m68k)
+ # FIXME: we need at least 68020 code to build shared libraries, but
+ # adding the '-m68020' flag to GCC prevents building anything better,
+ # like '-m68040'.
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4'
+ ;;
+ esac
+ ;;
+
+ beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*)
+ # PIC is the default for these OSes.
+ ;;
+ mingw* | cygwin* | os2* | pw32* | cegcc*)
+ # This hack is so that the source file can tell whether it is being
+ # built for inclusion in a dll (and should export symbols for example).
+ # Although the cygwin gcc ignores -fPIC, still need this for old-style
+ # (--disable-auto-import) libraries
+ m4_if([$1], [GCJ], [],
+ [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT'])
+ case $host_os in
+ os2*)
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='$wl-static'
+ ;;
+ esac
+ ;;
+ darwin* | rhapsody*)
+ # PIC is the default on this platform
+ # Common symbols not allowed in MH_DYLIB files
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common'
+ ;;
+ *djgpp*)
+ # DJGPP does not support shared libraries at all
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)=
+ ;;
+ haiku*)
+ # PIC is the default for Haiku.
+ # The "-static" flag exists, but is broken.
+ _LT_TAGVAR(lt_prog_compiler_static, $1)=
+ ;;
+ interix[[3-9]]*)
+ # Interix 3.x gcc -fpic/-fPIC options generate broken code.
+ # Instead, we relocate shared libraries at runtime.
+ ;;
+ sysv4*MP*)
+ if test -d /usr/nec; then
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic
+ fi
+ ;;
+ hpux*)
+ # PIC is the default for 64-bit PA HP-UX, but not for 32-bit
+ # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag
+ # sets the default TLS model and affects inlining.
+ case $host_cpu in
+ hppa*64*)
+ ;;
+ *)
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+ ;;
+ esac
+ ;;
+ *qnx* | *nto*)
+ # QNX uses GNU C++, but need to define -shared option too, otherwise
+ # it will coredump.
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared'
+ ;;
+ *)
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+ ;;
+ esac
+ else
+ case $host_os in
+ aix[[4-9]]*)
+ # All AIX code is PIC.
+ if test ia64 = "$host_cpu"; then
+ # AIX 5 now supports IA64 processor
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ else
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp'
+ fi
+ ;;
+ chorus*)
+ case $cc_basename in
+ cxch68*)
+ # Green Hills C++ Compiler
+ # _LT_TAGVAR(lt_prog_compiler_static, $1)="--no_auto_instantiation -u __main -u __premain -u _abort -r $COOL_DIR/lib/libOrb.a $MVME_DIR/lib/CC/libC.a $MVME_DIR/lib/classix/libcx.s.a"
+ ;;
+ esac
+ ;;
+ mingw* | cygwin* | os2* | pw32* | cegcc*)
+ # This hack is so that the source file can tell whether it is being
+ # built for inclusion in a dll (and should export symbols for example).
+ m4_if([$1], [GCJ], [],
+ [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT'])
+ ;;
+ dgux*)
+ case $cc_basename in
+ ec++*)
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+ ;;
+ ghcx*)
+ # Green Hills C++ Compiler
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
+ ;;
+ *)
+ ;;
+ esac
+ ;;
+ freebsd* | dragonfly*)
+ # FreeBSD uses GNU C++
+ ;;
+ hpux9* | hpux10* | hpux11*)
+ case $cc_basename in
+ CC*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='$wl-a ${wl}archive'
+ if test ia64 != "$host_cpu"; then
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z'
+ fi
+ ;;
+ aCC*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='$wl-a ${wl}archive'
+ case $host_cpu in
+ hppa*64*|ia64*)
+ # +Z the default
+ ;;
+ *)
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z'
+ ;;
+ esac
+ ;;
+ *)
+ ;;
+ esac
+ ;;
+ interix*)
+ # This is c89, which is MS Visual C++ (no shared libs)
+ # Anyone wants to do a port?
+ ;;
+ irix5* | irix6* | nonstopux*)
+ case $cc_basename in
+ CC*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+ # CC pic flag -KPIC is the default.
+ ;;
+ *)
+ ;;
+ esac
+ ;;
+ linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*)
+ case $cc_basename in
+ KCC*)
+ # KAI C++ Compiler
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,'
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+ ;;
+ ecpc* )
+ # old Intel C++ for x86_64, which still supported -KPIC.
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
+ ;;
+ icpc* )
+ # Intel C++, used to be incompatible with GCC.
+ # ICC 10 doesn't accept -KPIC any more.
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
+ ;;
+ pgCC* | pgcpp*)
+ # Portland Group C++ compiler
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ ;;
+ cxx*)
+ # Compaq C++
+ # Make sure the PIC flag is empty. It appears that all Alpha
+ # Linux and Compaq Tru64 Unix objects are PIC.
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)=
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+ ;;
+ xlc* | xlC* | bgxl[[cC]]* | mpixl[[cC]]*)
+ # IBM XL 8.0, 9.0 on PPC and BlueGene
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-qpic'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-qstaticlink'
+ ;;
+ *)
+ case `$CC -V 2>&1 | sed 5q` in
+ *Sun\ C*)
+ # Sun C++ 5.9
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld '
+ ;;
+ esac
+ ;;
+ esac
+ ;;
+ lynxos*)
+ ;;
+ m88k*)
+ ;;
+ mvs*)
+ case $cc_basename in
+ cxx*)
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-W c,exportall'
+ ;;
+ *)
+ ;;
+ esac
+ ;;
+ netbsd* | netbsdelf*-gnu)
+ ;;
+ *qnx* | *nto*)
+ # QNX uses GNU C++, but need to define -shared option too, otherwise
+ # it will coredump.
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared'
+ ;;
+ osf3* | osf4* | osf5*)
+ case $cc_basename in
+ KCC*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,'
+ ;;
+ RCC*)
+ # Rational C++ 2.4.1
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
+ ;;
+ cxx*)
+ # Digital/Compaq C++
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ # Make sure the PIC flag is empty. It appears that all Alpha
+ # Linux and Compaq Tru64 Unix objects are PIC.
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)=
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+ ;;
+ *)
+ ;;
+ esac
+ ;;
+ psos*)
+ ;;
+ solaris*)
+ case $cc_basename in
+ CC* | sunCC*)
+ # Sun C++ 4.2, 5.x and Centerline C++
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld '
+ ;;
+ gcx*)
+ # Green Hills C++ Compiler
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC'
+ ;;
+ *)
+ ;;
+ esac
+ ;;
+ sunos4*)
+ case $cc_basename in
+ CC*)
+ # Sun C++ 4.x
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ ;;
+ lcc*)
+ # Lucid
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
+ ;;
+ *)
+ ;;
+ esac
+ ;;
+ sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*)
+ case $cc_basename in
+ CC*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ ;;
+ esac
+ ;;
+ tandem*)
+ case $cc_basename in
+ NCC*)
+ # NonStop-UX NCC 3.20
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+ ;;
+ *)
+ ;;
+ esac
+ ;;
+ vxworks*)
+ ;;
+ *)
+ _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no
+ ;;
+ esac
+ fi
+],
+[
+ if test yes = "$GCC"; then
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
+
+ case $host_os in
+ aix*)
+ # All AIX code is PIC.
+ if test ia64 = "$host_cpu"; then
+ # AIX 5 now supports IA64 processor
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ fi
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+ ;;
+
+ amigaos*)
+ case $host_cpu in
+ powerpc)
+ # see comment about AmigaOS4 .so support
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+ ;;
+ m68k)
+ # FIXME: we need at least 68020 code to build shared libraries, but
+ # adding the '-m68020' flag to GCC prevents building anything better,
+ # like '-m68040'.
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4'
+ ;;
+ esac
+ ;;
+
+ beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*)
+ # PIC is the default for these OSes.
+ ;;
+
+ mingw* | cygwin* | pw32* | os2* | cegcc*)
+ # This hack is so that the source file can tell whether it is being
+ # built for inclusion in a dll (and should export symbols for example).
+ # Although the cygwin gcc ignores -fPIC, still need this for old-style
+ # (--disable-auto-import) libraries
+ m4_if([$1], [GCJ], [],
+ [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT'])
+ case $host_os in
+ os2*)
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='$wl-static'
+ ;;
+ esac
+ ;;
+
+ darwin* | rhapsody*)
+ # PIC is the default on this platform
+ # Common symbols not allowed in MH_DYLIB files
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common'
+ ;;
+
+ haiku*)
+ # PIC is the default for Haiku.
+ # The "-static" flag exists, but is broken.
+ _LT_TAGVAR(lt_prog_compiler_static, $1)=
+ ;;
+
+ hpux*)
+ # PIC is the default for 64-bit PA HP-UX, but not for 32-bit
+ # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag
+ # sets the default TLS model and affects inlining.
+ case $host_cpu in
+ hppa*64*)
+ # +Z the default
+ ;;
+ *)
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+ ;;
+ esac
+ ;;
+
+ interix[[3-9]]*)
+ # Interix 3.x gcc -fpic/-fPIC options generate broken code.
+ # Instead, we relocate shared libraries at runtime.
+ ;;
+
+ msdosdjgpp*)
+ # Just because we use GCC doesn't mean we suddenly get shared libraries
+ # on systems that don't support them.
+ _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no
+ enable_shared=no
+ ;;
+
+ *nto* | *qnx*)
+ # QNX uses GNU C++, but need to define -shared option too, otherwise
+ # it will coredump.
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared'
+ ;;
+
+ sysv4*MP*)
+ if test -d /usr/nec; then
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic
+ fi
+ ;;
+
+ *)
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+ ;;
+ esac
+
+ case $cc_basename in
+ nvcc*) # Cuda Compiler Driver 2.2
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Xlinker '
+ if test -n "$_LT_TAGVAR(lt_prog_compiler_pic, $1)"; then
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)="-Xcompiler $_LT_TAGVAR(lt_prog_compiler_pic, $1)"
+ fi
+ ;;
+ esac
+ else
+ # PORTME Check for flag to pass linker flags through the system compiler.
+ case $host_os in
+ aix*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ if test ia64 = "$host_cpu"; then
+ # AIX 5 now supports IA64 processor
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ else
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp'
+ fi
+ ;;
+
+ darwin* | rhapsody*)
+ # PIC is the default on this platform
+ # Common symbols not allowed in MH_DYLIB files
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common'
+ case $cc_basename in
+ nagfor*)
+ # NAG Fortran compiler
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,-Wl,,'
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ ;;
+ esac
+ ;;
+
+ mingw* | cygwin* | pw32* | os2* | cegcc*)
+ # This hack is so that the source file can tell whether it is being
+ # built for inclusion in a dll (and should export symbols for example).
+ m4_if([$1], [GCJ], [],
+ [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT'])
+ case $host_os in
+ os2*)
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='$wl-static'
+ ;;
+ esac
+ ;;
+
+ hpux9* | hpux10* | hpux11*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but
+ # not for PA HP-UX.
+ case $host_cpu in
+ hppa*64*|ia64*)
+ # +Z the default
+ ;;
+ *)
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z'
+ ;;
+ esac
+ # Is there a better lt_prog_compiler_static that works with the bundled CC?
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='$wl-a ${wl}archive'
+ ;;
+
+ irix5* | irix6* | nonstopux*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ # PIC (with -KPIC) is the default.
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+ ;;
+
+ linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*)
+ case $cc_basename in
+ # old Intel for x86_64, which still supported -KPIC.
+ ecc*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
+ ;;
+ # icc used to be incompatible with GCC.
+ # ICC 10 doesn't accept -KPIC any more.
+ icc* | ifort*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
+ ;;
+ # Lahey Fortran 8.1.
+ lf95*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='--shared'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='--static'
+ ;;
+ nagfor*)
+ # NAG Fortran compiler
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,-Wl,,'
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ ;;
+ tcc*)
+ # Fabrice Bellard et al's Tiny C Compiler
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
+ ;;
+ pgcc* | pgf77* | pgf90* | pgf95* | pgfortran*)
+ # Portland Group compilers (*not* the Pentium gcc compiler,
+ # which looks to be a dead project)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ ;;
+ ccc*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ # All Alpha code is PIC.
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+ ;;
+ xl* | bgxl* | bgf* | mpixl*)
+ # IBM XL C 8.0/Fortran 10.1, 11.1 on PPC and BlueGene
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-qpic'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-qstaticlink'
+ ;;
+ *)
+ case `$CC -V 2>&1 | sed 5q` in
+ *Sun\ Ceres\ Fortran* | *Sun*Fortran*\ [[1-7]].* | *Sun*Fortran*\ 8.[[0-3]]*)
+ # Sun Fortran 8.3 passes all unrecognized flags to the linker
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)=''
+ ;;
+ *Sun\ F* | *Sun*Fortran*)
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld '
+ ;;
+ *Sun\ C*)
+ # Sun C 5.9
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ ;;
+ *Intel*\ [[CF]]*Compiler*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
+ ;;
+ *Portland\ Group*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ ;;
+ esac
+ ;;
+ esac
+ ;;
+
+ newsos6)
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ ;;
+
+ *nto* | *qnx*)
+ # QNX uses GNU C++, but need to define -shared option too, otherwise
+ # it will coredump.
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared'
+ ;;
+
+ osf3* | osf4* | osf5*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ # All OSF/1 code is PIC.
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+ ;;
+
+ rdos*)
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+ ;;
+
+ solaris*)
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ case $cc_basename in
+ f77* | f90* | f95* | sunf77* | sunf90* | sunf95*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ';;
+ *)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,';;
+ esac
+ ;;
+
+ sunos4*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld '
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ ;;
+
+ sysv4 | sysv4.2uw2* | sysv4.3*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ ;;
+
+ sysv4*MP*)
+ if test -d /usr/nec; then
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-Kconform_pic'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ fi
+ ;;
+
+ sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ ;;
+
+ unicos*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no
+ ;;
+
+ uts4*)
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ ;;
+
+ *)
+ _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no
+ ;;
+ esac
+ fi
+])
+case $host_os in
+ # For platforms that do not support PIC, -DPIC is meaningless:
+ *djgpp*)
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)=
+ ;;
+ *)
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)="$_LT_TAGVAR(lt_prog_compiler_pic, $1)@&t@m4_if([$1],[],[ -DPIC],[m4_if([$1],[CXX],[ -DPIC],[])])"
+ ;;
+esac
+
+AC_CACHE_CHECK([for $compiler option to produce PIC],
+ [_LT_TAGVAR(lt_cv_prog_compiler_pic, $1)],
+ [_LT_TAGVAR(lt_cv_prog_compiler_pic, $1)=$_LT_TAGVAR(lt_prog_compiler_pic, $1)])
+_LT_TAGVAR(lt_prog_compiler_pic, $1)=$_LT_TAGVAR(lt_cv_prog_compiler_pic, $1)
+
+#
+# Check to make sure the PIC flag actually works.
+#
+if test -n "$_LT_TAGVAR(lt_prog_compiler_pic, $1)"; then
+ _LT_COMPILER_OPTION([if $compiler PIC flag $_LT_TAGVAR(lt_prog_compiler_pic, $1) works],
+ [_LT_TAGVAR(lt_cv_prog_compiler_pic_works, $1)],
+ [$_LT_TAGVAR(lt_prog_compiler_pic, $1)@&t@m4_if([$1],[],[ -DPIC],[m4_if([$1],[CXX],[ -DPIC],[])])], [],
+ [case $_LT_TAGVAR(lt_prog_compiler_pic, $1) in
+ "" | " "*) ;;
+ *) _LT_TAGVAR(lt_prog_compiler_pic, $1)=" $_LT_TAGVAR(lt_prog_compiler_pic, $1)" ;;
+ esac],
+ [_LT_TAGVAR(lt_prog_compiler_pic, $1)=
+ _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no])
+fi
+_LT_TAGDECL([pic_flag], [lt_prog_compiler_pic], [1],
+ [Additional compiler flags for building library objects])
+
+_LT_TAGDECL([wl], [lt_prog_compiler_wl], [1],
+ [How to pass a linker flag through the compiler])
+#
+# Check to make sure the static flag actually works.
+#
+wl=$_LT_TAGVAR(lt_prog_compiler_wl, $1) eval lt_tmp_static_flag=\"$_LT_TAGVAR(lt_prog_compiler_static, $1)\"
+_LT_LINKER_OPTION([if $compiler static flag $lt_tmp_static_flag works],
+ _LT_TAGVAR(lt_cv_prog_compiler_static_works, $1),
+ $lt_tmp_static_flag,
+ [],
+ [_LT_TAGVAR(lt_prog_compiler_static, $1)=])
+_LT_TAGDECL([link_static_flag], [lt_prog_compiler_static], [1],
+ [Compiler flag to prevent dynamic linking])
+])# _LT_COMPILER_PIC
+
+
+# _LT_LINKER_SHLIBS([TAGNAME])
+# ----------------------------
+# See if the linker supports building shared libraries.
+m4_defun([_LT_LINKER_SHLIBS],
+[AC_REQUIRE([LT_PATH_LD])dnl
+AC_REQUIRE([LT_PATH_NM])dnl
+m4_require([_LT_PATH_MANIFEST_TOOL])dnl
+m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+m4_require([_LT_DECL_EGREP])dnl
+m4_require([_LT_DECL_SED])dnl
+m4_require([_LT_CMD_GLOBAL_SYMBOLS])dnl
+m4_require([_LT_TAG_COMPILER])dnl
+AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries])
+m4_if([$1], [CXX], [
+ _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
+ _LT_TAGVAR(exclude_expsyms, $1)=['_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*']
+ case $host_os in
+ aix[[4-9]]*)
+ # If we're using GNU nm, then we don't want the "-C" option.
+ # -C means demangle to GNU nm, but means don't demangle to AIX nm.
+ # Without the "-l" option, or with the "-B" option, AIX nm treats
+ # weak defined symbols like other global defined symbols, whereas
+ # GNU nm marks them as "W".
+ # While the 'weak' keyword is ignored in the Export File, we need
+ # it in the Import File for the 'aix-soname' feature, so we have
+ # to replace the "-B" option with "-P" for AIX nm.
+ if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then
+ _LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && ([substr](\$ 3,1,1) != ".")) { if (\$ 2 == "W") { print \$ 3 " weak" } else { print \$ 3 } } }'\'' | sort -u > $export_symbols'
+ else
+ _LT_TAGVAR(export_symbols_cmds, $1)='`func_echo_all $NM | $SED -e '\''s/B\([[^B]]*\)$/P\1/'\''` -PCpgl $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) && ([substr](\$ 1,1,1) != ".")) { if ((\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) { print \$ 1 " weak" } else { print \$ 1 } } }'\'' | sort -u > $export_symbols'
+ fi
+ ;;
+ pw32*)
+ _LT_TAGVAR(export_symbols_cmds, $1)=$ltdll_cmds
+ ;;
+ cygwin* | mingw* | cegcc*)
+ case $cc_basename in
+ cl*)
+ _LT_TAGVAR(exclude_expsyms, $1)='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*'
+ ;;
+ *)
+ _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1 DATA/;s/^.*[[ ]]__nm__\([[^ ]]*\)[[ ]][[^ ]]*/\1 DATA/;/^I[[ ]]/d;/^[[AITW]][[ ]]/s/.* //'\'' | sort | uniq > $export_symbols'
+ _LT_TAGVAR(exclude_expsyms, $1)=['[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname']
+ ;;
+ esac
+ ;;
+ linux* | k*bsd*-gnu | gnu*)
+ _LT_TAGVAR(link_all_deplibs, $1)=no
+ ;;
+ *)
+ _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
+ ;;
+ esac
+], [
+ runpath_var=
+ _LT_TAGVAR(allow_undefined_flag, $1)=
+ _LT_TAGVAR(always_export_symbols, $1)=no
+ _LT_TAGVAR(archive_cmds, $1)=
+ _LT_TAGVAR(archive_expsym_cmds, $1)=
+ _LT_TAGVAR(compiler_needs_object, $1)=no
+ _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)=
+ _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
+ _LT_TAGVAR(hardcode_automatic, $1)=no
+ _LT_TAGVAR(hardcode_direct, $1)=no
+ _LT_TAGVAR(hardcode_direct_absolute, $1)=no
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=
+ _LT_TAGVAR(hardcode_minus_L, $1)=no
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported
+ _LT_TAGVAR(inherit_rpath, $1)=no
+ _LT_TAGVAR(link_all_deplibs, $1)=unknown
+ _LT_TAGVAR(module_cmds, $1)=
+ _LT_TAGVAR(module_expsym_cmds, $1)=
+ _LT_TAGVAR(old_archive_from_new_cmds, $1)=
+ _LT_TAGVAR(old_archive_from_expsyms_cmds, $1)=
+ _LT_TAGVAR(thread_safe_flag_spec, $1)=
+ _LT_TAGVAR(whole_archive_flag_spec, $1)=
+ # include_expsyms should be a list of space-separated symbols to be *always*
+ # included in the symbol list
+ _LT_TAGVAR(include_expsyms, $1)=
+ # exclude_expsyms can be an extended regexp of symbols to exclude
+ # it will be wrapped by ' (' and ')$', so one must not match beginning or
+ # end of line. Example: 'a|bc|.*d.*' will exclude the symbols 'a' and 'bc',
+ # as well as any symbol that contains 'd'.
+ _LT_TAGVAR(exclude_expsyms, $1)=['_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*']
+ # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out
+ # platforms (ab)use it in PIC code, but their linkers get confused if
+ # the symbol is explicitly referenced. Since portable code cannot
+ # rely on this symbol name, it's probably fine to never include it in
+ # preloaded symbol tables.
+ # Exclude shared library initialization/finalization symbols.
+dnl Note also adjust exclude_expsyms for C++ above.
+ extract_expsyms_cmds=
+
+ case $host_os in
+ cygwin* | mingw* | pw32* | cegcc*)
+ # FIXME: the MSVC++ port hasn't been tested in a loooong time
+ # When not using gcc, we currently assume that we are using
+ # Microsoft Visual C++.
+ if test yes != "$GCC"; then
+ with_gnu_ld=no
+ fi
+ ;;
+ interix*)
+ # we just hope/assume this is gcc and not c89 (= MSVC++)
+ with_gnu_ld=yes
+ ;;
+ openbsd* | bitrig*)
+ with_gnu_ld=no
+ ;;
+ linux* | k*bsd*-gnu | gnu*)
+ _LT_TAGVAR(link_all_deplibs, $1)=no
+ ;;
+ esac
+
+ _LT_TAGVAR(ld_shlibs, $1)=yes
+
+ # On some targets, GNU ld is compatible enough with the native linker
+ # that we're better off using the native interface for both.
+ lt_use_gnu_ld_interface=no
+ if test yes = "$with_gnu_ld"; then
+ case $host_os in
+ aix*)
+ # The AIX port of GNU ld has always aspired to compatibility
+ # with the native linker. However, as the warning in the GNU ld
+ # block says, versions before 2.19.5* couldn't really create working
+ # shared libraries, regardless of the interface used.
+ case `$LD -v 2>&1` in
+ *\ \(GNU\ Binutils\)\ 2.19.5*) ;;
+ *\ \(GNU\ Binutils\)\ 2.[[2-9]]*) ;;
+ *\ \(GNU\ Binutils\)\ [[3-9]]*) ;;
+ *)
+ lt_use_gnu_ld_interface=yes
+ ;;
+ esac
+ ;;
+ *)
+ lt_use_gnu_ld_interface=yes
+ ;;
+ esac
+ fi
+
+ if test yes = "$lt_use_gnu_ld_interface"; then
+ # If archive_cmds runs LD, not CC, wlarc should be empty
+ wlarc='$wl'
+
+ # Set some defaults for GNU ld with shared library support. These
+ # are reset later if shared libraries are not supported. Putting them
+ # here allows them to be overridden if necessary.
+ runpath_var=LD_RUN_PATH
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir'
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-dynamic'
+ # ancient GNU ld didn't support --whole-archive et. al.
+ if $LD --help 2>&1 | $GREP 'no-whole-archive' > /dev/null; then
+ _LT_TAGVAR(whole_archive_flag_spec, $1)=$wlarc'--whole-archive$convenience '$wlarc'--no-whole-archive'
+ else
+ _LT_TAGVAR(whole_archive_flag_spec, $1)=
+ fi
+ supports_anon_versioning=no
+ case `$LD -v | $SED -e 's/([^)]\+)\s\+//' 2>&1` in
+ *GNU\ gold*) supports_anon_versioning=yes ;;
+ *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.10.*) ;; # catch versions < 2.11
+ *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ...
+ *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ...
+ *\ 2.11.*) ;; # other 2.11 versions
+ *) supports_anon_versioning=yes ;;
+ esac
+
+ # See if GNU ld supports shared libraries.
+ case $host_os in
+ aix[[3-9]]*)
+ # On AIX/PPC, the GNU linker is very broken
+ if test ia64 != "$host_cpu"; then
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ cat <<_LT_EOF 1>&2
+
+*** Warning: the GNU linker, at least up to release 2.19, is reported
+*** to be unable to reliably create shared libraries on AIX.
+*** Therefore, libtool is disabling shared libraries support. If you
+*** really care for shared libraries, you may want to install binutils
+*** 2.20 or above, or modify your PATH so that a non-GNU linker is found.
+*** You will then need to restart the configuration process.
+
+_LT_EOF
+ fi
+ ;;
+
+ amigaos*)
+ case $host_cpu in
+ powerpc)
+ # see comment about AmigaOS4 .so support
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)=''
+ ;;
+ m68k)
+ _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+ _LT_TAGVAR(hardcode_minus_L, $1)=yes
+ ;;
+ esac
+ ;;
+
+ beos*)
+ if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+ _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+ # Joseph Beckenbach <jrb3@best.com> says some releases of gcc
+ # support --undefined. This deserves some investigation. FIXME
+ _LT_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
+ else
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ fi
+ ;;
+
+ cygwin* | mingw* | pw32* | cegcc*)
+ # _LT_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless,
+ # as there is no search path for DLLs.
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-all-symbols'
+ _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+ _LT_TAGVAR(always_export_symbols, $1)=no
+ _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
+ _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1 DATA/;s/^.*[[ ]]__nm__\([[^ ]]*\)[[ ]][[^ ]]*/\1 DATA/;/^I[[ ]]/d;/^[[AITW]][[ ]]/s/.* //'\'' | sort | uniq > $export_symbols'
+ _LT_TAGVAR(exclude_expsyms, $1)=['[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname']
+
+ if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname $wl--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+ # If the export-symbols file already is a .def file, use it as
+ # is; otherwise, prepend EXPORTS...
+ _LT_TAGVAR(archive_expsym_cmds, $1)='if _LT_DLL_DEF_P([$export_symbols]); then
+ cp $export_symbols $output_objdir/$soname.def;
+ else
+ echo EXPORTS > $output_objdir/$soname.def;
+ cat $export_symbols >> $output_objdir/$soname.def;
+ fi~
+ $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname $wl--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+ else
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ fi
+ ;;
+
+ haiku*)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
+ _LT_TAGVAR(link_all_deplibs, $1)=yes
+ ;;
+
+ os2*)
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+ _LT_TAGVAR(hardcode_minus_L, $1)=yes
+ _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+ shrext_cmds=.dll
+ _LT_TAGVAR(archive_cmds, $1)='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~
+ $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~
+ $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~
+ $ECHO EXPORTS >> $output_objdir/$libname.def~
+ emxexp $libobjs | $SED /"_DLL_InitTerm"/d >> $output_objdir/$libname.def~
+ $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~
+ emximp -o $lib $output_objdir/$libname.def'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~
+ $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~
+ $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~
+ $ECHO EXPORTS >> $output_objdir/$libname.def~
+ prefix_cmds="$SED"~
+ if test EXPORTS = "`$SED 1q $export_symbols`"; then
+ prefix_cmds="$prefix_cmds -e 1d";
+ fi~
+ prefix_cmds="$prefix_cmds -e \"s/^\(.*\)$/_\1/g\""~
+ cat $export_symbols | $prefix_cmds >> $output_objdir/$libname.def~
+ $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~
+ emximp -o $lib $output_objdir/$libname.def'
+ _LT_TAGVAR(old_archive_From_new_cmds, $1)='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def'
+ _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
+ ;;
+
+ interix[[3-9]]*)
+ _LT_TAGVAR(hardcode_direct, $1)=no
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir'
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E'
+ # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc.
+ # Instead, shared libraries are loaded at an image base (0x10000000 by
+ # default) and relocated if they conflict, which is a slow very memory
+ # consuming and fragmenting process. To avoid this, we pick a random,
+ # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link
+ # time. Moving up from 0x10000000 also allows more sbrk(2) space.
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-h,$soname $wl--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='sed "s|^|_|" $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-h,$soname $wl--retain-symbols-file,$output_objdir/$soname.expsym $wl--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+ ;;
+
+ gnu* | linux* | tpf* | k*bsd*-gnu | kopensolaris*-gnu)
+ tmp_diet=no
+ if test linux-dietlibc = "$host_os"; then
+ case $cc_basename in
+ diet\ *) tmp_diet=yes;; # linux-dietlibc with static linking (!diet-dyn)
+ esac
+ fi
+ if $LD --help 2>&1 | $EGREP ': supported targets:.* elf' > /dev/null \
+ && test no = "$tmp_diet"
+ then
+ tmp_addflag=' $pic_flag'
+ tmp_sharedflag='-shared'
+ case $cc_basename,$host_cpu in
+ pgcc*) # Portland Group C compiler
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive'
+ tmp_addflag=' $pic_flag'
+ ;;
+ pgf77* | pgf90* | pgf95* | pgfortran*)
+ # Portland Group f77 and f90 compilers
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive'
+ tmp_addflag=' $pic_flag -Mnomain' ;;
+ ecc*,ia64* | icc*,ia64*) # Intel C compiler on ia64
+ tmp_addflag=' -i_dynamic' ;;
+ efc*,ia64* | ifort*,ia64*) # Intel Fortran compiler on ia64
+ tmp_addflag=' -i_dynamic -nofor_main' ;;
+ ifc* | ifort*) # Intel Fortran compiler
+ tmp_addflag=' -nofor_main' ;;
+ lf95*) # Lahey Fortran 8.1
+ _LT_TAGVAR(whole_archive_flag_spec, $1)=
+ tmp_sharedflag='--shared' ;;
+ nagfor*) # NAGFOR 5.3
+ tmp_sharedflag='-Wl,-shared' ;;
+ xl[[cC]]* | bgxl[[cC]]* | mpixl[[cC]]*) # IBM XL C 8.0 on PPC (deal with xlf below)
+ tmp_sharedflag='-qmkshrobj'
+ tmp_addflag= ;;
+ nvcc*) # Cuda Compiler Driver 2.2
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive'
+ _LT_TAGVAR(compiler_needs_object, $1)=yes
+ ;;
+ esac
+ case `$CC -V 2>&1 | sed 5q` in
+ *Sun\ C*) # Sun C 5.9
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive'
+ _LT_TAGVAR(compiler_needs_object, $1)=yes
+ tmp_sharedflag='-G' ;;
+ *Sun\ F*) # Sun Fortran 8.3
+ tmp_sharedflag='-G' ;;
+ esac
+ _LT_TAGVAR(archive_cmds, $1)='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
+
+ if test yes = "$supports_anon_versioning"; then
+ _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~
+ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
+ echo "local: *; };" >> $output_objdir/$libname.ver~
+ $CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-version-script $wl$output_objdir/$libname.ver -o $lib'
+ fi
+
+ case $cc_basename in
+ tcc*)
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='-rdynamic'
+ ;;
+ xlf* | bgf* | bgxlf* | mpixlf*)
+ # IBM XL Fortran 10.1 on PPC cannot create shared libs itself
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='--whole-archive$convenience --no-whole-archive'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir'
+ _LT_TAGVAR(archive_cmds, $1)='$LD -shared $libobjs $deplibs $linker_flags -soname $soname -o $lib'
+ if test yes = "$supports_anon_versioning"; then
+ _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~
+ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
+ echo "local: *; };" >> $output_objdir/$libname.ver~
+ $LD -shared $libobjs $deplibs $linker_flags -soname $soname -version-script $output_objdir/$libname.ver -o $lib'
+ fi
+ ;;
+ esac
+ else
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ fi
+ ;;
+
+ netbsd* | netbsdelf*-gnu)
+ if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
+ _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib'
+ wlarc=
+ else
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib'
+ fi
+ ;;
+
+ solaris*)
+ if $LD -v 2>&1 | $GREP 'BFD 2\.8' > /dev/null; then
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ cat <<_LT_EOF 1>&2
+
+*** Warning: The releases 2.8.* of the GNU linker cannot reliably
+*** create shared libraries on Solaris systems. Therefore, libtool
+*** is disabling shared libraries support. We urge you to upgrade GNU
+*** binutils to release 2.9.1 or newer. Another option is to modify
+*** your PATH or compiler configuration so that the native linker is
+*** used, and then restart.
+
+_LT_EOF
+ elif $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib'
+ else
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ fi
+ ;;
+
+ sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*)
+ case `$LD -v 2>&1` in
+ *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.1[[0-5]].*)
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ cat <<_LT_EOF 1>&2
+
+*** Warning: Releases of the GNU linker prior to 2.16.91.0.3 cannot
+*** reliably create shared libraries on SCO systems. Therefore, libtool
+*** is disabling shared libraries support. We urge you to upgrade GNU
+*** binutils to release 2.16.91.0.3 or newer. Another option is to modify
+*** your PATH or compiler configuration so that the native linker is
+*** used, and then restart.
+
+_LT_EOF
+ ;;
+ *)
+ # For security reasons, it is highly recommended that you always
+ # use absolute paths for naming shared libraries, and exclude the
+ # DT_RUNPATH tag from executables and libraries. But doing so
+ # requires that you compile everything twice, which is a pain.
+ if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib'
+ else
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ fi
+ ;;
+ esac
+ ;;
+
+ sunos4*)
+ _LT_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+ wlarc=
+ _LT_TAGVAR(hardcode_direct, $1)=yes
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ ;;
+
+ *)
+ if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib'
+ else
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ fi
+ ;;
+ esac
+
+ if test no = "$_LT_TAGVAR(ld_shlibs, $1)"; then
+ runpath_var=
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)=
+ _LT_TAGVAR(whole_archive_flag_spec, $1)=
+ fi
+ else
+ # PORTME fill in a description of your system's linker (not GNU ld)
+ case $host_os in
+ aix3*)
+ _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+ _LT_TAGVAR(always_export_symbols, $1)=yes
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname'
+ # Note: this linker hardcodes the directories in LIBPATH if there
+ # are no directories specified by -L.
+ _LT_TAGVAR(hardcode_minus_L, $1)=yes
+ if test yes = "$GCC" && test -z "$lt_prog_compiler_static"; then
+ # Neither direct hardcoding nor static linking is supported with a
+ # broken collect2.
+ _LT_TAGVAR(hardcode_direct, $1)=unsupported
+ fi
+ ;;
+
+ aix[[4-9]]*)
+ if test ia64 = "$host_cpu"; then
+ # On IA64, the linker does run time linking by default, so we don't
+ # have to do anything special.
+ aix_use_runtimelinking=no
+ exp_sym_flag='-Bexport'
+ no_entry_flag=
+ else
+ # If we're using GNU nm, then we don't want the "-C" option.
+ # -C means demangle to GNU nm, but means don't demangle to AIX nm.
+ # Without the "-l" option, or with the "-B" option, AIX nm treats
+ # weak defined symbols like other global defined symbols, whereas
+ # GNU nm marks them as "W".
+ # While the 'weak' keyword is ignored in the Export File, we need
+ # it in the Import File for the 'aix-soname' feature, so we have
+ # to replace the "-B" option with "-P" for AIX nm.
+ if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then
+ _LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && ([substr](\$ 3,1,1) != ".")) { if (\$ 2 == "W") { print \$ 3 " weak" } else { print \$ 3 } } }'\'' | sort -u > $export_symbols'
+ else
+ _LT_TAGVAR(export_symbols_cmds, $1)='`func_echo_all $NM | $SED -e '\''s/B\([[^B]]*\)$/P\1/'\''` -PCpgl $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) && ([substr](\$ 1,1,1) != ".")) { if ((\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) { print \$ 1 " weak" } else { print \$ 1 } } }'\'' | sort -u > $export_symbols'
+ fi
+ aix_use_runtimelinking=no
+
+ # Test if we are trying to use run time linking or normal
+ # AIX style linking. If -brtl is somewhere in LDFLAGS, we
+ # have runtime linking enabled, and use it for executables.
+ # For shared libraries, we enable/disable runtime linking
+ # depending on the kind of the shared library created -
+ # when "with_aix_soname,aix_use_runtimelinking" is:
+ # "aix,no" lib.a(lib.so.V) shared, rtl:no, for executables
+ # "aix,yes" lib.so shared, rtl:yes, for executables
+ # lib.a static archive
+ # "both,no" lib.so.V(shr.o) shared, rtl:yes
+ # lib.a(lib.so.V) shared, rtl:no, for executables
+ # "both,yes" lib.so.V(shr.o) shared, rtl:yes, for executables
+ # lib.a(lib.so.V) shared, rtl:no
+ # "svr4,*" lib.so.V(shr.o) shared, rtl:yes, for executables
+ # lib.a static archive
+ case $host_os in aix4.[[23]]|aix4.[[23]].*|aix[[5-9]]*)
+ for ld_flag in $LDFLAGS; do
+ if (test x-brtl = "x$ld_flag" || test x-Wl,-brtl = "x$ld_flag"); then
+ aix_use_runtimelinking=yes
+ break
+ fi
+ done
+ if test svr4,no = "$with_aix_soname,$aix_use_runtimelinking"; then
+ # With aix-soname=svr4, we create the lib.so.V shared archives only,
+ # so we don't have lib.a shared libs to link our executables.
+ # We have to force runtime linking in this case.
+ aix_use_runtimelinking=yes
+ LDFLAGS="$LDFLAGS -Wl,-brtl"
+ fi
+ ;;
+ esac
+
+ exp_sym_flag='-bexport'
+ no_entry_flag='-bnoentry'
+ fi
+
+ # When large executables or shared objects are built, AIX ld can
+ # have problems creating the table of contents. If linking a library
+ # or program results in "error TOC overflow" add -mminimal-toc to
+ # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not
+ # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS.
+
+ _LT_TAGVAR(archive_cmds, $1)=''
+ _LT_TAGVAR(hardcode_direct, $1)=yes
+ _LT_TAGVAR(hardcode_direct_absolute, $1)=yes
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=':'
+ _LT_TAGVAR(link_all_deplibs, $1)=yes
+ _LT_TAGVAR(file_list_spec, $1)='$wl-f,'
+ case $with_aix_soname,$aix_use_runtimelinking in
+ aix,*) ;; # traditional, no import file
+ svr4,* | *,yes) # use import file
+ # The Import File defines what to hardcode.
+ _LT_TAGVAR(hardcode_direct, $1)=no
+ _LT_TAGVAR(hardcode_direct_absolute, $1)=no
+ ;;
+ esac
+
+ if test yes = "$GCC"; then
+ case $host_os in aix4.[[012]]|aix4.[[012]].*)
+ # We only want to do this on AIX 4.2 and lower, the check
+ # below for broken collect2 doesn't work under 4.3+
+ collect2name=`$CC -print-prog-name=collect2`
+ if test -f "$collect2name" &&
+ strings "$collect2name" | $GREP resolve_lib_name >/dev/null
+ then
+ # We have reworked collect2
+ :
+ else
+ # We have old collect2
+ _LT_TAGVAR(hardcode_direct, $1)=unsupported
+ # It fails to find uninstalled libraries when the uninstalled
+ # path is not listed in the libpath. Setting hardcode_minus_L
+ # to unsupported forces relinking
+ _LT_TAGVAR(hardcode_minus_L, $1)=yes
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=
+ fi
+ ;;
+ esac
+ shared_flag='-shared'
+ if test yes = "$aix_use_runtimelinking"; then
+ shared_flag="$shared_flag "'$wl-G'
+ fi
+ # Need to ensure runtime linking is disabled for the traditional
+ # shared library, or the linker may eventually find shared libraries
+ # /with/ Import File - we do not want to mix them.
+ shared_flag_aix='-shared'
+ shared_flag_svr4='-shared $wl-G'
+ else
+ # not using gcc
+ if test ia64 = "$host_cpu"; then
+ # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release
+ # chokes on -Wl,-G. The following line is correct:
+ shared_flag='-G'
+ else
+ if test yes = "$aix_use_runtimelinking"; then
+ shared_flag='$wl-G'
+ else
+ shared_flag='$wl-bM:SRE'
+ fi
+ shared_flag_aix='$wl-bM:SRE'
+ shared_flag_svr4='$wl-G'
+ fi
+ fi
+
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-bexpall'
+ # It seems that -bexpall does not export symbols beginning with
+ # underscore (_), so it is better to generate a list of symbols to export.
+ _LT_TAGVAR(always_export_symbols, $1)=yes
+ if test aix,yes = "$with_aix_soname,$aix_use_runtimelinking"; then
+ # Warning - without using the other runtime loading flags (-brtl),
+ # -berok will link without error, but may produce a broken library.
+ _LT_TAGVAR(allow_undefined_flag, $1)='-berok'
+ # Determine the default libpath from the value encoded in an
+ # empty executable.
+ _LT_SYS_MODULE_PATH_AIX([$1])
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-blibpath:$libdir:'"$aix_libpath"
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $deplibs $wl'$no_entry_flag' $compiler_flags `if test -n "$allow_undefined_flag"; then func_echo_all "$wl$allow_undefined_flag"; else :; fi` $wl'$exp_sym_flag:\$export_symbols' '$shared_flag
+ else
+ if test ia64 = "$host_cpu"; then
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-R $libdir:/usr/lib:/lib'
+ _LT_TAGVAR(allow_undefined_flag, $1)="-z nodefs"
+ _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\$wl$no_entry_flag"' $compiler_flags $wl$allow_undefined_flag '"\$wl$exp_sym_flag:\$export_symbols"
+ else
+ # Determine the default libpath from the value encoded in an
+ # empty executable.
+ _LT_SYS_MODULE_PATH_AIX([$1])
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-blibpath:$libdir:'"$aix_libpath"
+ # Warning - without using the other run time loading flags,
+ # -berok will link without error, but may produce a broken library.
+ _LT_TAGVAR(no_undefined_flag, $1)=' $wl-bernotok'
+ _LT_TAGVAR(allow_undefined_flag, $1)=' $wl-berok'
+ if test yes = "$with_gnu_ld"; then
+ # We only use this code for GNU lds that support --whole-archive.
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive$convenience $wl--no-whole-archive'
+ else
+ # Exported symbols can be pulled into shared objects from archives
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='$convenience'
+ fi
+ _LT_TAGVAR(archive_cmds_need_lc, $1)=yes
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$RM -r $output_objdir/$realname.d~$MKDIR $output_objdir/$realname.d'
+ # -brtl affects multiple linker settings, -berok does not and is overridden later
+ compiler_flags_filtered='`func_echo_all "$compiler_flags " | $SED -e "s%-brtl\\([[, ]]\\)%-berok\\1%g"`'
+ if test svr4 != "$with_aix_soname"; then
+ # This is similar to how AIX traditionally builds its shared libraries.
+ _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$CC '$shared_flag_aix' -o $output_objdir/$realname.d/$soname $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$realname.d/$soname'
+ fi
+ if test aix != "$with_aix_soname"; then
+ _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$CC '$shared_flag_svr4' -o $output_objdir/$realname.d/$shared_archive_member_spec.o $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$STRIP -e $output_objdir/$realname.d/$shared_archive_member_spec.o~( func_echo_all "#! $soname($shared_archive_member_spec.o)"; if test shr_64 = "$shared_archive_member_spec"; then func_echo_all "# 64"; else func_echo_all "# 32"; fi; cat $export_symbols ) > $output_objdir/$realname.d/$shared_archive_member_spec.imp~$AR $AR_FLAGS $output_objdir/$soname $output_objdir/$realname.d/$shared_archive_member_spec.o $output_objdir/$realname.d/$shared_archive_member_spec.imp'
+ else
+ # used by -dlpreopen to get the symbols
+ _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$MV $output_objdir/$realname.d/$soname $output_objdir'
+ fi
+ _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$RM -r $output_objdir/$realname.d'
+ fi
+ fi
+ ;;
+
+ amigaos*)
+ case $host_cpu in
+ powerpc)
+ # see comment about AmigaOS4 .so support
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)=''
+ ;;
+ m68k)
+ _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+ _LT_TAGVAR(hardcode_minus_L, $1)=yes
+ ;;
+ esac
+ ;;
+
+ bsdi[[45]]*)
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)=-rdynamic
+ ;;
+
+ cygwin* | mingw* | pw32* | cegcc*)
+ # When not using gcc, we currently assume that we are using
+ # Microsoft Visual C++.
+ # hardcode_libdir_flag_spec is actually meaningless, as there is
+ # no search path for DLLs.
+ case $cc_basename in
+ cl*)
+ # Native MSVC
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' '
+ _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+ _LT_TAGVAR(always_export_symbols, $1)=yes
+ _LT_TAGVAR(file_list_spec, $1)='@'
+ # Tell ltmain to make .lib files, not .a files.
+ libext=lib
+ # Tell ltmain to make .dll files, not .so files.
+ shrext_cmds=.dll
+ # FIXME: Setting linknames here is a bad hack.
+ _LT_TAGVAR(archive_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~linknames='
+ _LT_TAGVAR(archive_expsym_cmds, $1)='if _LT_DLL_DEF_P([$export_symbols]); then
+ cp "$export_symbols" "$output_objdir/$soname.def";
+ echo "$tool_output_objdir$soname.def" > "$output_objdir/$soname.exp";
+ else
+ $SED -e '\''s/^/-link -EXPORT:/'\'' < $export_symbols > $output_objdir/$soname.exp;
+ fi~
+ $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~
+ linknames='
+ # The linker will not automatically build a static lib if we build a DLL.
+ # _LT_TAGVAR(old_archive_from_new_cmds, $1)='true'
+ _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
+ _LT_TAGVAR(exclude_expsyms, $1)='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*'
+ _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1,DATA/'\'' | $SED -e '\''/^[[AITW]][[ ]]/s/.*[[ ]]//'\'' | sort | uniq > $export_symbols'
+ # Don't use ranlib
+ _LT_TAGVAR(old_postinstall_cmds, $1)='chmod 644 $oldlib'
+ _LT_TAGVAR(postlink_cmds, $1)='lt_outputfile="@OUTPUT@"~
+ lt_tool_outputfile="@TOOL_OUTPUT@"~
+ case $lt_outputfile in
+ *.exe|*.EXE) ;;
+ *)
+ lt_outputfile=$lt_outputfile.exe
+ lt_tool_outputfile=$lt_tool_outputfile.exe
+ ;;
+ esac~
+ if test : != "$MANIFEST_TOOL" && test -f "$lt_outputfile.manifest"; then
+ $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1;
+ $RM "$lt_outputfile.manifest";
+ fi'
+ ;;
+ *)
+ # Assume MSVC wrapper
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' '
+ _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+ # Tell ltmain to make .lib files, not .a files.
+ libext=lib
+ # Tell ltmain to make .dll files, not .so files.
+ shrext_cmds=.dll
+ # FIXME: Setting linknames here is a bad hack.
+ _LT_TAGVAR(archive_cmds, $1)='$CC -o $lib $libobjs $compiler_flags `func_echo_all "$deplibs" | $SED '\''s/ -lc$//'\''` -link -dll~linknames='
+ # The linker will automatically build a .lib file if we build a DLL.
+ _LT_TAGVAR(old_archive_from_new_cmds, $1)='true'
+ # FIXME: Should let the user specify the lib program.
+ _LT_TAGVAR(old_archive_cmds, $1)='lib -OUT:$oldlib$oldobjs$old_deplibs'
+ _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
+ ;;
+ esac
+ ;;
+
+ darwin* | rhapsody*)
+ _LT_DARWIN_LINKER_FEATURES($1)
+ ;;
+
+ dgux*)
+ _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ ;;
+
+ # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor
+ # support. Future versions do this automatically, but an explicit c++rt0.o
+ # does not break anything, and helps significantly (at the cost of a little
+ # extra space).
+ freebsd2.2*)
+ _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+ _LT_TAGVAR(hardcode_direct, $1)=yes
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ ;;
+
+ # Unfortunately, older versions of FreeBSD 2 do not have this feature.
+ freebsd2.*)
+ _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+ _LT_TAGVAR(hardcode_direct, $1)=yes
+ _LT_TAGVAR(hardcode_minus_L, $1)=yes
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ ;;
+
+ # FreeBSD 3 and greater uses gcc -shared to do shared libraries.
+ freebsd* | dragonfly*)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+ _LT_TAGVAR(hardcode_direct, $1)=yes
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ ;;
+
+ hpux9*)
+ if test yes = "$GCC"; then
+ _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -shared $pic_flag $wl+b $wl$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test "x$output_objdir/$soname" = "x$lib" || mv $output_objdir/$soname $lib'
+ else
+ _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test "x$output_objdir/$soname" = "x$lib" || mv $output_objdir/$soname $lib'
+ fi
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl+b $wl$libdir'
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+ _LT_TAGVAR(hardcode_direct, $1)=yes
+
+ # hardcode_minus_L: Not really in the search PATH,
+ # but as the default location of the library.
+ _LT_TAGVAR(hardcode_minus_L, $1)=yes
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E'
+ ;;
+
+ hpux10*)
+ if test yes,no = "$GCC,$with_gnu_ld"; then
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
+ else
+ _LT_TAGVAR(archive_cmds, $1)='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags'
+ fi
+ if test no = "$with_gnu_ld"; then
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl+b $wl$libdir'
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+ _LT_TAGVAR(hardcode_direct, $1)=yes
+ _LT_TAGVAR(hardcode_direct_absolute, $1)=yes
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E'
+ # hardcode_minus_L: Not really in the search PATH,
+ # but as the default location of the library.
+ _LT_TAGVAR(hardcode_minus_L, $1)=yes
+ fi
+ ;;
+
+ hpux11*)
+ if test yes,no = "$GCC,$with_gnu_ld"; then
+ case $host_cpu in
+ hppa*64*)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $wl+h $wl$soname -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ ia64*)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $wl+h $wl$soname $wl+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ *)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ esac
+ else
+ case $host_cpu in
+ hppa*64*)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -b $wl+h $wl$soname -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ ia64*)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -b $wl+h $wl$soname $wl+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ *)
+ m4_if($1, [], [
+ # Older versions of the 11.00 compiler do not understand -b yet
+ # (HP92453-01 A.11.01.20 doesn't, HP92453-01 B.11.X.35175-35176.GP does)
+ _LT_LINKER_OPTION([if $CC understands -b],
+ _LT_TAGVAR(lt_cv_prog_compiler__b, $1), [-b],
+ [_LT_TAGVAR(archive_cmds, $1)='$CC -b $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $libobjs $deplibs $compiler_flags'],
+ [_LT_TAGVAR(archive_cmds, $1)='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags'])],
+ [_LT_TAGVAR(archive_cmds, $1)='$CC -b $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $libobjs $deplibs $compiler_flags'])
+ ;;
+ esac
+ fi
+ if test no = "$with_gnu_ld"; then
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl+b $wl$libdir'
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+
+ case $host_cpu in
+ hppa*64*|ia64*)
+ _LT_TAGVAR(hardcode_direct, $1)=no
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ ;;
+ *)
+ _LT_TAGVAR(hardcode_direct, $1)=yes
+ _LT_TAGVAR(hardcode_direct_absolute, $1)=yes
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E'
+
+ # hardcode_minus_L: Not really in the search PATH,
+ # but as the default location of the library.
+ _LT_TAGVAR(hardcode_minus_L, $1)=yes
+ ;;
+ esac
+ fi
+ ;;
+
+ irix5* | irix6* | nonstopux*)
+ if test yes = "$GCC"; then
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib'
+ # Try to use the -exported_symbol ld option, if it does not
+ # work, assume that -exports_file does not work either and
+ # implicitly export all symbols.
+ # This should be the same for all languages, so no per-tag cache variable.
+ AC_CACHE_CHECK([whether the $host_os linker accepts -exported_symbol],
+ [lt_cv_irix_exported_symbol],
+ [save_LDFLAGS=$LDFLAGS
+ LDFLAGS="$LDFLAGS -shared $wl-exported_symbol ${wl}foo $wl-update_registry $wl/dev/null"
+ AC_LINK_IFELSE(
+ [AC_LANG_SOURCE(
+ [AC_LANG_CASE([C], [[int foo (void) { return 0; }]],
+ [C++], [[int foo (void) { return 0; }]],
+ [Fortran 77], [[
+ subroutine foo
+ end]],
+ [Fortran], [[
+ subroutine foo
+ end]])])],
+ [lt_cv_irix_exported_symbol=yes],
+ [lt_cv_irix_exported_symbol=no])
+ LDFLAGS=$save_LDFLAGS])
+ if test yes = "$lt_cv_irix_exported_symbol"; then
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations $wl-exports_file $wl$export_symbols -o $lib'
+ fi
+ _LT_TAGVAR(link_all_deplibs, $1)=no
+ else
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -exports_file $export_symbols -o $lib'
+ fi
+ _LT_TAGVAR(archive_cmds_need_lc, $1)='no'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir'
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+ _LT_TAGVAR(inherit_rpath, $1)=yes
+ _LT_TAGVAR(link_all_deplibs, $1)=yes
+ ;;
+
+ linux*)
+ case $cc_basename in
+ tcc*)
+ # Fabrice Bellard et al's Tiny C Compiler
+ _LT_TAGVAR(ld_shlibs, $1)=yes
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ esac
+ ;;
+
+ netbsd* | netbsdelf*-gnu)
+ if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
+ _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out
+ else
+ _LT_TAGVAR(archive_cmds, $1)='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF
+ fi
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+ _LT_TAGVAR(hardcode_direct, $1)=yes
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ ;;
+
+ newsos6)
+ _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ _LT_TAGVAR(hardcode_direct, $1)=yes
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir'
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ ;;
+
+ *nto* | *qnx*)
+ ;;
+
+ openbsd* | bitrig*)
+ if test -f /usr/libexec/ld.so; then
+ _LT_TAGVAR(hardcode_direct, $1)=yes
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ _LT_TAGVAR(hardcode_direct_absolute, $1)=yes
+ if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`"; then
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags $wl-retain-symbols-file,$export_symbols'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir'
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E'
+ else
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir'
+ fi
+ else
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ fi
+ ;;
+
+ os2*)
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+ _LT_TAGVAR(hardcode_minus_L, $1)=yes
+ _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+ shrext_cmds=.dll
+ _LT_TAGVAR(archive_cmds, $1)='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~
+ $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~
+ $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~
+ $ECHO EXPORTS >> $output_objdir/$libname.def~
+ emxexp $libobjs | $SED /"_DLL_InitTerm"/d >> $output_objdir/$libname.def~
+ $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~
+ emximp -o $lib $output_objdir/$libname.def'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~
+ $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~
+ $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~
+ $ECHO EXPORTS >> $output_objdir/$libname.def~
+ prefix_cmds="$SED"~
+ if test EXPORTS = "`$SED 1q $export_symbols`"; then
+ prefix_cmds="$prefix_cmds -e 1d";
+ fi~
+ prefix_cmds="$prefix_cmds -e \"s/^\(.*\)$/_\1/g\""~
+ cat $export_symbols | $prefix_cmds >> $output_objdir/$libname.def~
+ $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~
+ emximp -o $lib $output_objdir/$libname.def'
+ _LT_TAGVAR(old_archive_From_new_cmds, $1)='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def'
+ _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
+ ;;
+
+ osf3*)
+ if test yes = "$GCC"; then
+ _LT_TAGVAR(allow_undefined_flag, $1)=' $wl-expect_unresolved $wl\*'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared$allow_undefined_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib'
+ else
+ _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared$allow_undefined_flag $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib'
+ fi
+ _LT_TAGVAR(archive_cmds_need_lc, $1)='no'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir'
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+ ;;
+
+ osf4* | osf5*) # as osf3* with the addition of -msym flag
+ if test yes = "$GCC"; then
+ _LT_TAGVAR(allow_undefined_flag, $1)=' $wl-expect_unresolved $wl\*'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared$allow_undefined_flag $pic_flag $libobjs $deplibs $compiler_flags $wl-msym $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir'
+ else
+ _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared$allow_undefined_flag $libobjs $deplibs $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; printf "%s\\n" "-hidden">> $lib.exp~
+ $CC -shared$allow_undefined_flag $wl-input $wl$lib.exp $compiler_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib~$RM $lib.exp'
+
+ # Both c and cxx compiler support -rpath directly
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir'
+ fi
+ _LT_TAGVAR(archive_cmds_need_lc, $1)='no'
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+ ;;
+
+ solaris*)
+ _LT_TAGVAR(no_undefined_flag, $1)=' -z defs'
+ if test yes = "$GCC"; then
+ wlarc='$wl'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $wl-z ${wl}text $wl-h $wl$soname -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+ $CC -shared $pic_flag $wl-z ${wl}text $wl-M $wl$lib.exp $wl-h $wl$soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp'
+ else
+ case `$CC -V 2>&1` in
+ *"Compilers 5.0"*)
+ wlarc=''
+ _LT_TAGVAR(archive_cmds, $1)='$LD -G$allow_undefined_flag -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+ $LD -G$allow_undefined_flag -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$RM $lib.exp'
+ ;;
+ *)
+ wlarc='$wl'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -G$allow_undefined_flag -h $soname -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+ $CC -G$allow_undefined_flag -M $lib.exp -h $soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp'
+ ;;
+ esac
+ fi
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ case $host_os in
+ solaris2.[[0-5]] | solaris2.[[0-5]].*) ;;
+ *)
+ # The compiler driver will combine and reorder linker options,
+ # but understands '-z linker_flag'. GCC discards it without '$wl',
+ # but is careful enough not to reorder.
+ # Supported since Solaris 2.6 (maybe 2.5.1?)
+ if test yes = "$GCC"; then
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl-z ${wl}allextract$convenience $wl-z ${wl}defaultextract'
+ else
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract'
+ fi
+ ;;
+ esac
+ _LT_TAGVAR(link_all_deplibs, $1)=yes
+ ;;
+
+ sunos4*)
+ if test sequent = "$host_vendor"; then
+ # Use $CC to link under sequent, because it throws in some extra .o
+ # files that make .init and .fini sections work.
+ _LT_TAGVAR(archive_cmds, $1)='$CC -G $wl-h $soname -o $lib $libobjs $deplibs $compiler_flags'
+ else
+ _LT_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags'
+ fi
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+ _LT_TAGVAR(hardcode_direct, $1)=yes
+ _LT_TAGVAR(hardcode_minus_L, $1)=yes
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ ;;
+
+ sysv4)
+ case $host_vendor in
+ sni)
+ _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ _LT_TAGVAR(hardcode_direct, $1)=yes # is this really true???
+ ;;
+ siemens)
+ ## LD is ld it makes a PLAMLIB
+ ## CC just makes a GrossModule.
+ _LT_TAGVAR(archive_cmds, $1)='$LD -G -o $lib $libobjs $deplibs $linker_flags'
+ _LT_TAGVAR(reload_cmds, $1)='$CC -r -o $output$reload_objs'
+ _LT_TAGVAR(hardcode_direct, $1)=no
+ ;;
+ motorola)
+ _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ _LT_TAGVAR(hardcode_direct, $1)=no #Motorola manual says yes, but my tests say they lie
+ ;;
+ esac
+ runpath_var='LD_RUN_PATH'
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ ;;
+
+ sysv4.3*)
+ _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='-Bexport'
+ ;;
+
+ sysv4*MP*)
+ if test -d /usr/nec; then
+ _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ runpath_var=LD_RUN_PATH
+ hardcode_runpath_var=yes
+ _LT_TAGVAR(ld_shlibs, $1)=yes
+ fi
+ ;;
+
+ sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7* | sco3.2v5.0.[[024]]*)
+ _LT_TAGVAR(no_undefined_flag, $1)='$wl-z,text'
+ _LT_TAGVAR(archive_cmds_need_lc, $1)=no
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ runpath_var='LD_RUN_PATH'
+
+ if test yes = "$GCC"; then
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ else
+ _LT_TAGVAR(archive_cmds, $1)='$CC -G $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ fi
+ ;;
+
+ sysv5* | sco3.2v5* | sco5v6*)
+ # Note: We CANNOT use -z defs as we might desire, because we do not
+ # link with -lc, and that would cause any symbols used from libc to
+ # always be unresolved, which means just about no library would
+ # ever link correctly. If we're not using GNU ld we use -z text
+ # though, which does catch some bad symbols but isn't as heavy-handed
+ # as -z defs.
+ _LT_TAGVAR(no_undefined_flag, $1)='$wl-z,text'
+ _LT_TAGVAR(allow_undefined_flag, $1)='$wl-z,nodefs'
+ _LT_TAGVAR(archive_cmds_need_lc, $1)=no
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-R,$libdir'
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=':'
+ _LT_TAGVAR(link_all_deplibs, $1)=yes
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-Bexport'
+ runpath_var='LD_RUN_PATH'
+
+ if test yes = "$GCC"; then
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ else
+ _LT_TAGVAR(archive_cmds, $1)='$CC -G $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ fi
+ ;;
+
+ uts4*)
+ _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ ;;
+
+ *)
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ esac
+
+ if test sni = "$host_vendor"; then
+ case $host in
+ sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*)
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-Blargedynsym'
+ ;;
+ esac
+ fi
+ fi
+])
+AC_MSG_RESULT([$_LT_TAGVAR(ld_shlibs, $1)])
+test no = "$_LT_TAGVAR(ld_shlibs, $1)" && can_build_shared=no
+
+_LT_TAGVAR(with_gnu_ld, $1)=$with_gnu_ld
+
+_LT_DECL([], [libext], [0], [Old archive suffix (normally "a")])dnl
+_LT_DECL([], [shrext_cmds], [1], [Shared library suffix (normally ".so")])dnl
+_LT_DECL([], [extract_expsyms_cmds], [2],
+ [The commands to extract the exported symbol list from a shared archive])
+
+#
+# Do we need to explicitly link libc?
+#
+case "x$_LT_TAGVAR(archive_cmds_need_lc, $1)" in
+x|xyes)
+ # Assume -lc should be added
+ _LT_TAGVAR(archive_cmds_need_lc, $1)=yes
+
+ if test yes,yes = "$GCC,$enable_shared"; then
+ case $_LT_TAGVAR(archive_cmds, $1) in
+ *'~'*)
+ # FIXME: we may have to deal with multi-command sequences.
+ ;;
+ '$CC '*)
+ # Test whether the compiler implicitly links with -lc since on some
+ # systems, -lgcc has to come before -lc. If gcc already passes -lc
+ # to ld, don't add -lc before -lgcc.
+ AC_CACHE_CHECK([whether -lc should be explicitly linked in],
+ [lt_cv_]_LT_TAGVAR(archive_cmds_need_lc, $1),
+ [$RM conftest*
+ echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+
+ if AC_TRY_EVAL(ac_compile) 2>conftest.err; then
+ soname=conftest
+ lib=conftest
+ libobjs=conftest.$ac_objext
+ deplibs=
+ wl=$_LT_TAGVAR(lt_prog_compiler_wl, $1)
+ pic_flag=$_LT_TAGVAR(lt_prog_compiler_pic, $1)
+ compiler_flags=-v
+ linker_flags=-v
+ verstring=
+ output_objdir=.
+ libname=conftest
+ lt_save_allow_undefined_flag=$_LT_TAGVAR(allow_undefined_flag, $1)
+ _LT_TAGVAR(allow_undefined_flag, $1)=
+ if AC_TRY_EVAL(_LT_TAGVAR(archive_cmds, $1) 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1)
+ then
+ lt_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1)=no
+ else
+ lt_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1)=yes
+ fi
+ _LT_TAGVAR(allow_undefined_flag, $1)=$lt_save_allow_undefined_flag
+ else
+ cat conftest.err 1>&5
+ fi
+ $RM conftest*
+ ])
+ _LT_TAGVAR(archive_cmds_need_lc, $1)=$lt_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1)
+ ;;
+ esac
+ fi
+ ;;
+esac
+
+_LT_TAGDECL([build_libtool_need_lc], [archive_cmds_need_lc], [0],
+ [Whether or not to add -lc for building shared libraries])
+_LT_TAGDECL([allow_libtool_libs_with_static_runtimes],
+ [enable_shared_with_static_runtimes], [0],
+ [Whether or not to disallow shared libs when runtime libs are static])
+_LT_TAGDECL([], [export_dynamic_flag_spec], [1],
+ [Compiler flag to allow reflexive dlopens])
+_LT_TAGDECL([], [whole_archive_flag_spec], [1],
+ [Compiler flag to generate shared objects directly from archives])
+_LT_TAGDECL([], [compiler_needs_object], [1],
+ [Whether the compiler copes with passing no objects directly])
+_LT_TAGDECL([], [old_archive_from_new_cmds], [2],
+ [Create an old-style archive from a shared archive])
+_LT_TAGDECL([], [old_archive_from_expsyms_cmds], [2],
+ [Create a temporary old-style archive to link instead of a shared archive])
+_LT_TAGDECL([], [archive_cmds], [2], [Commands used to build a shared archive])
+_LT_TAGDECL([], [archive_expsym_cmds], [2])
+_LT_TAGDECL([], [module_cmds], [2],
+ [Commands used to build a loadable module if different from building
+ a shared archive.])
+_LT_TAGDECL([], [module_expsym_cmds], [2])
+_LT_TAGDECL([], [with_gnu_ld], [1],
+ [Whether we are building with GNU ld or not])
+_LT_TAGDECL([], [allow_undefined_flag], [1],
+ [Flag that allows shared libraries with undefined symbols to be built])
+_LT_TAGDECL([], [no_undefined_flag], [1],
+ [Flag that enforces no undefined symbols])
+_LT_TAGDECL([], [hardcode_libdir_flag_spec], [1],
+ [Flag to hardcode $libdir into a binary during linking.
+ This must work even if $libdir does not exist])
+_LT_TAGDECL([], [hardcode_libdir_separator], [1],
+ [Whether we need a single "-rpath" flag with a separated argument])
+_LT_TAGDECL([], [hardcode_direct], [0],
+ [Set to "yes" if using DIR/libNAME$shared_ext during linking hardcodes
+ DIR into the resulting binary])
+_LT_TAGDECL([], [hardcode_direct_absolute], [0],
+ [Set to "yes" if using DIR/libNAME$shared_ext during linking hardcodes
+ DIR into the resulting binary and the resulting library dependency is
+ "absolute", i.e impossible to change by setting $shlibpath_var if the
+ library is relocated])
+_LT_TAGDECL([], [hardcode_minus_L], [0],
+ [Set to "yes" if using the -LDIR flag during linking hardcodes DIR
+ into the resulting binary])
+_LT_TAGDECL([], [hardcode_shlibpath_var], [0],
+ [Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR
+ into the resulting binary])
+_LT_TAGDECL([], [hardcode_automatic], [0],
+ [Set to "yes" if building a shared library automatically hardcodes DIR
+ into the library and all subsequent libraries and executables linked
+ against it])
+_LT_TAGDECL([], [inherit_rpath], [0],
+ [Set to yes if linker adds runtime paths of dependent libraries
+ to runtime path list])
+_LT_TAGDECL([], [link_all_deplibs], [0],
+ [Whether libtool must link a program against all its dependency libraries])
+_LT_TAGDECL([], [always_export_symbols], [0],
+ [Set to "yes" if exported symbols are required])
+_LT_TAGDECL([], [export_symbols_cmds], [2],
+ [The commands to list exported symbols])
+_LT_TAGDECL([], [exclude_expsyms], [1],
+ [Symbols that should not be listed in the preloaded symbols])
+_LT_TAGDECL([], [include_expsyms], [1],
+ [Symbols that must always be exported])
+_LT_TAGDECL([], [prelink_cmds], [2],
+ [Commands necessary for linking programs (against libraries) with templates])
+_LT_TAGDECL([], [postlink_cmds], [2],
+ [Commands necessary for finishing linking programs])
+_LT_TAGDECL([], [file_list_spec], [1],
+ [Specify filename containing input files])
+dnl FIXME: Not yet implemented
+dnl _LT_TAGDECL([], [thread_safe_flag_spec], [1],
+dnl [Compiler flag to generate thread safe objects])
+])# _LT_LINKER_SHLIBS
+
+
+# _LT_LANG_C_CONFIG([TAG])
+# ------------------------
+# Ensure that the configuration variables for a C compiler are suitably
+# defined. These variables are subsequently used by _LT_CONFIG to write
+# the compiler configuration to 'libtool'.
+m4_defun([_LT_LANG_C_CONFIG],
+[m4_require([_LT_DECL_EGREP])dnl
+lt_save_CC=$CC
+AC_LANG_PUSH(C)
+
+# Source file extension for C test sources.
+ac_ext=c
+
+# Object file extension for compiled C test sources.
+objext=o
+_LT_TAGVAR(objext, $1)=$objext
+
+# Code to be used in simple compile tests
+lt_simple_compile_test_code="int some_variable = 0;"
+
+# Code to be used in simple link tests
+lt_simple_link_test_code='int main(){return(0);}'
+
+_LT_TAG_COMPILER
+# Save the default compiler, since it gets overwritten when the other
+# tags are being tested, and _LT_TAGVAR(compiler, []) is a NOP.
+compiler_DEFAULT=$CC
+
+# save warnings/boilerplate of simple test code
+_LT_COMPILER_BOILERPLATE
+_LT_LINKER_BOILERPLATE
+
+## CAVEAT EMPTOR:
+## There is no encapsulation within the following macros, do not change
+## the running order or otherwise move them around unless you know exactly
+## what you are doing...
+if test -n "$compiler"; then
+ _LT_COMPILER_NO_RTTI($1)
+ _LT_COMPILER_PIC($1)
+ _LT_COMPILER_C_O($1)
+ _LT_COMPILER_FILE_LOCKS($1)
+ _LT_LINKER_SHLIBS($1)
+ _LT_SYS_DYNAMIC_LINKER($1)
+ _LT_LINKER_HARDCODE_LIBPATH($1)
+ LT_SYS_DLOPEN_SELF
+ _LT_CMD_STRIPLIB
+
+ # Report what library types will actually be built
+ AC_MSG_CHECKING([if libtool supports shared libraries])
+ AC_MSG_RESULT([$can_build_shared])
+
+ AC_MSG_CHECKING([whether to build shared libraries])
+ test no = "$can_build_shared" && enable_shared=no
+
+ # On AIX, shared libraries and static libraries use the same namespace, and
+ # are all built from PIC.
+ case $host_os in
+ aix3*)
+ test yes = "$enable_shared" && enable_static=no
+ if test -n "$RANLIB"; then
+ archive_cmds="$archive_cmds~\$RANLIB \$lib"
+ postinstall_cmds='$RANLIB $lib'
+ fi
+ ;;
+
+ aix[[4-9]]*)
+ if test ia64 != "$host_cpu"; then
+ case $enable_shared,$with_aix_soname,$aix_use_runtimelinking in
+ yes,aix,yes) ;; # shared object as lib.so file only
+ yes,svr4,*) ;; # shared object as lib.so archive member only
+ yes,*) enable_static=no ;; # shared object in lib.a archive as well
+ esac
+ fi
+ ;;
+ esac
+ AC_MSG_RESULT([$enable_shared])
+
+ AC_MSG_CHECKING([whether to build static libraries])
+ # Make sure either enable_shared or enable_static is yes.
+ test yes = "$enable_shared" || enable_static=yes
+ AC_MSG_RESULT([$enable_static])
+
+ _LT_CONFIG($1)
+fi
+AC_LANG_POP
+CC=$lt_save_CC
+])# _LT_LANG_C_CONFIG
+
+
+# _LT_LANG_CXX_CONFIG([TAG])
+# --------------------------
+# Ensure that the configuration variables for a C++ compiler are suitably
+# defined. These variables are subsequently used by _LT_CONFIG to write
+# the compiler configuration to 'libtool'.
+m4_defun([_LT_LANG_CXX_CONFIG],
+[m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+m4_require([_LT_DECL_EGREP])dnl
+m4_require([_LT_PATH_MANIFEST_TOOL])dnl
+if test -n "$CXX" && ( test no != "$CXX" &&
+ ( (test g++ = "$CXX" && `g++ -v >/dev/null 2>&1` ) ||
+ (test g++ != "$CXX"))); then
+ AC_PROG_CXXCPP
+else
+ _lt_caught_CXX_error=yes
+fi
+
+AC_LANG_PUSH(C++)
+_LT_TAGVAR(archive_cmds_need_lc, $1)=no
+_LT_TAGVAR(allow_undefined_flag, $1)=
+_LT_TAGVAR(always_export_symbols, $1)=no
+_LT_TAGVAR(archive_expsym_cmds, $1)=
+_LT_TAGVAR(compiler_needs_object, $1)=no
+_LT_TAGVAR(export_dynamic_flag_spec, $1)=
+_LT_TAGVAR(hardcode_direct, $1)=no
+_LT_TAGVAR(hardcode_direct_absolute, $1)=no
+_LT_TAGVAR(hardcode_libdir_flag_spec, $1)=
+_LT_TAGVAR(hardcode_libdir_separator, $1)=
+_LT_TAGVAR(hardcode_minus_L, $1)=no
+_LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported
+_LT_TAGVAR(hardcode_automatic, $1)=no
+_LT_TAGVAR(inherit_rpath, $1)=no
+_LT_TAGVAR(module_cmds, $1)=
+_LT_TAGVAR(module_expsym_cmds, $1)=
+_LT_TAGVAR(link_all_deplibs, $1)=unknown
+_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds
+_LT_TAGVAR(reload_flag, $1)=$reload_flag
+_LT_TAGVAR(reload_cmds, $1)=$reload_cmds
+_LT_TAGVAR(no_undefined_flag, $1)=
+_LT_TAGVAR(whole_archive_flag_spec, $1)=
+_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no
+
+# Source file extension for C++ test sources.
+ac_ext=cpp
+
+# Object file extension for compiled C++ test sources.
+objext=o
+_LT_TAGVAR(objext, $1)=$objext
+
+# No sense in running all these tests if we already determined that
+# the CXX compiler isn't working. Some variables (like enable_shared)
+# are currently assumed to apply to all compilers on this platform,
+# and will be corrupted by setting them based on a non-working compiler.
+if test yes != "$_lt_caught_CXX_error"; then
+ # Code to be used in simple compile tests
+ lt_simple_compile_test_code="int some_variable = 0;"
+
+ # Code to be used in simple link tests
+ lt_simple_link_test_code='int main(int, char *[[]]) { return(0); }'
+
+ # ltmain only uses $CC for tagged configurations so make sure $CC is set.
+ _LT_TAG_COMPILER
+
+ # save warnings/boilerplate of simple test code
+ _LT_COMPILER_BOILERPLATE
+ _LT_LINKER_BOILERPLATE
+
+ # Allow CC to be a program name with arguments.
+ lt_save_CC=$CC
+ lt_save_CFLAGS=$CFLAGS
+ lt_save_LD=$LD
+ lt_save_GCC=$GCC
+ GCC=$GXX
+ lt_save_with_gnu_ld=$with_gnu_ld
+ lt_save_path_LD=$lt_cv_path_LD
+ if test -n "${lt_cv_prog_gnu_ldcxx+set}"; then
+ lt_cv_prog_gnu_ld=$lt_cv_prog_gnu_ldcxx
+ else
+ $as_unset lt_cv_prog_gnu_ld
+ fi
+ if test -n "${lt_cv_path_LDCXX+set}"; then
+ lt_cv_path_LD=$lt_cv_path_LDCXX
+ else
+ $as_unset lt_cv_path_LD
+ fi
+ test -z "${LDCXX+set}" || LD=$LDCXX
+ CC=${CXX-"c++"}
+ CFLAGS=$CXXFLAGS
+ compiler=$CC
+ _LT_TAGVAR(compiler, $1)=$CC
+ _LT_CC_BASENAME([$compiler])
+
+ if test -n "$compiler"; then
+ # We don't want -fno-exception when compiling C++ code, so set the
+ # no_builtin_flag separately
+ if test yes = "$GXX"; then
+ _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin'
+ else
+ _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=
+ fi
+
+ if test yes = "$GXX"; then
+ # Set up default GNU C++ configuration
+
+ LT_PATH_LD
+
+ # Check if GNU C++ uses GNU ld as the underlying linker, since the
+ # archiving commands below assume that GNU ld is being used.
+ if test yes = "$with_gnu_ld"; then
+ _LT_TAGVAR(archive_cmds, $1)='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib'
+
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir'
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-dynamic'
+
+ # If archive_cmds runs LD, not CC, wlarc should be empty
+ # XXX I think wlarc can be eliminated in ltcf-cxx, but I need to
+ # investigate it a little bit more. (MM)
+ wlarc='$wl'
+
+ # ancient GNU ld didn't support --whole-archive et. al.
+ if eval "`$CC -print-prog-name=ld` --help 2>&1" |
+ $GREP 'no-whole-archive' > /dev/null; then
+ _LT_TAGVAR(whole_archive_flag_spec, $1)=$wlarc'--whole-archive$convenience '$wlarc'--no-whole-archive'
+ else
+ _LT_TAGVAR(whole_archive_flag_spec, $1)=
+ fi
+ else
+ with_gnu_ld=no
+ wlarc=
+
+ # A generic and very simple default shared library creation
+ # command for GNU C++ for the case where it uses the native
+ # linker, instead of GNU ld. If possible, this setting should
+ # overridden to take advantage of the native linker features on
+ # the platform it is being used on.
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib'
+ fi
+
+ # Commands to make compiler produce verbose output that lists
+ # what "hidden" libraries, object files and flags are used when
+ # linking a shared library.
+ output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"'
+
+ else
+ GXX=no
+ with_gnu_ld=no
+ wlarc=
+ fi
+
+ # PORTME: fill in a description of your system's C++ link characteristics
+ AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries])
+ _LT_TAGVAR(ld_shlibs, $1)=yes
+ case $host_os in
+ aix3*)
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ aix[[4-9]]*)
+ if test ia64 = "$host_cpu"; then
+ # On IA64, the linker does run time linking by default, so we don't
+ # have to do anything special.
+ aix_use_runtimelinking=no
+ exp_sym_flag='-Bexport'
+ no_entry_flag=
+ else
+ aix_use_runtimelinking=no
+
+ # Test if we are trying to use run time linking or normal
+ # AIX style linking. If -brtl is somewhere in LDFLAGS, we
+ # have runtime linking enabled, and use it for executables.
+ # For shared libraries, we enable/disable runtime linking
+ # depending on the kind of the shared library created -
+ # when "with_aix_soname,aix_use_runtimelinking" is:
+ # "aix,no" lib.a(lib.so.V) shared, rtl:no, for executables
+ # "aix,yes" lib.so shared, rtl:yes, for executables
+ # lib.a static archive
+ # "both,no" lib.so.V(shr.o) shared, rtl:yes
+ # lib.a(lib.so.V) shared, rtl:no, for executables
+ # "both,yes" lib.so.V(shr.o) shared, rtl:yes, for executables
+ # lib.a(lib.so.V) shared, rtl:no
+ # "svr4,*" lib.so.V(shr.o) shared, rtl:yes, for executables
+ # lib.a static archive
+ case $host_os in aix4.[[23]]|aix4.[[23]].*|aix[[5-9]]*)
+ for ld_flag in $LDFLAGS; do
+ case $ld_flag in
+ *-brtl*)
+ aix_use_runtimelinking=yes
+ break
+ ;;
+ esac
+ done
+ if test svr4,no = "$with_aix_soname,$aix_use_runtimelinking"; then
+ # With aix-soname=svr4, we create the lib.so.V shared archives only,
+ # so we don't have lib.a shared libs to link our executables.
+ # We have to force runtime linking in this case.
+ aix_use_runtimelinking=yes
+ LDFLAGS="$LDFLAGS -Wl,-brtl"
+ fi
+ ;;
+ esac
+
+ exp_sym_flag='-bexport'
+ no_entry_flag='-bnoentry'
+ fi
+
+ # When large executables or shared objects are built, AIX ld can
+ # have problems creating the table of contents. If linking a library
+ # or program results in "error TOC overflow" add -mminimal-toc to
+ # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not
+ # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS.
+
+ _LT_TAGVAR(archive_cmds, $1)=''
+ _LT_TAGVAR(hardcode_direct, $1)=yes
+ _LT_TAGVAR(hardcode_direct_absolute, $1)=yes
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=':'
+ _LT_TAGVAR(link_all_deplibs, $1)=yes
+ _LT_TAGVAR(file_list_spec, $1)='$wl-f,'
+ case $with_aix_soname,$aix_use_runtimelinking in
+ aix,*) ;; # no import file
+ svr4,* | *,yes) # use import file
+ # The Import File defines what to hardcode.
+ _LT_TAGVAR(hardcode_direct, $1)=no
+ _LT_TAGVAR(hardcode_direct_absolute, $1)=no
+ ;;
+ esac
+
+ if test yes = "$GXX"; then
+ case $host_os in aix4.[[012]]|aix4.[[012]].*)
+ # We only want to do this on AIX 4.2 and lower, the check
+ # below for broken collect2 doesn't work under 4.3+
+ collect2name=`$CC -print-prog-name=collect2`
+ if test -f "$collect2name" &&
+ strings "$collect2name" | $GREP resolve_lib_name >/dev/null
+ then
+ # We have reworked collect2
+ :
+ else
+ # We have old collect2
+ _LT_TAGVAR(hardcode_direct, $1)=unsupported
+ # It fails to find uninstalled libraries when the uninstalled
+ # path is not listed in the libpath. Setting hardcode_minus_L
+ # to unsupported forces relinking
+ _LT_TAGVAR(hardcode_minus_L, $1)=yes
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=
+ fi
+ esac
+ shared_flag='-shared'
+ if test yes = "$aix_use_runtimelinking"; then
+ shared_flag=$shared_flag' $wl-G'
+ fi
+ # Need to ensure runtime linking is disabled for the traditional
+ # shared library, or the linker may eventually find shared libraries
+ # /with/ Import File - we do not want to mix them.
+ shared_flag_aix='-shared'
+ shared_flag_svr4='-shared $wl-G'
+ else
+ # not using gcc
+ if test ia64 = "$host_cpu"; then
+ # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release
+ # chokes on -Wl,-G. The following line is correct:
+ shared_flag='-G'
+ else
+ if test yes = "$aix_use_runtimelinking"; then
+ shared_flag='$wl-G'
+ else
+ shared_flag='$wl-bM:SRE'
+ fi
+ shared_flag_aix='$wl-bM:SRE'
+ shared_flag_svr4='$wl-G'
+ fi
+ fi
+
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-bexpall'
+ # It seems that -bexpall does not export symbols beginning with
+ # underscore (_), so it is better to generate a list of symbols to
+ # export.
+ _LT_TAGVAR(always_export_symbols, $1)=yes
+ if test aix,yes = "$with_aix_soname,$aix_use_runtimelinking"; then
+ # Warning - without using the other runtime loading flags (-brtl),
+ # -berok will link without error, but may produce a broken library.
+ # The "-G" linker flag allows undefined symbols.
+ _LT_TAGVAR(no_undefined_flag, $1)='-bernotok'
+ # Determine the default libpath from the value encoded in an empty
+ # executable.
+ _LT_SYS_MODULE_PATH_AIX([$1])
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-blibpath:$libdir:'"$aix_libpath"
+
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $deplibs $wl'$no_entry_flag' $compiler_flags `if test -n "$allow_undefined_flag"; then func_echo_all "$wl$allow_undefined_flag"; else :; fi` $wl'$exp_sym_flag:\$export_symbols' '$shared_flag
+ else
+ if test ia64 = "$host_cpu"; then
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-R $libdir:/usr/lib:/lib'
+ _LT_TAGVAR(allow_undefined_flag, $1)="-z nodefs"
+ _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\$wl$no_entry_flag"' $compiler_flags $wl$allow_undefined_flag '"\$wl$exp_sym_flag:\$export_symbols"
+ else
+ # Determine the default libpath from the value encoded in an
+ # empty executable.
+ _LT_SYS_MODULE_PATH_AIX([$1])
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-blibpath:$libdir:'"$aix_libpath"
+ # Warning - without using the other run time loading flags,
+ # -berok will link without error, but may produce a broken library.
+ _LT_TAGVAR(no_undefined_flag, $1)=' $wl-bernotok'
+ _LT_TAGVAR(allow_undefined_flag, $1)=' $wl-berok'
+ if test yes = "$with_gnu_ld"; then
+ # We only use this code for GNU lds that support --whole-archive.
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive$convenience $wl--no-whole-archive'
+ else
+ # Exported symbols can be pulled into shared objects from archives
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='$convenience'
+ fi
+ _LT_TAGVAR(archive_cmds_need_lc, $1)=yes
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$RM -r $output_objdir/$realname.d~$MKDIR $output_objdir/$realname.d'
+ # -brtl affects multiple linker settings, -berok does not and is overridden later
+ compiler_flags_filtered='`func_echo_all "$compiler_flags " | $SED -e "s%-brtl\\([[, ]]\\)%-berok\\1%g"`'
+ if test svr4 != "$with_aix_soname"; then
+ # This is similar to how AIX traditionally builds its shared
+ # libraries. Need -bnortl late, we may have -brtl in LDFLAGS.
+ _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$CC '$shared_flag_aix' -o $output_objdir/$realname.d/$soname $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$realname.d/$soname'
+ fi
+ if test aix != "$with_aix_soname"; then
+ _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$CC '$shared_flag_svr4' -o $output_objdir/$realname.d/$shared_archive_member_spec.o $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$STRIP -e $output_objdir/$realname.d/$shared_archive_member_spec.o~( func_echo_all "#! $soname($shared_archive_member_spec.o)"; if test shr_64 = "$shared_archive_member_spec"; then func_echo_all "# 64"; else func_echo_all "# 32"; fi; cat $export_symbols ) > $output_objdir/$realname.d/$shared_archive_member_spec.imp~$AR $AR_FLAGS $output_objdir/$soname $output_objdir/$realname.d/$shared_archive_member_spec.o $output_objdir/$realname.d/$shared_archive_member_spec.imp'
+ else
+ # used by -dlpreopen to get the symbols
+ _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$MV $output_objdir/$realname.d/$soname $output_objdir'
+ fi
+ _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$RM -r $output_objdir/$realname.d'
+ fi
+ fi
+ ;;
+
+ beos*)
+ if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+ _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+ # Joseph Beckenbach <jrb3@best.com> says some releases of gcc
+ # support --undefined. This deserves some investigation. FIXME
+ _LT_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
+ else
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ fi
+ ;;
+
+ chorus*)
+ case $cc_basename in
+ *)
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ esac
+ ;;
+
+ cygwin* | mingw* | pw32* | cegcc*)
+ case $GXX,$cc_basename in
+ ,cl* | no,cl*)
+ # Native MSVC
+ # hardcode_libdir_flag_spec is actually meaningless, as there is
+ # no search path for DLLs.
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' '
+ _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+ _LT_TAGVAR(always_export_symbols, $1)=yes
+ _LT_TAGVAR(file_list_spec, $1)='@'
+ # Tell ltmain to make .lib files, not .a files.
+ libext=lib
+ # Tell ltmain to make .dll files, not .so files.
+ shrext_cmds=.dll
+ # FIXME: Setting linknames here is a bad hack.
+ _LT_TAGVAR(archive_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~linknames='
+ _LT_TAGVAR(archive_expsym_cmds, $1)='if _LT_DLL_DEF_P([$export_symbols]); then
+ cp "$export_symbols" "$output_objdir/$soname.def";
+ echo "$tool_output_objdir$soname.def" > "$output_objdir/$soname.exp";
+ else
+ $SED -e '\''s/^/-link -EXPORT:/'\'' < $export_symbols > $output_objdir/$soname.exp;
+ fi~
+ $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~
+ linknames='
+ # The linker will not automatically build a static lib if we build a DLL.
+ # _LT_TAGVAR(old_archive_from_new_cmds, $1)='true'
+ _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
+ # Don't use ranlib
+ _LT_TAGVAR(old_postinstall_cmds, $1)='chmod 644 $oldlib'
+ _LT_TAGVAR(postlink_cmds, $1)='lt_outputfile="@OUTPUT@"~
+ lt_tool_outputfile="@TOOL_OUTPUT@"~
+ case $lt_outputfile in
+ *.exe|*.EXE) ;;
+ *)
+ lt_outputfile=$lt_outputfile.exe
+ lt_tool_outputfile=$lt_tool_outputfile.exe
+ ;;
+ esac~
+ func_to_tool_file "$lt_outputfile"~
+ if test : != "$MANIFEST_TOOL" && test -f "$lt_outputfile.manifest"; then
+ $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1;
+ $RM "$lt_outputfile.manifest";
+ fi'
+ ;;
+ *)
+ # g++
+ # _LT_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless,
+ # as there is no search path for DLLs.
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-all-symbols'
+ _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+ _LT_TAGVAR(always_export_symbols, $1)=no
+ _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
+
+ if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname $wl--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+ # If the export-symbols file already is a .def file, use it as
+ # is; otherwise, prepend EXPORTS...
+ _LT_TAGVAR(archive_expsym_cmds, $1)='if _LT_DLL_DEF_P([$export_symbols]); then
+ cp $export_symbols $output_objdir/$soname.def;
+ else
+ echo EXPORTS > $output_objdir/$soname.def;
+ cat $export_symbols >> $output_objdir/$soname.def;
+ fi~
+ $CC -shared -nostdlib $output_objdir/$soname.def $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname $wl--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+ else
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ fi
+ ;;
+ esac
+ ;;
+ darwin* | rhapsody*)
+ _LT_DARWIN_LINKER_FEATURES($1)
+ ;;
+
+ os2*)
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+ _LT_TAGVAR(hardcode_minus_L, $1)=yes
+ _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+ shrext_cmds=.dll
+ _LT_TAGVAR(archive_cmds, $1)='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~
+ $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~
+ $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~
+ $ECHO EXPORTS >> $output_objdir/$libname.def~
+ emxexp $libobjs | $SED /"_DLL_InitTerm"/d >> $output_objdir/$libname.def~
+ $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~
+ emximp -o $lib $output_objdir/$libname.def'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~
+ $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~
+ $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~
+ $ECHO EXPORTS >> $output_objdir/$libname.def~
+ prefix_cmds="$SED"~
+ if test EXPORTS = "`$SED 1q $export_symbols`"; then
+ prefix_cmds="$prefix_cmds -e 1d";
+ fi~
+ prefix_cmds="$prefix_cmds -e \"s/^\(.*\)$/_\1/g\""~
+ cat $export_symbols | $prefix_cmds >> $output_objdir/$libname.def~
+ $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~
+ emximp -o $lib $output_objdir/$libname.def'
+ _LT_TAGVAR(old_archive_From_new_cmds, $1)='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def'
+ _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
+ ;;
+
+ dgux*)
+ case $cc_basename in
+ ec++*)
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ ghcx*)
+ # Green Hills C++ Compiler
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ *)
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ esac
+ ;;
+
+ freebsd2.*)
+ # C++ shared libraries reported to be fairly broken before
+ # switch to ELF
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+
+ freebsd-elf*)
+ _LT_TAGVAR(archive_cmds_need_lc, $1)=no
+ ;;
+
+ freebsd* | dragonfly*)
+ # FreeBSD 3 and later use GNU C++ and GNU ld with standard ELF
+ # conventions
+ _LT_TAGVAR(ld_shlibs, $1)=yes
+ ;;
+
+ haiku*)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
+ _LT_TAGVAR(link_all_deplibs, $1)=yes
+ ;;
+
+ hpux9*)
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl+b $wl$libdir'
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E'
+ _LT_TAGVAR(hardcode_direct, $1)=yes
+ _LT_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH,
+ # but as the default
+ # location of the library.
+
+ case $cc_basename in
+ CC*)
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ aCC*)
+ _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -b $wl+b $wl$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test "x$output_objdir/$soname" = "x$lib" || mv $output_objdir/$soname $lib'
+ # Commands to make compiler produce verbose output that lists
+ # what "hidden" libraries, object files and flags are used when
+ # linking a shared library.
+ #
+ # There doesn't appear to be a way to prevent this compiler from
+ # explicitly linking system object files so we need to strip them
+ # from the output so that they don't get included in the library
+ # dependencies.
+ output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $EGREP "\-L"`; list= ; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"'
+ ;;
+ *)
+ if test yes = "$GXX"; then
+ _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -shared -nostdlib $pic_flag $wl+b $wl$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test "x$output_objdir/$soname" = "x$lib" || mv $output_objdir/$soname $lib'
+ else
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ fi
+ ;;
+ esac
+ ;;
+
+ hpux10*|hpux11*)
+ if test no = "$with_gnu_ld"; then
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl+b $wl$libdir'
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+
+ case $host_cpu in
+ hppa*64*|ia64*)
+ ;;
+ *)
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E'
+ ;;
+ esac
+ fi
+ case $host_cpu in
+ hppa*64*|ia64*)
+ _LT_TAGVAR(hardcode_direct, $1)=no
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ ;;
+ *)
+ _LT_TAGVAR(hardcode_direct, $1)=yes
+ _LT_TAGVAR(hardcode_direct_absolute, $1)=yes
+ _LT_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH,
+ # but as the default
+ # location of the library.
+ ;;
+ esac
+
+ case $cc_basename in
+ CC*)
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ aCC*)
+ case $host_cpu in
+ hppa*64*)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -b $wl+h $wl$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+ ;;
+ ia64*)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -b $wl+h $wl$soname $wl+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+ ;;
+ *)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -b $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+ ;;
+ esac
+ # Commands to make compiler produce verbose output that lists
+ # what "hidden" libraries, object files and flags are used when
+ # linking a shared library.
+ #
+ # There doesn't appear to be a way to prevent this compiler from
+ # explicitly linking system object files so we need to strip them
+ # from the output so that they don't get included in the library
+ # dependencies.
+ output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $GREP "\-L"`; list= ; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"'
+ ;;
+ *)
+ if test yes = "$GXX"; then
+ if test no = "$with_gnu_ld"; then
+ case $host_cpu in
+ hppa*64*)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC $wl+h $wl$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+ ;;
+ ia64*)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $pic_flag $wl+h $wl$soname $wl+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+ ;;
+ *)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $pic_flag $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+ ;;
+ esac
+ fi
+ else
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ fi
+ ;;
+ esac
+ ;;
+
+ interix[[3-9]]*)
+ _LT_TAGVAR(hardcode_direct, $1)=no
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir'
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E'
+ # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc.
+ # Instead, shared libraries are loaded at an image base (0x10000000 by
+ # default) and relocated if they conflict, which is a slow very memory
+ # consuming and fragmenting process. To avoid this, we pick a random,
+ # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link
+ # time. Moving up from 0x10000000 also allows more sbrk(2) space.
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-h,$soname $wl--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='sed "s|^|_|" $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-h,$soname $wl--retain-symbols-file,$output_objdir/$soname.expsym $wl--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+ ;;
+ irix5* | irix6*)
+ case $cc_basename in
+ CC*)
+ # SGI C++
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared -all -multigot $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib'
+
+ # Archives containing C++ object files must be created using
+ # "CC -ar", where "CC" is the IRIX C++ compiler. This is
+ # necessary to make sure instantiated templates are included
+ # in the archive.
+ _LT_TAGVAR(old_archive_cmds, $1)='$CC -ar -WR,-u -o $oldlib $oldobjs'
+ ;;
+ *)
+ if test yes = "$GXX"; then
+ if test no = "$with_gnu_ld"; then
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib'
+ else
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` -o $lib'
+ fi
+ fi
+ _LT_TAGVAR(link_all_deplibs, $1)=yes
+ ;;
+ esac
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir'
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+ _LT_TAGVAR(inherit_rpath, $1)=yes
+ ;;
+
+ linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*)
+ case $cc_basename in
+ KCC*)
+ # Kuck and Associates, Inc. (KAI) C++ Compiler
+
+ # KCC will only create a shared library if the output file
+ # ends with ".so" (or ".sl" for HP-UX), so rename the library
+ # to its proper name (with version) after linking.
+ _LT_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\$tempext\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\$tempext\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib $wl-retain-symbols-file,$export_symbols; mv \$templib $lib'
+ # Commands to make compiler produce verbose output that lists
+ # what "hidden" libraries, object files and flags are used when
+ # linking a shared library.
+ #
+ # There doesn't appear to be a way to prevent this compiler from
+ # explicitly linking system object files so we need to strip them
+ # from the output so that they don't get included in the library
+ # dependencies.
+ output_verbose_link_cmd='templist=`$CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 | $GREP "ld"`; rm -f libconftest$shared_ext; list= ; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"'
+
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir'
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-dynamic'
+
+ # Archives containing C++ object files must be created using
+ # "CC -Bstatic", where "CC" is the KAI C++ compiler.
+ _LT_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs'
+ ;;
+ icpc* | ecpc* )
+ # Intel C++
+ with_gnu_ld=yes
+ # version 8.0 and above of icpc choke on multiply defined symbols
+ # if we add $predep_objects and $postdep_objects, however 7.1 and
+ # earlier do not add the objects themselves.
+ case `$CC -V 2>&1` in
+ *"Version 7."*)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib'
+ ;;
+ *) # Version 8.0 or newer
+ tmp_idyn=
+ case $host_cpu in
+ ia64*) tmp_idyn=' -i_dynamic';;
+ esac
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib'
+ ;;
+ esac
+ _LT_TAGVAR(archive_cmds_need_lc, $1)=no
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir'
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-dynamic'
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive$convenience $wl--no-whole-archive'
+ ;;
+ pgCC* | pgcpp*)
+ # Portland Group C++ compiler
+ case `$CC -V` in
+ *pgCC\ [[1-5]].* | *pgcpp\ [[1-5]].*)
+ _LT_TAGVAR(prelink_cmds, $1)='tpldir=Template.dir~
+ rm -rf $tpldir~
+ $CC --prelink_objects --instantiation_dir $tpldir $objs $libobjs $compile_deplibs~
+ compile_command="$compile_command `find $tpldir -name \*.o | sort | $NL2SP`"'
+ _LT_TAGVAR(old_archive_cmds, $1)='tpldir=Template.dir~
+ rm -rf $tpldir~
+ $CC --prelink_objects --instantiation_dir $tpldir $oldobjs$old_deplibs~
+ $AR $AR_FLAGS $oldlib$oldobjs$old_deplibs `find $tpldir -name \*.o | sort | $NL2SP`~
+ $RANLIB $oldlib'
+ _LT_TAGVAR(archive_cmds, $1)='tpldir=Template.dir~
+ rm -rf $tpldir~
+ $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~
+ $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='tpldir=Template.dir~
+ rm -rf $tpldir~
+ $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~
+ $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib'
+ ;;
+ *) # Version 6 and above use weak symbols
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib'
+ ;;
+ esac
+
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl--rpath $wl$libdir'
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-dynamic'
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive'
+ ;;
+ cxx*)
+ # Compaq C++
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib $wl-retain-symbols-file $wl$export_symbols'
+
+ runpath_var=LD_RUN_PATH
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir'
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+
+ # Commands to make compiler produce verbose output that lists
+ # what "hidden" libraries, object files and flags are used when
+ # linking a shared library.
+ #
+ # There doesn't appear to be a way to prevent this compiler from
+ # explicitly linking system object files so we need to strip them
+ # from the output so that they don't get included in the library
+ # dependencies.
+ output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld .*$\)/\1/"`; list= ; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "X$list" | $Xsed'
+ ;;
+ xl* | mpixl* | bgxl*)
+ # IBM XL 8.0 on PPC, with GNU ld
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir'
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-dynamic'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -qmkshrobj $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
+ if test yes = "$supports_anon_versioning"; then
+ _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~
+ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
+ echo "local: *; };" >> $output_objdir/$libname.ver~
+ $CC -qmkshrobj $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-version-script $wl$output_objdir/$libname.ver -o $lib'
+ fi
+ ;;
+ *)
+ case `$CC -V 2>&1 | sed 5q` in
+ *Sun\ C*)
+ # Sun C++ 5.9
+ _LT_TAGVAR(no_undefined_flag, $1)=' -zdefs'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -G$allow_undefined_flag -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G$allow_undefined_flag -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-retain-symbols-file $wl$export_symbols'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive'
+ _LT_TAGVAR(compiler_needs_object, $1)=yes
+
+ # Not sure whether something based on
+ # $CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1
+ # would be better.
+ output_verbose_link_cmd='func_echo_all'
+
+ # Archives containing C++ object files must be created using
+ # "CC -xar", where "CC" is the Sun C++ compiler. This is
+ # necessary to make sure instantiated templates are included
+ # in the archive.
+ _LT_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs'
+ ;;
+ esac
+ ;;
+ esac
+ ;;
+
+ lynxos*)
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+
+ m88k*)
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+
+ mvs*)
+ case $cc_basename in
+ cxx*)
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ *)
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ esac
+ ;;
+
+ netbsd*)
+ if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
+ _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $predep_objects $libobjs $deplibs $postdep_objects $linker_flags'
+ wlarc=
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+ _LT_TAGVAR(hardcode_direct, $1)=yes
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ fi
+ # Workaround some broken pre-1.5 toolchains
+ output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP conftest.$objext | $SED -e "s:-lgcc -lc -lgcc::"'
+ ;;
+
+ *nto* | *qnx*)
+ _LT_TAGVAR(ld_shlibs, $1)=yes
+ ;;
+
+ openbsd* | bitrig*)
+ if test -f /usr/libexec/ld.so; then
+ _LT_TAGVAR(hardcode_direct, $1)=yes
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ _LT_TAGVAR(hardcode_direct_absolute, $1)=yes
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir'
+ if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`"; then
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-retain-symbols-file,$export_symbols -o $lib'
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E'
+ _LT_TAGVAR(whole_archive_flag_spec, $1)=$wlarc'--whole-archive$convenience '$wlarc'--no-whole-archive'
+ fi
+ output_verbose_link_cmd=func_echo_all
+ else
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ fi
+ ;;
+
+ osf3* | osf4* | osf5*)
+ case $cc_basename in
+ KCC*)
+ # Kuck and Associates, Inc. (KAI) C++ Compiler
+
+ # KCC will only create a shared library if the output file
+ # ends with ".so" (or ".sl" for HP-UX), so rename the library
+ # to its proper name (with version) after linking.
+ _LT_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo "$lib" | $SED -e "s/\$tempext\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib'
+
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir'
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+
+ # Archives containing C++ object files must be created using
+ # the KAI C++ compiler.
+ case $host in
+ osf3*) _LT_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs' ;;
+ *) _LT_TAGVAR(old_archive_cmds, $1)='$CC -o $oldlib $oldobjs' ;;
+ esac
+ ;;
+ RCC*)
+ # Rational C++ 2.4.1
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ cxx*)
+ case $host in
+ osf3*)
+ _LT_TAGVAR(allow_undefined_flag, $1)=' $wl-expect_unresolved $wl\*'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $soname `test -n "$verstring" && func_echo_all "$wl-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir'
+ ;;
+ *)
+ _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done~
+ echo "-hidden">> $lib.exp~
+ $CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname $wl-input $wl$lib.exp `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib~
+ $RM $lib.exp'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir'
+ ;;
+ esac
+
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+
+ # Commands to make compiler produce verbose output that lists
+ # what "hidden" libraries, object files and flags are used when
+ # linking a shared library.
+ #
+ # There doesn't appear to be a way to prevent this compiler from
+ # explicitly linking system object files so we need to strip them
+ # from the output so that they don't get included in the library
+ # dependencies.
+ output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld" | $GREP -v "ld:"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list= ; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"'
+ ;;
+ *)
+ if test yes,no = "$GXX,$with_gnu_ld"; then
+ _LT_TAGVAR(allow_undefined_flag, $1)=' $wl-expect_unresolved $wl\*'
+ case $host in
+ osf3*)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib'
+ ;;
+ *)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-msym $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib'
+ ;;
+ esac
+
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir'
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+
+ # Commands to make compiler produce verbose output that lists
+ # what "hidden" libraries, object files and flags are used when
+ # linking a shared library.
+ output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"'
+
+ else
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ fi
+ ;;
+ esac
+ ;;
+
+ psos*)
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+
+ sunos4*)
+ case $cc_basename in
+ CC*)
+ # Sun C++ 4.x
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ lcc*)
+ # Lucid
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ *)
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ esac
+ ;;
+
+ solaris*)
+ case $cc_basename in
+ CC* | sunCC*)
+ # Sun C++ 4.2, 5.x and Centerline C++
+ _LT_TAGVAR(archive_cmds_need_lc,$1)=yes
+ _LT_TAGVAR(no_undefined_flag, $1)=' -zdefs'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -G$allow_undefined_flag -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+ $CC -G$allow_undefined_flag $wl-M $wl$lib.exp -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp'
+
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ case $host_os in
+ solaris2.[[0-5]] | solaris2.[[0-5]].*) ;;
+ *)
+ # The compiler driver will combine and reorder linker options,
+ # but understands '-z linker_flag'.
+ # Supported since Solaris 2.6 (maybe 2.5.1?)
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract'
+ ;;
+ esac
+ _LT_TAGVAR(link_all_deplibs, $1)=yes
+
+ output_verbose_link_cmd='func_echo_all'
+
+ # Archives containing C++ object files must be created using
+ # "CC -xar", where "CC" is the Sun C++ compiler. This is
+ # necessary to make sure instantiated templates are included
+ # in the archive.
+ _LT_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs'
+ ;;
+ gcx*)
+ # Green Hills C++ Compiler
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-h $wl$soname -o $lib'
+
+ # The C++ compiler must be used to create the archive.
+ _LT_TAGVAR(old_archive_cmds, $1)='$CC $LDFLAGS -archive -o $oldlib $oldobjs'
+ ;;
+ *)
+ # GNU C++ compiler with Solaris linker
+ if test yes,no = "$GXX,$with_gnu_ld"; then
+ _LT_TAGVAR(no_undefined_flag, $1)=' $wl-z ${wl}defs'
+ if $CC --version | $GREP -v '^2\.7' > /dev/null; then
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-h $wl$soname -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+ $CC -shared $pic_flag -nostdlib $wl-M $wl$lib.exp $wl-h $wl$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp'
+
+ # Commands to make compiler produce verbose output that lists
+ # what "hidden" libraries, object files and flags are used when
+ # linking a shared library.
+ output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"'
+ else
+ # g++ 2.7 appears to require '-G' NOT '-shared' on this
+ # platform.
+ _LT_TAGVAR(archive_cmds, $1)='$CC -G -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-h $wl$soname -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+ $CC -G -nostdlib $wl-M $wl$lib.exp $wl-h $wl$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp'
+
+ # Commands to make compiler produce verbose output that lists
+ # what "hidden" libraries, object files and flags are used when
+ # linking a shared library.
+ output_verbose_link_cmd='$CC -G $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"'
+ fi
+
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-R $wl$libdir'
+ case $host_os in
+ solaris2.[[0-5]] | solaris2.[[0-5]].*) ;;
+ *)
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl-z ${wl}allextract$convenience $wl-z ${wl}defaultextract'
+ ;;
+ esac
+ fi
+ ;;
+ esac
+ ;;
+
+ sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7* | sco3.2v5.0.[[024]]*)
+ _LT_TAGVAR(no_undefined_flag, $1)='$wl-z,text'
+ _LT_TAGVAR(archive_cmds_need_lc, $1)=no
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ runpath_var='LD_RUN_PATH'
+
+ case $cc_basename in
+ CC*)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -G $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ *)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ esac
+ ;;
+
+ sysv5* | sco3.2v5* | sco5v6*)
+ # Note: We CANNOT use -z defs as we might desire, because we do not
+ # link with -lc, and that would cause any symbols used from libc to
+ # always be unresolved, which means just about no library would
+ # ever link correctly. If we're not using GNU ld we use -z text
+ # though, which does catch some bad symbols but isn't as heavy-handed
+ # as -z defs.
+ _LT_TAGVAR(no_undefined_flag, $1)='$wl-z,text'
+ _LT_TAGVAR(allow_undefined_flag, $1)='$wl-z,nodefs'
+ _LT_TAGVAR(archive_cmds_need_lc, $1)=no
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-R,$libdir'
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=':'
+ _LT_TAGVAR(link_all_deplibs, $1)=yes
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-Bexport'
+ runpath_var='LD_RUN_PATH'
+
+ case $cc_basename in
+ CC*)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -G $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(old_archive_cmds, $1)='$CC -Tprelink_objects $oldobjs~
+ '"$_LT_TAGVAR(old_archive_cmds, $1)"
+ _LT_TAGVAR(reload_cmds, $1)='$CC -Tprelink_objects $reload_objs~
+ '"$_LT_TAGVAR(reload_cmds, $1)"
+ ;;
+ *)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ esac
+ ;;
+
+ tandem*)
+ case $cc_basename in
+ NCC*)
+ # NonStop-UX NCC 3.20
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ *)
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ esac
+ ;;
+
+ vxworks*)
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+
+ *)
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ esac
+
+ AC_MSG_RESULT([$_LT_TAGVAR(ld_shlibs, $1)])
+ test no = "$_LT_TAGVAR(ld_shlibs, $1)" && can_build_shared=no
+
+ _LT_TAGVAR(GCC, $1)=$GXX
+ _LT_TAGVAR(LD, $1)=$LD
+
+ ## CAVEAT EMPTOR:
+ ## There is no encapsulation within the following macros, do not change
+ ## the running order or otherwise move them around unless you know exactly
+ ## what you are doing...
+ _LT_SYS_HIDDEN_LIBDEPS($1)
+ _LT_COMPILER_PIC($1)
+ _LT_COMPILER_C_O($1)
+ _LT_COMPILER_FILE_LOCKS($1)
+ _LT_LINKER_SHLIBS($1)
+ _LT_SYS_DYNAMIC_LINKER($1)
+ _LT_LINKER_HARDCODE_LIBPATH($1)
+
+ _LT_CONFIG($1)
+ fi # test -n "$compiler"
+
+ CC=$lt_save_CC
+ CFLAGS=$lt_save_CFLAGS
+ LDCXX=$LD
+ LD=$lt_save_LD
+ GCC=$lt_save_GCC
+ with_gnu_ld=$lt_save_with_gnu_ld
+ lt_cv_path_LDCXX=$lt_cv_path_LD
+ lt_cv_path_LD=$lt_save_path_LD
+ lt_cv_prog_gnu_ldcxx=$lt_cv_prog_gnu_ld
+ lt_cv_prog_gnu_ld=$lt_save_with_gnu_ld
+fi # test yes != "$_lt_caught_CXX_error"
+
+AC_LANG_POP
+])# _LT_LANG_CXX_CONFIG
+
+
+# _LT_FUNC_STRIPNAME_CNF
+# ----------------------
+# func_stripname_cnf prefix suffix name
+# strip PREFIX and SUFFIX off of NAME.
+# PREFIX and SUFFIX must not contain globbing or regex special
+# characters, hashes, percent signs, but SUFFIX may contain a leading
+# dot (in which case that matches only a dot).
+#
+# This function is identical to the (non-XSI) version of func_stripname,
+# except this one can be used by m4 code that may be executed by configure,
+# rather than the libtool script.
+m4_defun([_LT_FUNC_STRIPNAME_CNF],[dnl
+AC_REQUIRE([_LT_DECL_SED])
+AC_REQUIRE([_LT_PROG_ECHO_BACKSLASH])
+func_stripname_cnf ()
+{
+ case @S|@2 in
+ .*) func_stripname_result=`$ECHO "@S|@3" | $SED "s%^@S|@1%%; s%\\\\@S|@2\$%%"`;;
+ *) func_stripname_result=`$ECHO "@S|@3" | $SED "s%^@S|@1%%; s%@S|@2\$%%"`;;
+ esac
+} # func_stripname_cnf
+])# _LT_FUNC_STRIPNAME_CNF
+
+
+# _LT_SYS_HIDDEN_LIBDEPS([TAGNAME])
+# ---------------------------------
+# Figure out "hidden" library dependencies from verbose
+# compiler output when linking a shared library.
+# Parse the compiler output and extract the necessary
+# objects, libraries and library flags.
+m4_defun([_LT_SYS_HIDDEN_LIBDEPS],
+[m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+AC_REQUIRE([_LT_FUNC_STRIPNAME_CNF])dnl
+# Dependencies to place before and after the object being linked:
+_LT_TAGVAR(predep_objects, $1)=
+_LT_TAGVAR(postdep_objects, $1)=
+_LT_TAGVAR(predeps, $1)=
+_LT_TAGVAR(postdeps, $1)=
+_LT_TAGVAR(compiler_lib_search_path, $1)=
+
+dnl we can't use the lt_simple_compile_test_code here,
+dnl because it contains code intended for an executable,
+dnl not a library. It's possible we should let each
+dnl tag define a new lt_????_link_test_code variable,
+dnl but it's only used here...
+m4_if([$1], [], [cat > conftest.$ac_ext <<_LT_EOF
+int a;
+void foo (void) { a = 0; }
+_LT_EOF
+], [$1], [CXX], [cat > conftest.$ac_ext <<_LT_EOF
+class Foo
+{
+public:
+ Foo (void) { a = 0; }
+private:
+ int a;
+};
+_LT_EOF
+], [$1], [F77], [cat > conftest.$ac_ext <<_LT_EOF
+ subroutine foo
+ implicit none
+ integer*4 a
+ a=0
+ return
+ end
+_LT_EOF
+], [$1], [FC], [cat > conftest.$ac_ext <<_LT_EOF
+ subroutine foo
+ implicit none
+ integer a
+ a=0
+ return
+ end
+_LT_EOF
+], [$1], [GCJ], [cat > conftest.$ac_ext <<_LT_EOF
+public class foo {
+ private int a;
+ public void bar (void) {
+ a = 0;
+ }
+};
+_LT_EOF
+], [$1], [GO], [cat > conftest.$ac_ext <<_LT_EOF
+package foo
+func foo() {
+}
+_LT_EOF
+])
+
+_lt_libdeps_save_CFLAGS=$CFLAGS
+case "$CC $CFLAGS " in #(
+*\ -flto*\ *) CFLAGS="$CFLAGS -fno-lto" ;;
+*\ -fwhopr*\ *) CFLAGS="$CFLAGS -fno-whopr" ;;
+*\ -fuse-linker-plugin*\ *) CFLAGS="$CFLAGS -fno-use-linker-plugin" ;;
+esac
+
+dnl Parse the compiler output and extract the necessary
+dnl objects, libraries and library flags.
+if AC_TRY_EVAL(ac_compile); then
+ # Parse the compiler output and extract the necessary
+ # objects, libraries and library flags.
+
+ # Sentinel used to keep track of whether or not we are before
+ # the conftest object file.
+ pre_test_object_deps_done=no
+
+ for p in `eval "$output_verbose_link_cmd"`; do
+ case $prev$p in
+
+ -L* | -R* | -l*)
+ # Some compilers place space between "-{L,R}" and the path.
+ # Remove the space.
+ if test x-L = "$p" ||
+ test x-R = "$p"; then
+ prev=$p
+ continue
+ fi
+
+ # Expand the sysroot to ease extracting the directories later.
+ if test -z "$prev"; then
+ case $p in
+ -L*) func_stripname_cnf '-L' '' "$p"; prev=-L; p=$func_stripname_result ;;
+ -R*) func_stripname_cnf '-R' '' "$p"; prev=-R; p=$func_stripname_result ;;
+ -l*) func_stripname_cnf '-l' '' "$p"; prev=-l; p=$func_stripname_result ;;
+ esac
+ fi
+ case $p in
+ =*) func_stripname_cnf '=' '' "$p"; p=$lt_sysroot$func_stripname_result ;;
+ esac
+ if test no = "$pre_test_object_deps_done"; then
+ case $prev in
+ -L | -R)
+ # Internal compiler library paths should come after those
+ # provided the user. The postdeps already come after the
+ # user supplied libs so there is no need to process them.
+ if test -z "$_LT_TAGVAR(compiler_lib_search_path, $1)"; then
+ _LT_TAGVAR(compiler_lib_search_path, $1)=$prev$p
+ else
+ _LT_TAGVAR(compiler_lib_search_path, $1)="${_LT_TAGVAR(compiler_lib_search_path, $1)} $prev$p"
+ fi
+ ;;
+ # The "-l" case would never come before the object being
+ # linked, so don't bother handling this case.
+ esac
+ else
+ if test -z "$_LT_TAGVAR(postdeps, $1)"; then
+ _LT_TAGVAR(postdeps, $1)=$prev$p
+ else
+ _LT_TAGVAR(postdeps, $1)="${_LT_TAGVAR(postdeps, $1)} $prev$p"
+ fi
+ fi
+ prev=
+ ;;
+
+ *.lto.$objext) ;; # Ignore GCC LTO objects
+ *.$objext)
+ # This assumes that the test object file only shows up
+ # once in the compiler output.
+ if test "$p" = "conftest.$objext"; then
+ pre_test_object_deps_done=yes
+ continue
+ fi
+
+ if test no = "$pre_test_object_deps_done"; then
+ if test -z "$_LT_TAGVAR(predep_objects, $1)"; then
+ _LT_TAGVAR(predep_objects, $1)=$p
+ else
+ _LT_TAGVAR(predep_objects, $1)="$_LT_TAGVAR(predep_objects, $1) $p"
+ fi
+ else
+ if test -z "$_LT_TAGVAR(postdep_objects, $1)"; then
+ _LT_TAGVAR(postdep_objects, $1)=$p
+ else
+ _LT_TAGVAR(postdep_objects, $1)="$_LT_TAGVAR(postdep_objects, $1) $p"
+ fi
+ fi
+ ;;
+
+ *) ;; # Ignore the rest.
+
+ esac
+ done
+
+ # Clean up.
+ rm -f a.out a.exe
+else
+ echo "libtool.m4: error: problem compiling $1 test program"
+fi
+
+$RM -f confest.$objext
+CFLAGS=$_lt_libdeps_save_CFLAGS
+
+# PORTME: override above test on systems where it is broken
+m4_if([$1], [CXX],
+[case $host_os in
+interix[[3-9]]*)
+ # Interix 3.5 installs completely hosed .la files for C++, so rather than
+ # hack all around it, let's just trust "g++" to DTRT.
+ _LT_TAGVAR(predep_objects,$1)=
+ _LT_TAGVAR(postdep_objects,$1)=
+ _LT_TAGVAR(postdeps,$1)=
+ ;;
+esac
+])
+
+case " $_LT_TAGVAR(postdeps, $1) " in
+*" -lc "*) _LT_TAGVAR(archive_cmds_need_lc, $1)=no ;;
+esac
+ _LT_TAGVAR(compiler_lib_search_dirs, $1)=
+if test -n "${_LT_TAGVAR(compiler_lib_search_path, $1)}"; then
+ _LT_TAGVAR(compiler_lib_search_dirs, $1)=`echo " ${_LT_TAGVAR(compiler_lib_search_path, $1)}" | $SED -e 's! -L! !g' -e 's!^ !!'`
+fi
+_LT_TAGDECL([], [compiler_lib_search_dirs], [1],
+ [The directories searched by this compiler when creating a shared library])
+_LT_TAGDECL([], [predep_objects], [1],
+ [Dependencies to place before and after the objects being linked to
+ create a shared library])
+_LT_TAGDECL([], [postdep_objects], [1])
+_LT_TAGDECL([], [predeps], [1])
+_LT_TAGDECL([], [postdeps], [1])
+_LT_TAGDECL([], [compiler_lib_search_path], [1],
+ [The library search path used internally by the compiler when linking
+ a shared library])
+])# _LT_SYS_HIDDEN_LIBDEPS
+
+
+# _LT_LANG_F77_CONFIG([TAG])
+# --------------------------
+# Ensure that the configuration variables for a Fortran 77 compiler are
+# suitably defined. These variables are subsequently used by _LT_CONFIG
+# to write the compiler configuration to 'libtool'.
+m4_defun([_LT_LANG_F77_CONFIG],
+[AC_LANG_PUSH(Fortran 77)
+if test -z "$F77" || test no = "$F77"; then
+ _lt_disable_F77=yes
+fi
+
+_LT_TAGVAR(archive_cmds_need_lc, $1)=no
+_LT_TAGVAR(allow_undefined_flag, $1)=
+_LT_TAGVAR(always_export_symbols, $1)=no
+_LT_TAGVAR(archive_expsym_cmds, $1)=
+_LT_TAGVAR(export_dynamic_flag_spec, $1)=
+_LT_TAGVAR(hardcode_direct, $1)=no
+_LT_TAGVAR(hardcode_direct_absolute, $1)=no
+_LT_TAGVAR(hardcode_libdir_flag_spec, $1)=
+_LT_TAGVAR(hardcode_libdir_separator, $1)=
+_LT_TAGVAR(hardcode_minus_L, $1)=no
+_LT_TAGVAR(hardcode_automatic, $1)=no
+_LT_TAGVAR(inherit_rpath, $1)=no
+_LT_TAGVAR(module_cmds, $1)=
+_LT_TAGVAR(module_expsym_cmds, $1)=
+_LT_TAGVAR(link_all_deplibs, $1)=unknown
+_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds
+_LT_TAGVAR(reload_flag, $1)=$reload_flag
+_LT_TAGVAR(reload_cmds, $1)=$reload_cmds
+_LT_TAGVAR(no_undefined_flag, $1)=
+_LT_TAGVAR(whole_archive_flag_spec, $1)=
+_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no
+
+# Source file extension for f77 test sources.
+ac_ext=f
+
+# Object file extension for compiled f77 test sources.
+objext=o
+_LT_TAGVAR(objext, $1)=$objext
+
+# No sense in running all these tests if we already determined that
+# the F77 compiler isn't working. Some variables (like enable_shared)
+# are currently assumed to apply to all compilers on this platform,
+# and will be corrupted by setting them based on a non-working compiler.
+if test yes != "$_lt_disable_F77"; then
+ # Code to be used in simple compile tests
+ lt_simple_compile_test_code="\
+ subroutine t
+ return
+ end
+"
+
+ # Code to be used in simple link tests
+ lt_simple_link_test_code="\
+ program t
+ end
+"
+
+ # ltmain only uses $CC for tagged configurations so make sure $CC is set.
+ _LT_TAG_COMPILER
+
+ # save warnings/boilerplate of simple test code
+ _LT_COMPILER_BOILERPLATE
+ _LT_LINKER_BOILERPLATE
+
+ # Allow CC to be a program name with arguments.
+ lt_save_CC=$CC
+ lt_save_GCC=$GCC
+ lt_save_CFLAGS=$CFLAGS
+ CC=${F77-"f77"}
+ CFLAGS=$FFLAGS
+ compiler=$CC
+ _LT_TAGVAR(compiler, $1)=$CC
+ _LT_CC_BASENAME([$compiler])
+ GCC=$G77
+ if test -n "$compiler"; then
+ AC_MSG_CHECKING([if libtool supports shared libraries])
+ AC_MSG_RESULT([$can_build_shared])
+
+ AC_MSG_CHECKING([whether to build shared libraries])
+ test no = "$can_build_shared" && enable_shared=no
+
+ # On AIX, shared libraries and static libraries use the same namespace, and
+ # are all built from PIC.
+ case $host_os in
+ aix3*)
+ test yes = "$enable_shared" && enable_static=no
+ if test -n "$RANLIB"; then
+ archive_cmds="$archive_cmds~\$RANLIB \$lib"
+ postinstall_cmds='$RANLIB $lib'
+ fi
+ ;;
+ aix[[4-9]]*)
+ if test ia64 != "$host_cpu"; then
+ case $enable_shared,$with_aix_soname,$aix_use_runtimelinking in
+ yes,aix,yes) ;; # shared object as lib.so file only
+ yes,svr4,*) ;; # shared object as lib.so archive member only
+ yes,*) enable_static=no ;; # shared object in lib.a archive as well
+ esac
+ fi
+ ;;
+ esac
+ AC_MSG_RESULT([$enable_shared])
+
+ AC_MSG_CHECKING([whether to build static libraries])
+ # Make sure either enable_shared or enable_static is yes.
+ test yes = "$enable_shared" || enable_static=yes
+ AC_MSG_RESULT([$enable_static])
+
+ _LT_TAGVAR(GCC, $1)=$G77
+ _LT_TAGVAR(LD, $1)=$LD
+
+ ## CAVEAT EMPTOR:
+ ## There is no encapsulation within the following macros, do not change
+ ## the running order or otherwise move them around unless you know exactly
+ ## what you are doing...
+ _LT_COMPILER_PIC($1)
+ _LT_COMPILER_C_O($1)
+ _LT_COMPILER_FILE_LOCKS($1)
+ _LT_LINKER_SHLIBS($1)
+ _LT_SYS_DYNAMIC_LINKER($1)
+ _LT_LINKER_HARDCODE_LIBPATH($1)
+
+ _LT_CONFIG($1)
+ fi # test -n "$compiler"
+
+ GCC=$lt_save_GCC
+ CC=$lt_save_CC
+ CFLAGS=$lt_save_CFLAGS
+fi # test yes != "$_lt_disable_F77"
+
+AC_LANG_POP
+])# _LT_LANG_F77_CONFIG
+
+
+# _LT_LANG_FC_CONFIG([TAG])
+# -------------------------
+# Ensure that the configuration variables for a Fortran compiler are
+# suitably defined. These variables are subsequently used by _LT_CONFIG
+# to write the compiler configuration to 'libtool'.
+m4_defun([_LT_LANG_FC_CONFIG],
+[AC_LANG_PUSH(Fortran)
+
+if test -z "$FC" || test no = "$FC"; then
+ _lt_disable_FC=yes
+fi
+
+_LT_TAGVAR(archive_cmds_need_lc, $1)=no
+_LT_TAGVAR(allow_undefined_flag, $1)=
+_LT_TAGVAR(always_export_symbols, $1)=no
+_LT_TAGVAR(archive_expsym_cmds, $1)=
+_LT_TAGVAR(export_dynamic_flag_spec, $1)=
+_LT_TAGVAR(hardcode_direct, $1)=no
+_LT_TAGVAR(hardcode_direct_absolute, $1)=no
+_LT_TAGVAR(hardcode_libdir_flag_spec, $1)=
+_LT_TAGVAR(hardcode_libdir_separator, $1)=
+_LT_TAGVAR(hardcode_minus_L, $1)=no
+_LT_TAGVAR(hardcode_automatic, $1)=no
+_LT_TAGVAR(inherit_rpath, $1)=no
+_LT_TAGVAR(module_cmds, $1)=
+_LT_TAGVAR(module_expsym_cmds, $1)=
+_LT_TAGVAR(link_all_deplibs, $1)=unknown
+_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds
+_LT_TAGVAR(reload_flag, $1)=$reload_flag
+_LT_TAGVAR(reload_cmds, $1)=$reload_cmds
+_LT_TAGVAR(no_undefined_flag, $1)=
+_LT_TAGVAR(whole_archive_flag_spec, $1)=
+_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no
+
+# Source file extension for fc test sources.
+ac_ext=${ac_fc_srcext-f}
+
+# Object file extension for compiled fc test sources.
+objext=o
+_LT_TAGVAR(objext, $1)=$objext
+
+# No sense in running all these tests if we already determined that
+# the FC compiler isn't working. Some variables (like enable_shared)
+# are currently assumed to apply to all compilers on this platform,
+# and will be corrupted by setting them based on a non-working compiler.
+if test yes != "$_lt_disable_FC"; then
+ # Code to be used in simple compile tests
+ lt_simple_compile_test_code="\
+ subroutine t
+ return
+ end
+"
+
+ # Code to be used in simple link tests
+ lt_simple_link_test_code="\
+ program t
+ end
+"
+
+ # ltmain only uses $CC for tagged configurations so make sure $CC is set.
+ _LT_TAG_COMPILER
+
+ # save warnings/boilerplate of simple test code
+ _LT_COMPILER_BOILERPLATE
+ _LT_LINKER_BOILERPLATE
+
+ # Allow CC to be a program name with arguments.
+ lt_save_CC=$CC
+ lt_save_GCC=$GCC
+ lt_save_CFLAGS=$CFLAGS
+ CC=${FC-"f95"}
+ CFLAGS=$FCFLAGS
+ compiler=$CC
+ GCC=$ac_cv_fc_compiler_gnu
+
+ _LT_TAGVAR(compiler, $1)=$CC
+ _LT_CC_BASENAME([$compiler])
+
+ if test -n "$compiler"; then
+ AC_MSG_CHECKING([if libtool supports shared libraries])
+ AC_MSG_RESULT([$can_build_shared])
+
+ AC_MSG_CHECKING([whether to build shared libraries])
+ test no = "$can_build_shared" && enable_shared=no
+
+ # On AIX, shared libraries and static libraries use the same namespace, and
+ # are all built from PIC.
+ case $host_os in
+ aix3*)
+ test yes = "$enable_shared" && enable_static=no
+ if test -n "$RANLIB"; then
+ archive_cmds="$archive_cmds~\$RANLIB \$lib"
+ postinstall_cmds='$RANLIB $lib'
+ fi
+ ;;
+ aix[[4-9]]*)
+ if test ia64 != "$host_cpu"; then
+ case $enable_shared,$with_aix_soname,$aix_use_runtimelinking in
+ yes,aix,yes) ;; # shared object as lib.so file only
+ yes,svr4,*) ;; # shared object as lib.so archive member only
+ yes,*) enable_static=no ;; # shared object in lib.a archive as well
+ esac
+ fi
+ ;;
+ esac
+ AC_MSG_RESULT([$enable_shared])
+
+ AC_MSG_CHECKING([whether to build static libraries])
+ # Make sure either enable_shared or enable_static is yes.
+ test yes = "$enable_shared" || enable_static=yes
+ AC_MSG_RESULT([$enable_static])
+
+ _LT_TAGVAR(GCC, $1)=$ac_cv_fc_compiler_gnu
+ _LT_TAGVAR(LD, $1)=$LD
+
+ ## CAVEAT EMPTOR:
+ ## There is no encapsulation within the following macros, do not change
+ ## the running order or otherwise move them around unless you know exactly
+ ## what you are doing...
+ _LT_SYS_HIDDEN_LIBDEPS($1)
+ _LT_COMPILER_PIC($1)
+ _LT_COMPILER_C_O($1)
+ _LT_COMPILER_FILE_LOCKS($1)
+ _LT_LINKER_SHLIBS($1)
+ _LT_SYS_DYNAMIC_LINKER($1)
+ _LT_LINKER_HARDCODE_LIBPATH($1)
+
+ _LT_CONFIG($1)
+ fi # test -n "$compiler"
+
+ GCC=$lt_save_GCC
+ CC=$lt_save_CC
+ CFLAGS=$lt_save_CFLAGS
+fi # test yes != "$_lt_disable_FC"
+
+AC_LANG_POP
+])# _LT_LANG_FC_CONFIG
+
+
+# _LT_LANG_GCJ_CONFIG([TAG])
+# --------------------------
+# Ensure that the configuration variables for the GNU Java Compiler compiler
+# are suitably defined. These variables are subsequently used by _LT_CONFIG
+# to write the compiler configuration to 'libtool'.
+m4_defun([_LT_LANG_GCJ_CONFIG],
+[AC_REQUIRE([LT_PROG_GCJ])dnl
+AC_LANG_SAVE
+
+# Source file extension for Java test sources.
+ac_ext=java
+
+# Object file extension for compiled Java test sources.
+objext=o
+_LT_TAGVAR(objext, $1)=$objext
+
+# Code to be used in simple compile tests
+lt_simple_compile_test_code="class foo {}"
+
+# Code to be used in simple link tests
+lt_simple_link_test_code='public class conftest { public static void main(String[[]] argv) {}; }'
+
+# ltmain only uses $CC for tagged configurations so make sure $CC is set.
+_LT_TAG_COMPILER
+
+# save warnings/boilerplate of simple test code
+_LT_COMPILER_BOILERPLATE
+_LT_LINKER_BOILERPLATE
+
+# Allow CC to be a program name with arguments.
+lt_save_CC=$CC
+lt_save_CFLAGS=$CFLAGS
+lt_save_GCC=$GCC
+GCC=yes
+CC=${GCJ-"gcj"}
+CFLAGS=$GCJFLAGS
+compiler=$CC
+_LT_TAGVAR(compiler, $1)=$CC
+_LT_TAGVAR(LD, $1)=$LD
+_LT_CC_BASENAME([$compiler])
+
+# GCJ did not exist at the time GCC didn't implicitly link libc in.
+_LT_TAGVAR(archive_cmds_need_lc, $1)=no
+
+_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds
+_LT_TAGVAR(reload_flag, $1)=$reload_flag
+_LT_TAGVAR(reload_cmds, $1)=$reload_cmds
+
+## CAVEAT EMPTOR:
+## There is no encapsulation within the following macros, do not change
+## the running order or otherwise move them around unless you know exactly
+## what you are doing...
+if test -n "$compiler"; then
+ _LT_COMPILER_NO_RTTI($1)
+ _LT_COMPILER_PIC($1)
+ _LT_COMPILER_C_O($1)
+ _LT_COMPILER_FILE_LOCKS($1)
+ _LT_LINKER_SHLIBS($1)
+ _LT_LINKER_HARDCODE_LIBPATH($1)
+
+ _LT_CONFIG($1)
+fi
+
+AC_LANG_RESTORE
+
+GCC=$lt_save_GCC
+CC=$lt_save_CC
+CFLAGS=$lt_save_CFLAGS
+])# _LT_LANG_GCJ_CONFIG
+
+
+# _LT_LANG_GO_CONFIG([TAG])
+# --------------------------
+# Ensure that the configuration variables for the GNU Go compiler
+# are suitably defined. These variables are subsequently used by _LT_CONFIG
+# to write the compiler configuration to 'libtool'.
+m4_defun([_LT_LANG_GO_CONFIG],
+[AC_REQUIRE([LT_PROG_GO])dnl
+AC_LANG_SAVE
+
+# Source file extension for Go test sources.
+ac_ext=go
+
+# Object file extension for compiled Go test sources.
+objext=o
+_LT_TAGVAR(objext, $1)=$objext
+
+# Code to be used in simple compile tests
+lt_simple_compile_test_code="package main; func main() { }"
+
+# Code to be used in simple link tests
+lt_simple_link_test_code='package main; func main() { }'
+
+# ltmain only uses $CC for tagged configurations so make sure $CC is set.
+_LT_TAG_COMPILER
+
+# save warnings/boilerplate of simple test code
+_LT_COMPILER_BOILERPLATE
+_LT_LINKER_BOILERPLATE
+
+# Allow CC to be a program name with arguments.
+lt_save_CC=$CC
+lt_save_CFLAGS=$CFLAGS
+lt_save_GCC=$GCC
+GCC=yes
+CC=${GOC-"gccgo"}
+CFLAGS=$GOFLAGS
+compiler=$CC
+_LT_TAGVAR(compiler, $1)=$CC
+_LT_TAGVAR(LD, $1)=$LD
+_LT_CC_BASENAME([$compiler])
+
+# Go did not exist at the time GCC didn't implicitly link libc in.
+_LT_TAGVAR(archive_cmds_need_lc, $1)=no
+
+_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds
+_LT_TAGVAR(reload_flag, $1)=$reload_flag
+_LT_TAGVAR(reload_cmds, $1)=$reload_cmds
+
+## CAVEAT EMPTOR:
+## There is no encapsulation within the following macros, do not change
+## the running order or otherwise move them around unless you know exactly
+## what you are doing...
+if test -n "$compiler"; then
+ _LT_COMPILER_NO_RTTI($1)
+ _LT_COMPILER_PIC($1)
+ _LT_COMPILER_C_O($1)
+ _LT_COMPILER_FILE_LOCKS($1)
+ _LT_LINKER_SHLIBS($1)
+ _LT_LINKER_HARDCODE_LIBPATH($1)
+
+ _LT_CONFIG($1)
+fi
+
+AC_LANG_RESTORE
+
+GCC=$lt_save_GCC
+CC=$lt_save_CC
+CFLAGS=$lt_save_CFLAGS
+])# _LT_LANG_GO_CONFIG
+
+
+# _LT_LANG_RC_CONFIG([TAG])
+# -------------------------
+# Ensure that the configuration variables for the Windows resource compiler
+# are suitably defined. These variables are subsequently used by _LT_CONFIG
+# to write the compiler configuration to 'libtool'.
+m4_defun([_LT_LANG_RC_CONFIG],
+[AC_REQUIRE([LT_PROG_RC])dnl
+AC_LANG_SAVE
+
+# Source file extension for RC test sources.
+ac_ext=rc
+
+# Object file extension for compiled RC test sources.
+objext=o
+_LT_TAGVAR(objext, $1)=$objext
+
+# Code to be used in simple compile tests
+lt_simple_compile_test_code='sample MENU { MENUITEM "&Soup", 100, CHECKED }'
+
+# Code to be used in simple link tests
+lt_simple_link_test_code=$lt_simple_compile_test_code
+
+# ltmain only uses $CC for tagged configurations so make sure $CC is set.
+_LT_TAG_COMPILER
+
+# save warnings/boilerplate of simple test code
+_LT_COMPILER_BOILERPLATE
+_LT_LINKER_BOILERPLATE
+
+# Allow CC to be a program name with arguments.
+lt_save_CC=$CC
+lt_save_CFLAGS=$CFLAGS
+lt_save_GCC=$GCC
+GCC=
+CC=${RC-"windres"}
+CFLAGS=
+compiler=$CC
+_LT_TAGVAR(compiler, $1)=$CC
+_LT_CC_BASENAME([$compiler])
+_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes
+
+if test -n "$compiler"; then
+ :
+ _LT_CONFIG($1)
+fi
+
+GCC=$lt_save_GCC
+AC_LANG_RESTORE
+CC=$lt_save_CC
+CFLAGS=$lt_save_CFLAGS
+])# _LT_LANG_RC_CONFIG
+
+
+# LT_PROG_GCJ
+# -----------
+AC_DEFUN([LT_PROG_GCJ],
+[m4_ifdef([AC_PROG_GCJ], [AC_PROG_GCJ],
+ [m4_ifdef([A][M_PROG_GCJ], [A][M_PROG_GCJ],
+ [AC_CHECK_TOOL(GCJ, gcj,)
+ test set = "${GCJFLAGS+set}" || GCJFLAGS="-g -O2"
+ AC_SUBST(GCJFLAGS)])])[]dnl
+])
+
+# Old name:
+AU_ALIAS([LT_AC_PROG_GCJ], [LT_PROG_GCJ])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([LT_AC_PROG_GCJ], [])
+
+
+# LT_PROG_GO
+# ----------
+AC_DEFUN([LT_PROG_GO],
+[AC_CHECK_TOOL(GOC, gccgo,)
+])
+
+
+# LT_PROG_RC
+# ----------
+AC_DEFUN([LT_PROG_RC],
+[AC_CHECK_TOOL(RC, windres,)
+])
+
+# Old name:
+AU_ALIAS([LT_AC_PROG_RC], [LT_PROG_RC])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([LT_AC_PROG_RC], [])
+
+
+# _LT_DECL_EGREP
+# --------------
+# If we don't have a new enough Autoconf to choose the best grep
+# available, choose the one first in the user's PATH.
+m4_defun([_LT_DECL_EGREP],
+[AC_REQUIRE([AC_PROG_EGREP])dnl
+AC_REQUIRE([AC_PROG_FGREP])dnl
+test -z "$GREP" && GREP=grep
+_LT_DECL([], [GREP], [1], [A grep program that handles long lines])
+_LT_DECL([], [EGREP], [1], [An ERE matcher])
+_LT_DECL([], [FGREP], [1], [A literal string matcher])
+dnl Non-bleeding-edge autoconf doesn't subst GREP, so do it here too
+AC_SUBST([GREP])
+])
+
+
+# _LT_DECL_OBJDUMP
+# --------------
+# If we don't have a new enough Autoconf to choose the best objdump
+# available, choose the one first in the user's PATH.
+m4_defun([_LT_DECL_OBJDUMP],
+[AC_CHECK_TOOL(OBJDUMP, objdump, false)
+test -z "$OBJDUMP" && OBJDUMP=objdump
+_LT_DECL([], [OBJDUMP], [1], [An object symbol dumper])
+AC_SUBST([OBJDUMP])
+])
+
+# _LT_DECL_DLLTOOL
+# ----------------
+# Ensure DLLTOOL variable is set.
+m4_defun([_LT_DECL_DLLTOOL],
+[AC_CHECK_TOOL(DLLTOOL, dlltool, false)
+test -z "$DLLTOOL" && DLLTOOL=dlltool
+_LT_DECL([], [DLLTOOL], [1], [DLL creation program])
+AC_SUBST([DLLTOOL])
+])
+
+# _LT_DECL_SED
+# ------------
+# Check for a fully-functional sed program, that truncates
+# as few characters as possible. Prefer GNU sed if found.
+m4_defun([_LT_DECL_SED],
+[AC_PROG_SED
+test -z "$SED" && SED=sed
+Xsed="$SED -e 1s/^X//"
+_LT_DECL([], [SED], [1], [A sed program that does not truncate output])
+_LT_DECL([], [Xsed], ["\$SED -e 1s/^X//"],
+ [Sed that helps us avoid accidentally triggering echo(1) options like -n])
+])# _LT_DECL_SED
+
+m4_ifndef([AC_PROG_SED], [
+############################################################
+# NOTE: This macro has been submitted for inclusion into #
+# GNU Autoconf as AC_PROG_SED. When it is available in #
+# a released version of Autoconf we should remove this #
+# macro and use it instead. #
+############################################################
+
+m4_defun([AC_PROG_SED],
+[AC_MSG_CHECKING([for a sed that does not truncate output])
+AC_CACHE_VAL(lt_cv_path_SED,
+[# Loop through the user's path and test for sed and gsed.
+# Then use that list of sed's as ones to test for truncation.
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for lt_ac_prog in sed gsed; do
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$lt_ac_prog$ac_exec_ext"; then
+ lt_ac_sed_list="$lt_ac_sed_list $as_dir/$lt_ac_prog$ac_exec_ext"
+ fi
+ done
+ done
+done
+IFS=$as_save_IFS
+lt_ac_max=0
+lt_ac_count=0
+# Add /usr/xpg4/bin/sed as it is typically found on Solaris
+# along with /bin/sed that truncates output.
+for lt_ac_sed in $lt_ac_sed_list /usr/xpg4/bin/sed; do
+ test ! -f "$lt_ac_sed" && continue
+ cat /dev/null > conftest.in
+ lt_ac_count=0
+ echo $ECHO_N "0123456789$ECHO_C" >conftest.in
+ # Check for GNU sed and select it if it is found.
+ if "$lt_ac_sed" --version 2>&1 < /dev/null | grep 'GNU' > /dev/null; then
+ lt_cv_path_SED=$lt_ac_sed
+ break
+ fi
+ while true; do
+ cat conftest.in conftest.in >conftest.tmp
+ mv conftest.tmp conftest.in
+ cp conftest.in conftest.nl
+ echo >>conftest.nl
+ $lt_ac_sed -e 's/a$//' < conftest.nl >conftest.out || break
+ cmp -s conftest.out conftest.nl || break
+ # 10000 chars as input seems more than enough
+ test 10 -lt "$lt_ac_count" && break
+ lt_ac_count=`expr $lt_ac_count + 1`
+ if test "$lt_ac_count" -gt "$lt_ac_max"; then
+ lt_ac_max=$lt_ac_count
+ lt_cv_path_SED=$lt_ac_sed
+ fi
+ done
+done
+])
+SED=$lt_cv_path_SED
+AC_SUBST([SED])
+AC_MSG_RESULT([$SED])
+])#AC_PROG_SED
+])#m4_ifndef
+
+# Old name:
+AU_ALIAS([LT_AC_PROG_SED], [AC_PROG_SED])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([LT_AC_PROG_SED], [])
+
+
+# _LT_CHECK_SHELL_FEATURES
+# ------------------------
+# Find out whether the shell is Bourne or XSI compatible,
+# or has some other useful features.
+m4_defun([_LT_CHECK_SHELL_FEATURES],
+[if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then
+ lt_unset=unset
+else
+ lt_unset=false
+fi
+_LT_DECL([], [lt_unset], [0], [whether the shell understands "unset"])dnl
+
+# test EBCDIC or ASCII
+case `echo X|tr X '\101'` in
+ A) # ASCII based system
+ # \n is not interpreted correctly by Solaris 8 /usr/ucb/tr
+ lt_SP2NL='tr \040 \012'
+ lt_NL2SP='tr \015\012 \040\040'
+ ;;
+ *) # EBCDIC based system
+ lt_SP2NL='tr \100 \n'
+ lt_NL2SP='tr \r\n \100\100'
+ ;;
+esac
+_LT_DECL([SP2NL], [lt_SP2NL], [1], [turn spaces into newlines])dnl
+_LT_DECL([NL2SP], [lt_NL2SP], [1], [turn newlines into spaces])dnl
+])# _LT_CHECK_SHELL_FEATURES
+
+
+# _LT_PATH_CONVERSION_FUNCTIONS
+# -----------------------------
+# Determine what file name conversion functions should be used by
+# func_to_host_file (and, implicitly, by func_to_host_path). These are needed
+# for certain cross-compile configurations and native mingw.
+m4_defun([_LT_PATH_CONVERSION_FUNCTIONS],
+[AC_REQUIRE([AC_CANONICAL_HOST])dnl
+AC_REQUIRE([AC_CANONICAL_BUILD])dnl
+AC_MSG_CHECKING([how to convert $build file names to $host format])
+AC_CACHE_VAL(lt_cv_to_host_file_cmd,
+[case $host in
+ *-*-mingw* )
+ case $build in
+ *-*-mingw* ) # actually msys
+ lt_cv_to_host_file_cmd=func_convert_file_msys_to_w32
+ ;;
+ *-*-cygwin* )
+ lt_cv_to_host_file_cmd=func_convert_file_cygwin_to_w32
+ ;;
+ * ) # otherwise, assume *nix
+ lt_cv_to_host_file_cmd=func_convert_file_nix_to_w32
+ ;;
+ esac
+ ;;
+ *-*-cygwin* )
+ case $build in
+ *-*-mingw* ) # actually msys
+ lt_cv_to_host_file_cmd=func_convert_file_msys_to_cygwin
+ ;;
+ *-*-cygwin* )
+ lt_cv_to_host_file_cmd=func_convert_file_noop
+ ;;
+ * ) # otherwise, assume *nix
+ lt_cv_to_host_file_cmd=func_convert_file_nix_to_cygwin
+ ;;
+ esac
+ ;;
+ * ) # unhandled hosts (and "normal" native builds)
+ lt_cv_to_host_file_cmd=func_convert_file_noop
+ ;;
+esac
+])
+to_host_file_cmd=$lt_cv_to_host_file_cmd
+AC_MSG_RESULT([$lt_cv_to_host_file_cmd])
+_LT_DECL([to_host_file_cmd], [lt_cv_to_host_file_cmd],
+ [0], [convert $build file names to $host format])dnl
+
+AC_MSG_CHECKING([how to convert $build file names to toolchain format])
+AC_CACHE_VAL(lt_cv_to_tool_file_cmd,
+[#assume ordinary cross tools, or native build.
+lt_cv_to_tool_file_cmd=func_convert_file_noop
+case $host in
+ *-*-mingw* )
+ case $build in
+ *-*-mingw* ) # actually msys
+ lt_cv_to_tool_file_cmd=func_convert_file_msys_to_w32
+ ;;
+ esac
+ ;;
+esac
+])
+to_tool_file_cmd=$lt_cv_to_tool_file_cmd
+AC_MSG_RESULT([$lt_cv_to_tool_file_cmd])
+_LT_DECL([to_tool_file_cmd], [lt_cv_to_tool_file_cmd],
+ [0], [convert $build files to toolchain format])dnl
+])# _LT_PATH_CONVERSION_FUNCTIONS
diff --git a/m4/ltoptions.m4 b/m4/ltoptions.m4
new file mode 100644
index 0000000..94b0829
--- /dev/null
+++ b/m4/ltoptions.m4
@@ -0,0 +1,437 @@
+# Helper functions for option handling. -*- Autoconf -*-
+#
+# Copyright (C) 2004-2005, 2007-2009, 2011-2015 Free Software
+# Foundation, Inc.
+# Written by Gary V. Vaughan, 2004
+#
+# This file is free software; the Free Software Foundation gives
+# unlimited permission to copy and/or distribute it, with or without
+# modifications, as long as this notice is preserved.
+
+# serial 8 ltoptions.m4
+
+# This is to help aclocal find these macros, as it can't see m4_define.
+AC_DEFUN([LTOPTIONS_VERSION], [m4_if([1])])
+
+
+# _LT_MANGLE_OPTION(MACRO-NAME, OPTION-NAME)
+# ------------------------------------------
+m4_define([_LT_MANGLE_OPTION],
+[[_LT_OPTION_]m4_bpatsubst($1__$2, [[^a-zA-Z0-9_]], [_])])
+
+
+# _LT_SET_OPTION(MACRO-NAME, OPTION-NAME)
+# ---------------------------------------
+# Set option OPTION-NAME for macro MACRO-NAME, and if there is a
+# matching handler defined, dispatch to it. Other OPTION-NAMEs are
+# saved as a flag.
+m4_define([_LT_SET_OPTION],
+[m4_define(_LT_MANGLE_OPTION([$1], [$2]))dnl
+m4_ifdef(_LT_MANGLE_DEFUN([$1], [$2]),
+ _LT_MANGLE_DEFUN([$1], [$2]),
+ [m4_warning([Unknown $1 option '$2'])])[]dnl
+])
+
+
+# _LT_IF_OPTION(MACRO-NAME, OPTION-NAME, IF-SET, [IF-NOT-SET])
+# ------------------------------------------------------------
+# Execute IF-SET if OPTION is set, IF-NOT-SET otherwise.
+m4_define([_LT_IF_OPTION],
+[m4_ifdef(_LT_MANGLE_OPTION([$1], [$2]), [$3], [$4])])
+
+
+# _LT_UNLESS_OPTIONS(MACRO-NAME, OPTION-LIST, IF-NOT-SET)
+# -------------------------------------------------------
+# Execute IF-NOT-SET unless all options in OPTION-LIST for MACRO-NAME
+# are set.
+m4_define([_LT_UNLESS_OPTIONS],
+[m4_foreach([_LT_Option], m4_split(m4_normalize([$2])),
+ [m4_ifdef(_LT_MANGLE_OPTION([$1], _LT_Option),
+ [m4_define([$0_found])])])[]dnl
+m4_ifdef([$0_found], [m4_undefine([$0_found])], [$3
+])[]dnl
+])
+
+
+# _LT_SET_OPTIONS(MACRO-NAME, OPTION-LIST)
+# ----------------------------------------
+# OPTION-LIST is a space-separated list of Libtool options associated
+# with MACRO-NAME. If any OPTION has a matching handler declared with
+# LT_OPTION_DEFINE, dispatch to that macro; otherwise complain about
+# the unknown option and exit.
+m4_defun([_LT_SET_OPTIONS],
+[# Set options
+m4_foreach([_LT_Option], m4_split(m4_normalize([$2])),
+ [_LT_SET_OPTION([$1], _LT_Option)])
+
+m4_if([$1],[LT_INIT],[
+ dnl
+ dnl Simply set some default values (i.e off) if boolean options were not
+ dnl specified:
+ _LT_UNLESS_OPTIONS([LT_INIT], [dlopen], [enable_dlopen=no
+ ])
+ _LT_UNLESS_OPTIONS([LT_INIT], [win32-dll], [enable_win32_dll=no
+ ])
+ dnl
+ dnl If no reference was made to various pairs of opposing options, then
+ dnl we run the default mode handler for the pair. For example, if neither
+ dnl 'shared' nor 'disable-shared' was passed, we enable building of shared
+ dnl archives by default:
+ _LT_UNLESS_OPTIONS([LT_INIT], [shared disable-shared], [_LT_ENABLE_SHARED])
+ _LT_UNLESS_OPTIONS([LT_INIT], [static disable-static], [_LT_ENABLE_STATIC])
+ _LT_UNLESS_OPTIONS([LT_INIT], [pic-only no-pic], [_LT_WITH_PIC])
+ _LT_UNLESS_OPTIONS([LT_INIT], [fast-install disable-fast-install],
+ [_LT_ENABLE_FAST_INSTALL])
+ _LT_UNLESS_OPTIONS([LT_INIT], [aix-soname=aix aix-soname=both aix-soname=svr4],
+ [_LT_WITH_AIX_SONAME([aix])])
+ ])
+])# _LT_SET_OPTIONS
+
+
+## --------------------------------- ##
+## Macros to handle LT_INIT options. ##
+## --------------------------------- ##
+
+# _LT_MANGLE_DEFUN(MACRO-NAME, OPTION-NAME)
+# -----------------------------------------
+m4_define([_LT_MANGLE_DEFUN],
+[[_LT_OPTION_DEFUN_]m4_bpatsubst(m4_toupper([$1__$2]), [[^A-Z0-9_]], [_])])
+
+
+# LT_OPTION_DEFINE(MACRO-NAME, OPTION-NAME, CODE)
+# -----------------------------------------------
+m4_define([LT_OPTION_DEFINE],
+[m4_define(_LT_MANGLE_DEFUN([$1], [$2]), [$3])[]dnl
+])# LT_OPTION_DEFINE
+
+
+# dlopen
+# ------
+LT_OPTION_DEFINE([LT_INIT], [dlopen], [enable_dlopen=yes
+])
+
+AU_DEFUN([AC_LIBTOOL_DLOPEN],
+[_LT_SET_OPTION([LT_INIT], [dlopen])
+AC_DIAGNOSE([obsolete],
+[$0: Remove this warning and the call to _LT_SET_OPTION when you
+put the 'dlopen' option into LT_INIT's first parameter.])
+])
+
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_LIBTOOL_DLOPEN], [])
+
+
+# win32-dll
+# ---------
+# Declare package support for building win32 dll's.
+LT_OPTION_DEFINE([LT_INIT], [win32-dll],
+[enable_win32_dll=yes
+
+case $host in
+*-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-cegcc*)
+ AC_CHECK_TOOL(AS, as, false)
+ AC_CHECK_TOOL(DLLTOOL, dlltool, false)
+ AC_CHECK_TOOL(OBJDUMP, objdump, false)
+ ;;
+esac
+
+test -z "$AS" && AS=as
+_LT_DECL([], [AS], [1], [Assembler program])dnl
+
+test -z "$DLLTOOL" && DLLTOOL=dlltool
+_LT_DECL([], [DLLTOOL], [1], [DLL creation program])dnl
+
+test -z "$OBJDUMP" && OBJDUMP=objdump
+_LT_DECL([], [OBJDUMP], [1], [Object dumper program])dnl
+])# win32-dll
+
+AU_DEFUN([AC_LIBTOOL_WIN32_DLL],
+[AC_REQUIRE([AC_CANONICAL_HOST])dnl
+_LT_SET_OPTION([LT_INIT], [win32-dll])
+AC_DIAGNOSE([obsolete],
+[$0: Remove this warning and the call to _LT_SET_OPTION when you
+put the 'win32-dll' option into LT_INIT's first parameter.])
+])
+
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_LIBTOOL_WIN32_DLL], [])
+
+
+# _LT_ENABLE_SHARED([DEFAULT])
+# ----------------------------
+# implement the --enable-shared flag, and supports the 'shared' and
+# 'disable-shared' LT_INIT options.
+# DEFAULT is either 'yes' or 'no'. If omitted, it defaults to 'yes'.
+m4_define([_LT_ENABLE_SHARED],
+[m4_define([_LT_ENABLE_SHARED_DEFAULT], [m4_if($1, no, no, yes)])dnl
+AC_ARG_ENABLE([shared],
+ [AS_HELP_STRING([--enable-shared@<:@=PKGS@:>@],
+ [build shared libraries @<:@default=]_LT_ENABLE_SHARED_DEFAULT[@:>@])],
+ [p=${PACKAGE-default}
+ case $enableval in
+ yes) enable_shared=yes ;;
+ no) enable_shared=no ;;
+ *)
+ enable_shared=no
+ # Look at the argument we got. We use all the common list separators.
+ lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR,
+ for pkg in $enableval; do
+ IFS=$lt_save_ifs
+ if test "X$pkg" = "X$p"; then
+ enable_shared=yes
+ fi
+ done
+ IFS=$lt_save_ifs
+ ;;
+ esac],
+ [enable_shared=]_LT_ENABLE_SHARED_DEFAULT)
+
+ _LT_DECL([build_libtool_libs], [enable_shared], [0],
+ [Whether or not to build shared libraries])
+])# _LT_ENABLE_SHARED
+
+LT_OPTION_DEFINE([LT_INIT], [shared], [_LT_ENABLE_SHARED([yes])])
+LT_OPTION_DEFINE([LT_INIT], [disable-shared], [_LT_ENABLE_SHARED([no])])
+
+# Old names:
+AC_DEFUN([AC_ENABLE_SHARED],
+[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[shared])
+])
+
+AC_DEFUN([AC_DISABLE_SHARED],
+[_LT_SET_OPTION([LT_INIT], [disable-shared])
+])
+
+AU_DEFUN([AM_ENABLE_SHARED], [AC_ENABLE_SHARED($@)])
+AU_DEFUN([AM_DISABLE_SHARED], [AC_DISABLE_SHARED($@)])
+
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AM_ENABLE_SHARED], [])
+dnl AC_DEFUN([AM_DISABLE_SHARED], [])
+
+
+
+# _LT_ENABLE_STATIC([DEFAULT])
+# ----------------------------
+# implement the --enable-static flag, and support the 'static' and
+# 'disable-static' LT_INIT options.
+# DEFAULT is either 'yes' or 'no'. If omitted, it defaults to 'yes'.
+m4_define([_LT_ENABLE_STATIC],
+[m4_define([_LT_ENABLE_STATIC_DEFAULT], [m4_if($1, no, no, yes)])dnl
+AC_ARG_ENABLE([static],
+ [AS_HELP_STRING([--enable-static@<:@=PKGS@:>@],
+ [build static libraries @<:@default=]_LT_ENABLE_STATIC_DEFAULT[@:>@])],
+ [p=${PACKAGE-default}
+ case $enableval in
+ yes) enable_static=yes ;;
+ no) enable_static=no ;;
+ *)
+ enable_static=no
+ # Look at the argument we got. We use all the common list separators.
+ lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR,
+ for pkg in $enableval; do
+ IFS=$lt_save_ifs
+ if test "X$pkg" = "X$p"; then
+ enable_static=yes
+ fi
+ done
+ IFS=$lt_save_ifs
+ ;;
+ esac],
+ [enable_static=]_LT_ENABLE_STATIC_DEFAULT)
+
+ _LT_DECL([build_old_libs], [enable_static], [0],
+ [Whether or not to build static libraries])
+])# _LT_ENABLE_STATIC
+
+LT_OPTION_DEFINE([LT_INIT], [static], [_LT_ENABLE_STATIC([yes])])
+LT_OPTION_DEFINE([LT_INIT], [disable-static], [_LT_ENABLE_STATIC([no])])
+
+# Old names:
+AC_DEFUN([AC_ENABLE_STATIC],
+[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[static])
+])
+
+AC_DEFUN([AC_DISABLE_STATIC],
+[_LT_SET_OPTION([LT_INIT], [disable-static])
+])
+
+AU_DEFUN([AM_ENABLE_STATIC], [AC_ENABLE_STATIC($@)])
+AU_DEFUN([AM_DISABLE_STATIC], [AC_DISABLE_STATIC($@)])
+
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AM_ENABLE_STATIC], [])
+dnl AC_DEFUN([AM_DISABLE_STATIC], [])
+
+
+
+# _LT_ENABLE_FAST_INSTALL([DEFAULT])
+# ----------------------------------
+# implement the --enable-fast-install flag, and support the 'fast-install'
+# and 'disable-fast-install' LT_INIT options.
+# DEFAULT is either 'yes' or 'no'. If omitted, it defaults to 'yes'.
+m4_define([_LT_ENABLE_FAST_INSTALL],
+[m4_define([_LT_ENABLE_FAST_INSTALL_DEFAULT], [m4_if($1, no, no, yes)])dnl
+AC_ARG_ENABLE([fast-install],
+ [AS_HELP_STRING([--enable-fast-install@<:@=PKGS@:>@],
+ [optimize for fast installation @<:@default=]_LT_ENABLE_FAST_INSTALL_DEFAULT[@:>@])],
+ [p=${PACKAGE-default}
+ case $enableval in
+ yes) enable_fast_install=yes ;;
+ no) enable_fast_install=no ;;
+ *)
+ enable_fast_install=no
+ # Look at the argument we got. We use all the common list separators.
+ lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR,
+ for pkg in $enableval; do
+ IFS=$lt_save_ifs
+ if test "X$pkg" = "X$p"; then
+ enable_fast_install=yes
+ fi
+ done
+ IFS=$lt_save_ifs
+ ;;
+ esac],
+ [enable_fast_install=]_LT_ENABLE_FAST_INSTALL_DEFAULT)
+
+_LT_DECL([fast_install], [enable_fast_install], [0],
+ [Whether or not to optimize for fast installation])dnl
+])# _LT_ENABLE_FAST_INSTALL
+
+LT_OPTION_DEFINE([LT_INIT], [fast-install], [_LT_ENABLE_FAST_INSTALL([yes])])
+LT_OPTION_DEFINE([LT_INIT], [disable-fast-install], [_LT_ENABLE_FAST_INSTALL([no])])
+
+# Old names:
+AU_DEFUN([AC_ENABLE_FAST_INSTALL],
+[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[fast-install])
+AC_DIAGNOSE([obsolete],
+[$0: Remove this warning and the call to _LT_SET_OPTION when you put
+the 'fast-install' option into LT_INIT's first parameter.])
+])
+
+AU_DEFUN([AC_DISABLE_FAST_INSTALL],
+[_LT_SET_OPTION([LT_INIT], [disable-fast-install])
+AC_DIAGNOSE([obsolete],
+[$0: Remove this warning and the call to _LT_SET_OPTION when you put
+the 'disable-fast-install' option into LT_INIT's first parameter.])
+])
+
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_ENABLE_FAST_INSTALL], [])
+dnl AC_DEFUN([AM_DISABLE_FAST_INSTALL], [])
+
+
+# _LT_WITH_AIX_SONAME([DEFAULT])
+# ----------------------------------
+# implement the --with-aix-soname flag, and support the `aix-soname=aix'
+# and `aix-soname=both' and `aix-soname=svr4' LT_INIT options. DEFAULT
+# is either `aix', `both' or `svr4'. If omitted, it defaults to `aix'.
+m4_define([_LT_WITH_AIX_SONAME],
+[m4_define([_LT_WITH_AIX_SONAME_DEFAULT], [m4_if($1, svr4, svr4, m4_if($1, both, both, aix))])dnl
+shared_archive_member_spec=
+case $host,$enable_shared in
+power*-*-aix[[5-9]]*,yes)
+ AC_MSG_CHECKING([which variant of shared library versioning to provide])
+ AC_ARG_WITH([aix-soname],
+ [AS_HELP_STRING([--with-aix-soname=aix|svr4|both],
+ [shared library versioning (aka "SONAME") variant to provide on AIX, @<:@default=]_LT_WITH_AIX_SONAME_DEFAULT[@:>@.])],
+ [case $withval in
+ aix|svr4|both)
+ ;;
+ *)
+ AC_MSG_ERROR([Unknown argument to --with-aix-soname])
+ ;;
+ esac
+ lt_cv_with_aix_soname=$with_aix_soname],
+ [AC_CACHE_VAL([lt_cv_with_aix_soname],
+ [lt_cv_with_aix_soname=]_LT_WITH_AIX_SONAME_DEFAULT)
+ with_aix_soname=$lt_cv_with_aix_soname])
+ AC_MSG_RESULT([$with_aix_soname])
+ if test aix != "$with_aix_soname"; then
+ # For the AIX way of multilib, we name the shared archive member
+ # based on the bitwidth used, traditionally 'shr.o' or 'shr_64.o',
+ # and 'shr.imp' or 'shr_64.imp', respectively, for the Import File.
+ # Even when GNU compilers ignore OBJECT_MODE but need '-maix64' flag,
+ # the AIX toolchain works better with OBJECT_MODE set (default 32).
+ if test 64 = "${OBJECT_MODE-32}"; then
+ shared_archive_member_spec=shr_64
+ else
+ shared_archive_member_spec=shr
+ fi
+ fi
+ ;;
+*)
+ with_aix_soname=aix
+ ;;
+esac
+
+_LT_DECL([], [shared_archive_member_spec], [0],
+ [Shared archive member basename, for filename based shared library versioning on AIX])dnl
+])# _LT_WITH_AIX_SONAME
+
+LT_OPTION_DEFINE([LT_INIT], [aix-soname=aix], [_LT_WITH_AIX_SONAME([aix])])
+LT_OPTION_DEFINE([LT_INIT], [aix-soname=both], [_LT_WITH_AIX_SONAME([both])])
+LT_OPTION_DEFINE([LT_INIT], [aix-soname=svr4], [_LT_WITH_AIX_SONAME([svr4])])
+
+
+# _LT_WITH_PIC([MODE])
+# --------------------
+# implement the --with-pic flag, and support the 'pic-only' and 'no-pic'
+# LT_INIT options.
+# MODE is either 'yes' or 'no'. If omitted, it defaults to 'both'.
+m4_define([_LT_WITH_PIC],
+[AC_ARG_WITH([pic],
+ [AS_HELP_STRING([--with-pic@<:@=PKGS@:>@],
+ [try to use only PIC/non-PIC objects @<:@default=use both@:>@])],
+ [lt_p=${PACKAGE-default}
+ case $withval in
+ yes|no) pic_mode=$withval ;;
+ *)
+ pic_mode=default
+ # Look at the argument we got. We use all the common list separators.
+ lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR,
+ for lt_pkg in $withval; do
+ IFS=$lt_save_ifs
+ if test "X$lt_pkg" = "X$lt_p"; then
+ pic_mode=yes
+ fi
+ done
+ IFS=$lt_save_ifs
+ ;;
+ esac],
+ [pic_mode=m4_default([$1], [default])])
+
+_LT_DECL([], [pic_mode], [0], [What type of objects to build])dnl
+])# _LT_WITH_PIC
+
+LT_OPTION_DEFINE([LT_INIT], [pic-only], [_LT_WITH_PIC([yes])])
+LT_OPTION_DEFINE([LT_INIT], [no-pic], [_LT_WITH_PIC([no])])
+
+# Old name:
+AU_DEFUN([AC_LIBTOOL_PICMODE],
+[_LT_SET_OPTION([LT_INIT], [pic-only])
+AC_DIAGNOSE([obsolete],
+[$0: Remove this warning and the call to _LT_SET_OPTION when you
+put the 'pic-only' option into LT_INIT's first parameter.])
+])
+
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_LIBTOOL_PICMODE], [])
+
+## ----------------- ##
+## LTDL_INIT Options ##
+## ----------------- ##
+
+m4_define([_LTDL_MODE], [])
+LT_OPTION_DEFINE([LTDL_INIT], [nonrecursive],
+ [m4_define([_LTDL_MODE], [nonrecursive])])
+LT_OPTION_DEFINE([LTDL_INIT], [recursive],
+ [m4_define([_LTDL_MODE], [recursive])])
+LT_OPTION_DEFINE([LTDL_INIT], [subproject],
+ [m4_define([_LTDL_MODE], [subproject])])
+
+m4_define([_LTDL_TYPE], [])
+LT_OPTION_DEFINE([LTDL_INIT], [installable],
+ [m4_define([_LTDL_TYPE], [installable])])
+LT_OPTION_DEFINE([LTDL_INIT], [convenience],
+ [m4_define([_LTDL_TYPE], [convenience])])
diff --git a/m4/ltsugar.m4 b/m4/ltsugar.m4
new file mode 100644
index 0000000..48bc934
--- /dev/null
+++ b/m4/ltsugar.m4
@@ -0,0 +1,124 @@
+# ltsugar.m4 -- libtool m4 base layer. -*-Autoconf-*-
+#
+# Copyright (C) 2004-2005, 2007-2008, 2011-2015 Free Software
+# Foundation, Inc.
+# Written by Gary V. Vaughan, 2004
+#
+# This file is free software; the Free Software Foundation gives
+# unlimited permission to copy and/or distribute it, with or without
+# modifications, as long as this notice is preserved.
+
+# serial 6 ltsugar.m4
+
+# This is to help aclocal find these macros, as it can't see m4_define.
+AC_DEFUN([LTSUGAR_VERSION], [m4_if([0.1])])
+
+
+# lt_join(SEP, ARG1, [ARG2...])
+# -----------------------------
+# Produce ARG1SEPARG2...SEPARGn, omitting [] arguments and their
+# associated separator.
+# Needed until we can rely on m4_join from Autoconf 2.62, since all earlier
+# versions in m4sugar had bugs.
+m4_define([lt_join],
+[m4_if([$#], [1], [],
+ [$#], [2], [[$2]],
+ [m4_if([$2], [], [], [[$2]_])$0([$1], m4_shift(m4_shift($@)))])])
+m4_define([_lt_join],
+[m4_if([$#$2], [2], [],
+ [m4_if([$2], [], [], [[$1$2]])$0([$1], m4_shift(m4_shift($@)))])])
+
+
+# lt_car(LIST)
+# lt_cdr(LIST)
+# ------------
+# Manipulate m4 lists.
+# These macros are necessary as long as will still need to support
+# Autoconf-2.59, which quotes differently.
+m4_define([lt_car], [[$1]])
+m4_define([lt_cdr],
+[m4_if([$#], 0, [m4_fatal([$0: cannot be called without arguments])],
+ [$#], 1, [],
+ [m4_dquote(m4_shift($@))])])
+m4_define([lt_unquote], $1)
+
+
+# lt_append(MACRO-NAME, STRING, [SEPARATOR])
+# ------------------------------------------
+# Redefine MACRO-NAME to hold its former content plus 'SEPARATOR''STRING'.
+# Note that neither SEPARATOR nor STRING are expanded; they are appended
+# to MACRO-NAME as is (leaving the expansion for when MACRO-NAME is invoked).
+# No SEPARATOR is output if MACRO-NAME was previously undefined (different
+# than defined and empty).
+#
+# This macro is needed until we can rely on Autoconf 2.62, since earlier
+# versions of m4sugar mistakenly expanded SEPARATOR but not STRING.
+m4_define([lt_append],
+[m4_define([$1],
+ m4_ifdef([$1], [m4_defn([$1])[$3]])[$2])])
+
+
+
+# lt_combine(SEP, PREFIX-LIST, INFIX, SUFFIX1, [SUFFIX2...])
+# ----------------------------------------------------------
+# Produce a SEP delimited list of all paired combinations of elements of
+# PREFIX-LIST with SUFFIX1 through SUFFIXn. Each element of the list
+# has the form PREFIXmINFIXSUFFIXn.
+# Needed until we can rely on m4_combine added in Autoconf 2.62.
+m4_define([lt_combine],
+[m4_if(m4_eval([$# > 3]), [1],
+ [m4_pushdef([_Lt_sep], [m4_define([_Lt_sep], m4_defn([lt_car]))])]]dnl
+[[m4_foreach([_Lt_prefix], [$2],
+ [m4_foreach([_Lt_suffix],
+ ]m4_dquote(m4_dquote(m4_shift(m4_shift(m4_shift($@)))))[,
+ [_Lt_sep([$1])[]m4_defn([_Lt_prefix])[$3]m4_defn([_Lt_suffix])])])])])
+
+
+# lt_if_append_uniq(MACRO-NAME, VARNAME, [SEPARATOR], [UNIQ], [NOT-UNIQ])
+# -----------------------------------------------------------------------
+# Iff MACRO-NAME does not yet contain VARNAME, then append it (delimited
+# by SEPARATOR if supplied) and expand UNIQ, else NOT-UNIQ.
+m4_define([lt_if_append_uniq],
+[m4_ifdef([$1],
+ [m4_if(m4_index([$3]m4_defn([$1])[$3], [$3$2$3]), [-1],
+ [lt_append([$1], [$2], [$3])$4],
+ [$5])],
+ [lt_append([$1], [$2], [$3])$4])])
+
+
+# lt_dict_add(DICT, KEY, VALUE)
+# -----------------------------
+m4_define([lt_dict_add],
+[m4_define([$1($2)], [$3])])
+
+
+# lt_dict_add_subkey(DICT, KEY, SUBKEY, VALUE)
+# --------------------------------------------
+m4_define([lt_dict_add_subkey],
+[m4_define([$1($2:$3)], [$4])])
+
+
+# lt_dict_fetch(DICT, KEY, [SUBKEY])
+# ----------------------------------
+m4_define([lt_dict_fetch],
+[m4_ifval([$3],
+ m4_ifdef([$1($2:$3)], [m4_defn([$1($2:$3)])]),
+ m4_ifdef([$1($2)], [m4_defn([$1($2)])]))])
+
+
+# lt_if_dict_fetch(DICT, KEY, [SUBKEY], VALUE, IF-TRUE, [IF-FALSE])
+# -----------------------------------------------------------------
+m4_define([lt_if_dict_fetch],
+[m4_if(lt_dict_fetch([$1], [$2], [$3]), [$4],
+ [$5],
+ [$6])])
+
+
+# lt_dict_filter(DICT, [SUBKEY], VALUE, [SEPARATOR], KEY, [...])
+# --------------------------------------------------------------
+m4_define([lt_dict_filter],
+[m4_if([$5], [], [],
+ [lt_join(m4_quote(m4_default([$4], [[, ]])),
+ lt_unquote(m4_split(m4_normalize(m4_foreach(_Lt_key, lt_car([m4_shiftn(4, $@)]),
+ [lt_if_dict_fetch([$1], _Lt_key, [$2], [$3], [_Lt_key ])])))))])[]dnl
+])
diff --git a/m4/ltversion.m4 b/m4/ltversion.m4
new file mode 100644
index 0000000..fa04b52
--- /dev/null
+++ b/m4/ltversion.m4
@@ -0,0 +1,23 @@
+# ltversion.m4 -- version numbers -*- Autoconf -*-
+#
+# Copyright (C) 2004, 2011-2015 Free Software Foundation, Inc.
+# Written by Scott James Remnant, 2004
+#
+# This file is free software; the Free Software Foundation gives
+# unlimited permission to copy and/or distribute it, with or without
+# modifications, as long as this notice is preserved.
+
+# @configure_input@
+
+# serial 4179 ltversion.m4
+# This file is part of GNU Libtool
+
+m4_define([LT_PACKAGE_VERSION], [2.4.6])
+m4_define([LT_PACKAGE_REVISION], [2.4.6])
+
+AC_DEFUN([LTVERSION_VERSION],
+[macro_version='2.4.6'
+macro_revision='2.4.6'
+_LT_DECL(, macro_version, 0, [Which release of libtool.m4 was used?])
+_LT_DECL(, macro_revision, 0)
+])
diff --git a/m4/lt~obsolete.m4 b/m4/lt~obsolete.m4
new file mode 100644
index 0000000..c6b26f8
--- /dev/null
+++ b/m4/lt~obsolete.m4
@@ -0,0 +1,99 @@
+# lt~obsolete.m4 -- aclocal satisfying obsolete definitions. -*-Autoconf-*-
+#
+# Copyright (C) 2004-2005, 2007, 2009, 2011-2015 Free Software
+# Foundation, Inc.
+# Written by Scott James Remnant, 2004.
+#
+# This file is free software; the Free Software Foundation gives
+# unlimited permission to copy and/or distribute it, with or without
+# modifications, as long as this notice is preserved.
+
+# serial 5 lt~obsolete.m4
+
+# These exist entirely to fool aclocal when bootstrapping libtool.
+#
+# In the past libtool.m4 has provided macros via AC_DEFUN (or AU_DEFUN),
+# which have later been changed to m4_define as they aren't part of the
+# exported API, or moved to Autoconf or Automake where they belong.
+#
+# The trouble is, aclocal is a bit thick. It'll see the old AC_DEFUN
+# in /usr/share/aclocal/libtool.m4 and remember it, then when it sees us
+# using a macro with the same name in our local m4/libtool.m4 it'll
+# pull the old libtool.m4 in (it doesn't see our shiny new m4_define
+# and doesn't know about Autoconf macros at all.)
+#
+# So we provide this file, which has a silly filename so it's always
+# included after everything else. This provides aclocal with the
+# AC_DEFUNs it wants, but when m4 processes it, it doesn't do anything
+# because those macros already exist, or will be overwritten later.
+# We use AC_DEFUN over AU_DEFUN for compatibility with aclocal-1.6.
+#
+# Anytime we withdraw an AC_DEFUN or AU_DEFUN, remember to add it here.
+# Yes, that means every name once taken will need to remain here until
+# we give up compatibility with versions before 1.7, at which point
+# we need to keep only those names which we still refer to.
+
+# This is to help aclocal find these macros, as it can't see m4_define.
+AC_DEFUN([LTOBSOLETE_VERSION], [m4_if([1])])
+
+m4_ifndef([AC_LIBTOOL_LINKER_OPTION], [AC_DEFUN([AC_LIBTOOL_LINKER_OPTION])])
+m4_ifndef([AC_PROG_EGREP], [AC_DEFUN([AC_PROG_EGREP])])
+m4_ifndef([_LT_AC_PROG_ECHO_BACKSLASH], [AC_DEFUN([_LT_AC_PROG_ECHO_BACKSLASH])])
+m4_ifndef([_LT_AC_SHELL_INIT], [AC_DEFUN([_LT_AC_SHELL_INIT])])
+m4_ifndef([_LT_AC_SYS_LIBPATH_AIX], [AC_DEFUN([_LT_AC_SYS_LIBPATH_AIX])])
+m4_ifndef([_LT_PROG_LTMAIN], [AC_DEFUN([_LT_PROG_LTMAIN])])
+m4_ifndef([_LT_AC_TAGVAR], [AC_DEFUN([_LT_AC_TAGVAR])])
+m4_ifndef([AC_LTDL_ENABLE_INSTALL], [AC_DEFUN([AC_LTDL_ENABLE_INSTALL])])
+m4_ifndef([AC_LTDL_PREOPEN], [AC_DEFUN([AC_LTDL_PREOPEN])])
+m4_ifndef([_LT_AC_SYS_COMPILER], [AC_DEFUN([_LT_AC_SYS_COMPILER])])
+m4_ifndef([_LT_AC_LOCK], [AC_DEFUN([_LT_AC_LOCK])])
+m4_ifndef([AC_LIBTOOL_SYS_OLD_ARCHIVE], [AC_DEFUN([AC_LIBTOOL_SYS_OLD_ARCHIVE])])
+m4_ifndef([_LT_AC_TRY_DLOPEN_SELF], [AC_DEFUN([_LT_AC_TRY_DLOPEN_SELF])])
+m4_ifndef([AC_LIBTOOL_PROG_CC_C_O], [AC_DEFUN([AC_LIBTOOL_PROG_CC_C_O])])
+m4_ifndef([AC_LIBTOOL_SYS_HARD_LINK_LOCKS], [AC_DEFUN([AC_LIBTOOL_SYS_HARD_LINK_LOCKS])])
+m4_ifndef([AC_LIBTOOL_OBJDIR], [AC_DEFUN([AC_LIBTOOL_OBJDIR])])
+m4_ifndef([AC_LTDL_OBJDIR], [AC_DEFUN([AC_LTDL_OBJDIR])])
+m4_ifndef([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH], [AC_DEFUN([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH])])
+m4_ifndef([AC_LIBTOOL_SYS_LIB_STRIP], [AC_DEFUN([AC_LIBTOOL_SYS_LIB_STRIP])])
+m4_ifndef([AC_PATH_MAGIC], [AC_DEFUN([AC_PATH_MAGIC])])
+m4_ifndef([AC_PROG_LD_GNU], [AC_DEFUN([AC_PROG_LD_GNU])])
+m4_ifndef([AC_PROG_LD_RELOAD_FLAG], [AC_DEFUN([AC_PROG_LD_RELOAD_FLAG])])
+m4_ifndef([AC_DEPLIBS_CHECK_METHOD], [AC_DEFUN([AC_DEPLIBS_CHECK_METHOD])])
+m4_ifndef([AC_LIBTOOL_PROG_COMPILER_NO_RTTI], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_NO_RTTI])])
+m4_ifndef([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE], [AC_DEFUN([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE])])
+m4_ifndef([AC_LIBTOOL_PROG_COMPILER_PIC], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_PIC])])
+m4_ifndef([AC_LIBTOOL_PROG_LD_SHLIBS], [AC_DEFUN([AC_LIBTOOL_PROG_LD_SHLIBS])])
+m4_ifndef([AC_LIBTOOL_POSTDEP_PREDEP], [AC_DEFUN([AC_LIBTOOL_POSTDEP_PREDEP])])
+m4_ifndef([LT_AC_PROG_EGREP], [AC_DEFUN([LT_AC_PROG_EGREP])])
+m4_ifndef([LT_AC_PROG_SED], [AC_DEFUN([LT_AC_PROG_SED])])
+m4_ifndef([_LT_CC_BASENAME], [AC_DEFUN([_LT_CC_BASENAME])])
+m4_ifndef([_LT_COMPILER_BOILERPLATE], [AC_DEFUN([_LT_COMPILER_BOILERPLATE])])
+m4_ifndef([_LT_LINKER_BOILERPLATE], [AC_DEFUN([_LT_LINKER_BOILERPLATE])])
+m4_ifndef([_AC_PROG_LIBTOOL], [AC_DEFUN([_AC_PROG_LIBTOOL])])
+m4_ifndef([AC_LIBTOOL_SETUP], [AC_DEFUN([AC_LIBTOOL_SETUP])])
+m4_ifndef([_LT_AC_CHECK_DLFCN], [AC_DEFUN([_LT_AC_CHECK_DLFCN])])
+m4_ifndef([AC_LIBTOOL_SYS_DYNAMIC_LINKER], [AC_DEFUN([AC_LIBTOOL_SYS_DYNAMIC_LINKER])])
+m4_ifndef([_LT_AC_TAGCONFIG], [AC_DEFUN([_LT_AC_TAGCONFIG])])
+m4_ifndef([AC_DISABLE_FAST_INSTALL], [AC_DEFUN([AC_DISABLE_FAST_INSTALL])])
+m4_ifndef([_LT_AC_LANG_CXX], [AC_DEFUN([_LT_AC_LANG_CXX])])
+m4_ifndef([_LT_AC_LANG_F77], [AC_DEFUN([_LT_AC_LANG_F77])])
+m4_ifndef([_LT_AC_LANG_GCJ], [AC_DEFUN([_LT_AC_LANG_GCJ])])
+m4_ifndef([AC_LIBTOOL_LANG_C_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_C_CONFIG])])
+m4_ifndef([_LT_AC_LANG_C_CONFIG], [AC_DEFUN([_LT_AC_LANG_C_CONFIG])])
+m4_ifndef([AC_LIBTOOL_LANG_CXX_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_CXX_CONFIG])])
+m4_ifndef([_LT_AC_LANG_CXX_CONFIG], [AC_DEFUN([_LT_AC_LANG_CXX_CONFIG])])
+m4_ifndef([AC_LIBTOOL_LANG_F77_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_F77_CONFIG])])
+m4_ifndef([_LT_AC_LANG_F77_CONFIG], [AC_DEFUN([_LT_AC_LANG_F77_CONFIG])])
+m4_ifndef([AC_LIBTOOL_LANG_GCJ_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_GCJ_CONFIG])])
+m4_ifndef([_LT_AC_LANG_GCJ_CONFIG], [AC_DEFUN([_LT_AC_LANG_GCJ_CONFIG])])
+m4_ifndef([AC_LIBTOOL_LANG_RC_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_RC_CONFIG])])
+m4_ifndef([_LT_AC_LANG_RC_CONFIG], [AC_DEFUN([_LT_AC_LANG_RC_CONFIG])])
+m4_ifndef([AC_LIBTOOL_CONFIG], [AC_DEFUN([AC_LIBTOOL_CONFIG])])
+m4_ifndef([_LT_AC_FILE_LTDLL_C], [AC_DEFUN([_LT_AC_FILE_LTDLL_C])])
+m4_ifndef([_LT_REQUIRED_DARWIN_CHECKS], [AC_DEFUN([_LT_REQUIRED_DARWIN_CHECKS])])
+m4_ifndef([_LT_AC_PROG_CXXCPP], [AC_DEFUN([_LT_AC_PROG_CXXCPP])])
+m4_ifndef([_LT_PREPARE_SED_QUOTE_VARS], [AC_DEFUN([_LT_PREPARE_SED_QUOTE_VARS])])
+m4_ifndef([_LT_PROG_ECHO_BACKSLASH], [AC_DEFUN([_LT_PROG_ECHO_BACKSLASH])])
+m4_ifndef([_LT_PROG_F77], [AC_DEFUN([_LT_PROG_F77])])
+m4_ifndef([_LT_PROG_FC], [AC_DEFUN([_LT_PROG_FC])])
+m4_ifndef([_LT_PROG_CXX], [AC_DEFUN([_LT_PROG_CXX])])
diff --git a/objects/Makefile.am b/objects/Makefile.am
new file mode 100644
index 0000000..fea2030
--- /dev/null
+++ b/objects/Makefile.am
@@ -0,0 +1,67 @@
+AM_CPPFLAGS = \
+ -I$(top_srcdir)\
+ -DCUR_WORKING_DIR='"@BASE_CUR_WORKING_DIR@/objects"'
+
+noinst_LIBRARIES = librtfl-objects.a
+
+bin_PROGRAMS = rtfl-objbase rtfl-objcount rtfl-objview
+
+rtfl_objbase_SOURCES = rtfl_objbase.cc
+
+rtfl_objbase_LDADD = \
+ librtfl-objects.a \
+ ../common/librtfl-tools.a \
+ ../lout/liblout.a
+
+librtfl_objects_a_SOURCES = \
+ objdelete_controller.hh \
+ objdelete_controller.cc \
+ objects_buffer.hh \
+ objects_buffer.cc \
+ objects_parser.hh \
+ objects_parser.cc \
+ objects_writer.hh \
+ objects_writer.cc \
+ objident_controller.hh \
+ objident_controller.cc
+
+rtfl_objcount_SOURCES = \
+ objcount_controller.hh \
+ objcount_controller.cc \
+ objcount_window.hh \
+ objcount_window.cc \
+ rtfl_objcount.cc
+
+rtfl_objcount_LDADD = \
+ librtfl-objects.a \
+ ../common/librtfl-common.a \
+ ../common/librtfl-tools.a \
+ ../lout/liblout.a \
+ @LIBFLTK_LIBS@
+
+rtfl_objview_SOURCES = \
+ objview_commands.hh \
+ objview_commands.cc \
+ objview_graph.hh \
+ objview_graph.cc \
+ objview_controller.hh \
+ objview_controller.cc \
+ objview_stacktrace.hh \
+ objview_stacktrace.cc \
+ objview_window.hh \
+ objview_window.cc \
+ rtfl_objview.cc
+
+rtfl_objview_LDADD = \
+ librtfl-objects.a \
+ ../common/librtfl-common.a \
+ ../common/librtfl-tools.a \
+ ../dwr/libDw-rtfl.a \
+ ../dw/libDw-fltk.a \
+ ../dw/libDw-core.a \
+ ../lout/liblout.a \
+ @LIBFLTK_LIBS@
+
+if USE_GRAPH2
+rtfl_objview_LDADD += @GRAPHVIZ_LIBS@
+endif
diff --git a/objects/objcount_controller.cc b/objects/objcount_controller.cc
new file mode 100644
index 0000000..b7ce4e7
--- /dev/null
+++ b/objects/objcount_controller.cc
@@ -0,0 +1,114 @@
+/*
+ * RTFL
+ *
+ * Copyright 2013-2015 Sebastian Geerken <sgeerken@dillo.org>
+ *
+ * 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/>.
+ */
+
+#include "objcount_controller.hh"
+
+using namespace rtfl::tools;
+
+namespace rtfl {
+
+namespace objects {
+
+void ObjCountController::objMsg (CommonLineInfo *info, const char *id,
+ const char *aspect, int prio,
+ const char *message)
+{
+ table->registerObject (id);
+}
+
+void ObjCountController::objMark (CommonLineInfo *info, const char *id,
+ const char *aspect, int prio,
+ const char *message)
+{
+ table->registerObject (id);
+}
+
+ void ObjCountController::objMsgStart (CommonLineInfo *info, const char *id)
+{
+ table->registerObject (id);
+}
+
+void ObjCountController::objMsgEnd (CommonLineInfo *info, const char *id)
+{
+ table->registerObject (id);
+}
+
+void ObjCountController::objEnter (CommonLineInfo *info, const char *id,
+ const char *aspect, int prio,
+ const char *funname, const char *args)
+{
+ table->registerObject (id);
+}
+
+void ObjCountController::objLeave (CommonLineInfo *info, const char *id,
+ const char *vals)
+{
+ table->registerObject (id);
+}
+
+void ObjCountController::objCreate (CommonLineInfo *info, const char *id,
+ const char *klass)
+{
+ table->createObject (id, klass);
+}
+
+void ObjCountController::objIdent (CommonLineInfo *info, const char *id1,
+ const char *id2)
+{
+ // TODO Is this not done by ObjdentController?
+ table->addIdentity (id1, id2);
+}
+
+void ObjCountController::objNoIdent (CommonLineInfo *info)
+{
+}
+
+void ObjCountController::objAssoc (CommonLineInfo *info, const char *parent,
+ const char *child)
+{
+ table->registerObject (parent);
+ table->registerObject (child);
+}
+
+void ObjCountController::objSet (CommonLineInfo *info, const char *id,
+ const char *var, const char *val)
+{
+ table->registerObject (id);
+}
+
+void ObjCountController::objClassColor (CommonLineInfo *info, const char *klass,
+ const char *color)
+{
+ table->setClassColor (klass, color);
+}
+
+void ObjCountController::objObjectColor (CommonLineInfo *info, const char *id,
+ const char *color)
+{
+ table->registerObject (id);
+}
+
+void ObjCountController::objDelete (CommonLineInfo *info, const char *id)
+{
+ table->deleteObject (id);
+}
+
+} // namespace objects
+
+} // namespace rtfl
diff --git a/objects/objcount_controller.hh b/objects/objcount_controller.hh
new file mode 100644
index 0000000..6af5ba7
--- /dev/null
+++ b/objects/objcount_controller.hh
@@ -0,0 +1,50 @@
+#ifndef __OBJECTS_OBJCOUNT_CONTROLLER_HH__
+#define __OBJECTS_OBJCOUNT_CONTROLLER_HH__
+
+#include "objects_parser.hh"
+#include "objcount_window.hh"
+
+namespace rtfl {
+
+namespace objects {
+
+class ObjCountController: public ObjectsControllerBase
+{
+private:
+ ObjCountTable *table;
+
+public:
+ ObjCountController (ObjCountTable *table) { this->table = table; }
+
+ void objMsg (tools::CommonLineInfo *info, const char *id,
+ const char *aspect, int prio, const char *message);
+ void objMark (tools::CommonLineInfo *info, const char *id,
+ const char *aspect, int prio, const char *message);
+ void objMsgStart (tools::CommonLineInfo *info, const char *id);
+ void objMsgEnd (tools::CommonLineInfo *info, const char *id);
+ void objEnter (tools::CommonLineInfo *info, const char *id,
+ const char *aspect, int prio, const char *funname,
+ const char *args);
+ void objLeave (tools::CommonLineInfo *info, const char *id,
+ const char *vals);
+ void objCreate (tools::CommonLineInfo *info, const char *id,
+ const char *klass);
+ void objIdent (tools::CommonLineInfo *info, const char *id1,
+ const char *id2);
+ void objNoIdent (tools::CommonLineInfo *info);
+ void objAssoc (tools::CommonLineInfo *info, const char *parent,
+ const char *child);
+ void objSet (tools::CommonLineInfo *info, const char *id, const char *var,
+ const char *val);
+ void objClassColor (tools::CommonLineInfo *info, const char *klass,
+ const char *color);
+ void objObjectColor (tools::CommonLineInfo *info, const char *id,
+ const char *color);
+ void objDelete (tools::CommonLineInfo *info, const char *id);
+};
+
+} // namespace objects
+
+} // namespace rtfl
+
+#endif // __OBJECTS_OBJCOUNT_CONTROLLER_HH__
diff --git a/objects/objcount_window.cc b/objects/objcount_window.cc
new file mode 100644
index 0000000..d7adf06
--- /dev/null
+++ b/objects/objcount_window.cc
@@ -0,0 +1,445 @@
+/*
+ * RTFL
+ *
+ * Copyright 2013-2015 Sebastian Geerken <sgeerken@dillo.org>
+ *
+ * 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/>.
+ */
+
+#include "objcount_window.hh"
+#include "common/about.hh"
+
+#include <FL/Fl_Menu_Bar.H>
+#include <FL/Fl_Menu_Item.H>
+#include <FL/fl_draw.H>
+
+using namespace lout::container::typed;
+using namespace lout::object;
+using namespace lout::misc;
+
+namespace rtfl {
+
+namespace objects {
+
+ObjCountTable::Class::Class (const char *name)
+{
+ this->name = strdup (name);
+ count = new lout::misc::SimpleVector<int> (1);
+ count->increase ();
+ *(count->getLastRef()) = 0;
+}
+
+
+ObjCountTable::Class::~Class ()
+{
+ free (name);
+ delete count;
+}
+
+
+int ObjCountTable::Class::compareTo(Comparable *other)
+{
+ return strcmp (name, ((Class*)other)->name);
+}
+
+
+void ObjCountTable::Class::create ()
+{
+ (*(count->getLastRef()))++;
+}
+
+
+void ObjCountTable::Class::remove ()
+{
+ (*(count->getLastRef()))--;
+}
+
+
+void ObjCountTable::Class::newSnapshot ()
+{
+ int c = *(count->getLastRef());
+ count->increase ();
+ *(count->getLastRef()) = c;
+}
+
+
+// ----------------------------------------------------------------------
+
+
+int ObjCountTable::Object::classSernoGlobal = 0;
+
+
+ObjCountTable::Object::Object (Class *klass)
+{
+ setClass (klass);
+ refCount = 0;
+}
+
+
+ObjCountTable::Object::~Object ()
+{
+}
+
+
+void ObjCountTable::Object::setClass (Class *klass)
+{
+ this->klass = klass;
+ classSerno = classSernoGlobal++;
+}
+
+
+// ----------------------------------------------------------------------
+
+
+ObjCountTable::ObjectRef::ObjectRef (rtfl::objects::ObjCountTable::Object
+ *object)
+{
+ this->object = object;
+ object->ref ();
+}
+
+
+ObjCountTable::ObjectRef::~ObjectRef ()
+{
+ object->unref ();
+}
+
+
+// ----------------------------------------------------------------------
+
+
+ObjCountTable::ObjCountTable (int x, int y, int width, int height,
+ const char *label) :
+ Fl_Table (x, y, width, height, label)
+{
+ rows (0);
+ row_header (true);
+ row_height_all (20);
+ row_resize (false);
+
+ cols (1);
+ col_header (false);
+ row_header_width (200);
+ col_width_all (80);
+ col_resize (true);
+
+ end();
+
+ objects = new HashTable<String, ObjectRef> (true, true);
+ identities = new HashTable<String, String> (true, true);
+ identitiesRev = new HashTable<String, String> (false, false);
+ classes = new HashTable<String, Class> (true, false);
+ classesList = new Vector<Class> (1, true);
+
+ ensureClass ("<unknown>");
+}
+
+
+ObjCountTable::~ObjCountTable()
+{
+ delete objects;
+ delete identitiesRev;
+ delete identities;
+ delete classes;
+ delete classesList;
+}
+
+
+void ObjCountTable::draw_cell (TableContext context, int row, int col, int x,
+ int y, int width, int height)
+{
+ switch (context) {
+ case CONTEXT_COL_HEADER:
+ break;
+
+ case CONTEXT_ROW_HEADER:
+ fl_push_clip (x, y, width, height);
+ fl_draw_box (FL_THIN_UP_BOX, x, y, width, height, row_header_color ());
+ fl_color (FL_BLACK);
+ fl_draw (classesList->get(row)->name, x, y, width, height, FL_ALIGN_LEFT);
+ fl_pop_clip ();
+ break;
+
+ case CONTEXT_CELL:
+ fl_push_clip (x, y, width, height);
+ fl_color (FL_WHITE);
+ fl_rectf (x, y, width, height);
+ fl_color (FL_BLACK);
+ char buf[6];
+ snprintf (buf, 6, "%d", classesList->get(row)->count->get (col));
+ fl_draw (buf, x, y, width, height, FL_ALIGN_RIGHT);
+ fl_pop_clip ();
+ break;
+
+ default:
+ // compiler happyness
+ break;
+ }
+}
+
+
+ObjCountTable::Class *ObjCountTable::ensureClass (const char *className)
+{
+ String key (className);
+ Class *klass = classes->get (&key);
+
+ if (klass == NULL) {
+ klass = new Class (className);
+ classes->put (new String (className), klass);
+
+ int i = classesList->bsearch (klass, false);
+ classesList->insert (klass, i);
+ for (int j = i; j < classesList->size (); j++)
+ classesList->get(j)->index = j;
+
+ rows (rows () + 1);
+ }
+
+ return klass;
+}
+
+void ObjCountTable::createObject (const char *id, const char *className)
+{
+ Class *klass = ensureClass (className);
+
+ String key (id);
+ ObjectRef *objectRef = objects->get (&key);
+
+ if (objectRef != NULL) {
+ objectRef->object->getClass()->remove ();
+ objectRef->object->setClass (klass);
+ } else {
+ rtfl::objects::ObjCountTable::Object *object;
+ String *id2 = identities->get (&key);
+ if (id2) {
+ ObjectRef *objRef2 = objects->get (id2);
+ assert (objRef2 != NULL);
+ object = objRef2->object;
+ } else
+ object = new rtfl::objects::ObjCountTable::Object (klass);
+
+ objectRef = new ObjectRef (object);
+ objects->put (new String (id), objectRef);
+ }
+
+ klass->create ();
+ damage_zone(klass->index, cols () - 1, klass->index, cols () - 1);
+}
+
+
+void ObjCountTable::deleteObject (const char *id)
+{
+ String key (id);
+ ObjectRef *objectRef = objects->get (&key);
+ if (objectRef != NULL) {
+ objectRef->object->getClass()->remove ();
+ damage_zone(objectRef->object->getClass()->index,cols () - 1,
+ objectRef->object->getClass()->index, cols () - 1);
+
+ objects->remove (&key);
+
+ String *key2 = identities->get (&key);
+ if (key2) {
+ identitiesRev->remove (key2);
+ identities->remove (&key);
+ } else {
+ key2 = identitiesRev->get (&key);
+ if (key2) {
+ identitiesRev->remove (&key);
+ identities->remove (key2);
+ }
+ }
+ }
+}
+
+
+void ObjCountTable::registerObject (const char *id)
+{
+ String key (id);
+ if (!objects->contains (&key))
+ createObject (id, "<unknown>");
+}
+
+
+void ObjCountTable::addIdentity (const char *id1, const char *id2)
+{
+ if (strcmp (id1, id2) != 0) {
+ // Note: An ObjectRef (which is != NULL) points always to an Object.
+ String key1 (id1), key2 (id2);
+ ObjectRef *objRef1 = objects->get (&key1),
+ *objRef2 = objects->get (&key2);
+
+ if (objRef1 == NULL && objRef2 == NULL) {
+ // Neither defined: create both.
+ registerObject (id1);
+ insertIdentity (id2, id1);
+ registerObject (id2);
+ } else if (objRef1 == NULL) {
+ // First not defined, but second: create from second.
+ insertIdentity (id2, id1);
+ registerObject (id2);
+ } else if (objRef2 == NULL) {
+ // Vice versa.
+ insertIdentity (id1, id2);
+ registerObject (id1);
+ } else {
+ // Both already defined ...
+ if (objRef1->object == objRef2->object)
+ // ... for same object: caller's fault.
+ fprintf (stderr, "WARNING: Identity of '%s' and '%s' added twice.",
+ id1, id2);
+ else {
+ // ... for different objects.
+ if (objRef1->object->getClassSerno () >
+ objRef2->object->getClassSerno ()) {
+ // Class definition of first object more recent, so assign it to
+ // second.
+ objRef2->object->getClass()->remove ();
+ damage_zone(objRef2->object->getClass()->index,cols () - 1,
+ objRef2->object->getClass()->index, cols () - 1);
+ objRef2->object->unref ();
+ objRef2->object = objRef1->object;
+ objRef2->object->ref ();
+ } else {
+ // Vice versa.
+ objRef1->object->getClass()->remove ();
+ damage_zone(objRef1->object->getClass()->index,cols () - 1,
+ objRef1->object->getClass()->index, cols () - 1);
+ objRef1->object->unref ();
+ objRef1->object = objRef2->object;
+ objRef1->object->ref ();
+ }
+ }
+ }
+ }
+}
+
+
+void ObjCountTable::insertIdentity (const char *id1, const char *id2)
+{
+ String *s1 = new String (id1), *s2 = new String (id2);
+ identities->put (s1, s2);
+ identitiesRev->put (s2, s1);
+}
+
+
+void ObjCountTable::setClassColor (const char *klass, const char *color)
+{
+}
+
+
+void ObjCountTable::newSnapshot ()
+{
+ for (int i = 0; i < classesList->size (); i++)
+ classesList->get(i)->newSnapshot ();
+
+ cols (cols () + 1);
+}
+
+
+void ObjCountTable::removeOldestSnapshot ()
+{
+}
+
+
+// ----------------------------------------------------------------------
+
+
+ObjCountWindow::ObjCountWindow (int width, int height, const char *title) :
+ Fl_Window (width, height, title)
+{
+ int menuHeight = 24;
+
+ callback(windowCallback, NULL);
+ box(FL_NO_BOX);
+
+ Fl_Menu_Bar *menu = new Fl_Menu_Bar(0, 0, width, menuHeight);
+
+ table = new ObjCountTable (0, menuHeight, width, height - menuHeight);
+
+ Fl_Menu_Item menuItems[] = {
+ { "&File", 0, 0, 0, FL_SUBMENU, 0, 0, 0, 0 },
+ { "Quit", FL_COMMAND + 'q', quit, this, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+
+ { "&Snapshot", 0, 0, 0, FL_SUBMENU, 0, 0, 0, 0 },
+ { "New &snapshot", FL_COMMAND + 's', newSnapshot, this, 0, 0, 0, 0, 0 },
+ { "&Delete oldest", FL_COMMAND + 'd', removeOldestSnapshot, this,
+ 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+
+ { "&Help", 0, 0, 0, FL_SUBMENU, 0, 0, 0, 0 },
+ { "&About RTFL", 0, about, this, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0 }
+ };
+ menu->copy(menuItems);
+
+ resizable(table);
+
+ aboutWindow = NULL;
+}
+
+
+ObjCountWindow::~ObjCountWindow ()
+{
+ if (aboutWindow)
+ delete aboutWindow;
+}
+
+
+void ObjCountWindow::windowCallback (Fl_Widget *widget, void *data)
+{
+ // Ignore escape key. TODO Looks rather hackish to me.
+ if (Fl::event_key() != FL_Escape)
+ quit (widget, data);
+}
+
+
+void ObjCountWindow::quit (Fl_Widget *widget, void *data)
+{
+ exit (0);
+}
+
+
+void ObjCountWindow::newSnapshot (Fl_Widget *widget, void *data)
+{
+ ObjCountWindow *window = (ObjCountWindow*)data;
+ window->table->newSnapshot ();
+}
+
+
+void ObjCountWindow::removeOldestSnapshot (Fl_Widget *widget, void *data)
+{
+ ObjCountWindow *window = (ObjCountWindow*)data;
+ window->table->removeOldestSnapshot ();
+}
+
+
+void ObjCountWindow::about (Fl_Widget *widget, void *data)
+{
+ ObjCountWindow *window = (ObjCountWindow*)data;
+
+ if (window->aboutWindow == NULL)
+ window->aboutWindow =
+ new common::AboutWindow("rtfl-objcount", "",
+ common::AboutWindow::HEIGHT_SIMPLE);
+ window->aboutWindow->show ();
+}
+
+
+} // namespace objects
+
+} // namespace rtfl
diff --git a/objects/objcount_window.hh b/objects/objcount_window.hh
new file mode 100644
index 0000000..485be55
--- /dev/null
+++ b/objects/objcount_window.hh
@@ -0,0 +1,118 @@
+#ifndef __OBJECTS_OBJCOUNT_WINDOW_HH__
+#define __OBJECTS_OBJCOUNT_WINDOW_HH__
+
+#include <FL/Fl_Window.H>
+#include <FL/Fl_Table.H>
+
+#include "lout/object.hh"
+#include "lout/container.hh"
+#include "lout/misc.hh"
+
+namespace rtfl {
+
+namespace objects {
+
+class ObjCountTable : public Fl_Table
+{
+private:
+ class Class: public lout::object::Comparable
+ {
+ public:
+ char *name;
+ int index;
+ lout::misc::SimpleVector<int> *count;
+
+ Class (const char *name);
+ ~Class ();
+
+ int compareTo(Comparable *other);
+
+ void create ();
+ void remove ();
+ void newSnapshot ();
+ };
+
+ class Object: public lout::object::Object
+ {
+ private:
+ static int classSernoGlobal;
+
+ Class *klass;
+ int classSerno;
+ int refCount;
+
+ ~Object ();
+
+ public:
+ Object (Class *klass);
+
+ inline void ref () { refCount++; }
+ inline void unref () { if (--refCount == 0) delete this; }
+
+ inline Class *getClass () { return klass; }
+ void setClass (Class *klass);
+ inline int getClassSerno () { return classSerno; }
+ };
+
+ class ObjectRef: public lout::object::Object
+ {
+ public:
+ rtfl::objects::ObjCountTable::Object *object;
+
+ ObjectRef (rtfl::objects::ObjCountTable::Object *object);
+ ~ObjectRef ();
+ };
+
+ lout::container::typed::HashTable<lout::object::String, ObjectRef> *objects;
+ lout::container::typed::HashTable<lout::object::String, lout::object::String>
+ *identities, *identitiesRev;
+ lout::container::typed::HashTable<lout::object::String, Class> *classes;
+ lout::container::typed::Vector<Class> *classesList;
+
+ Class *ensureClass (const char *className);
+ void insertIdentity (const char *id1, const char *id2);
+
+public:
+ ObjCountTable (int x, int y, int width, int height,
+ const char *label = NULL);
+ ~ObjCountTable();
+
+ void draw_cell (TableContext context, int row, int col, int x, int y,
+ int width, int height);
+
+ void createObject (const char *id, const char *className);
+ void deleteObject (const char *id);
+ void registerObject (const char *id);
+ void addIdentity (const char *id1, const char *id2);
+ void setClassColor (const char *klass, const char *color);
+ void newSnapshot ();
+ void removeOldestSnapshot ();
+};
+
+
+class ObjCountWindow: public Fl_Window
+{
+private:
+ Fl_Window *aboutWindow;
+ ObjCountTable *table;
+
+ static void windowCallback (Fl_Widget *widget, void *data);
+ static void quit (Fl_Widget *widget, void *data);
+ static void newSnapshot (Fl_Widget *widget, void *data);
+ static void removeOldestSnapshot (Fl_Widget *widget, void *data);
+ static void about (Fl_Widget *widget, void *data);
+
+public:
+ ObjCountWindow (int width, int height, const char *title);
+ ~ObjCountWindow ();
+
+ inline ObjCountTable *getTable () { return table; }
+};
+
+
+
+} // namespace objects
+
+} // namespace rtfl
+
+#endif // __OBJECTS_OBJCOUNT_WINDOW_HH__
diff --git a/objects/objdelete_controller.cc b/objects/objdelete_controller.cc
new file mode 100644
index 0000000..8224029
--- /dev/null
+++ b/objects/objdelete_controller.cc
@@ -0,0 +1,204 @@
+/*
+ * RTFL
+ *
+ * Copyright 2015 Sebastian Geerken <sgeerken@dillo.org>
+ *
+ * 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; with the following exception:
+ *
+ * The copyright holders of RTFL give you permission to link this file
+ * statically or dynamically against all versions of the graphviz
+ * library, which are published by AT&T Corp. under one of the following
+ * licenses:
+ *
+ * - Common Public License version 1.0 as published by International
+ * Business Machines Corporation (IBM), or
+ * - Eclipse Public License version 1.0 as published by the Eclipse
+ * Foundation.
+ *
+ * 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/>.
+ */
+
+#include "objdelete_controller.hh"
+
+using namespace lout::object;
+using namespace lout::misc;
+using namespace lout::container::typed;
+using namespace rtfl::tools;
+
+namespace rtfl {
+
+namespace objects {
+
+ObjDeleteController::ObjInfo::ObjInfo (const char *id)
+{
+ numCreated = 0;
+ numDeleted = 0;
+ origId = strdup (id);
+ mappedId = strdup (id);
+}
+
+ObjDeleteController::ObjInfo::~ObjInfo ()
+{
+ free (origId);
+ free (mappedId);
+}
+
+void ObjDeleteController::ObjInfo::use ()
+{
+ numCreated = max (numCreated, 1);
+}
+
+void ObjDeleteController::ObjInfo::objCreate ()
+{
+ numCreated++;
+}
+
+void ObjDeleteController::ObjInfo::objDelete ()
+{
+ numCreated--;
+ if (numCreated <= 0) {
+ numCreated = 0;
+ numDeleted++;
+
+ free (mappedId);
+ mappedId = (char*) malloc ((strlen (origId) + 10 + 1) * sizeof (char));
+ sprintf (mappedId, "%s-%d", origId, numDeleted);
+ }
+}
+
+ObjDeleteController::ObjDeleteController (ObjectsController *successor)
+{
+ this->successor = successor;
+ successor->setObjectsSource (this);
+ setObjectsSink (successor);
+
+ objInfos = new HashTable<String, ObjInfo> (true, true);
+}
+
+ObjDeleteController::~ObjDeleteController ()
+{
+ delete objInfos;
+}
+
+void ObjDeleteController::objMsg (CommonLineInfo *info, const char *id,
+ const char *aspect, int prio,
+ const char *message)
+{
+ successor->objMsg (info, mapId (id), aspect, prio, message);
+}
+
+void ObjDeleteController::objMark (CommonLineInfo *info, const char *id,
+ const char *aspect, int prio,
+ const char *message)
+{
+ successor->objMark (info, mapId (id), aspect, prio, message);
+}
+
+void ObjDeleteController::objMsgStart (CommonLineInfo *info, const char *id)
+{
+ successor->objMsgStart (info, mapId (id));
+}
+
+void ObjDeleteController::objMsgEnd (CommonLineInfo *info, const char *id)
+{
+ successor->objMsgEnd (info, mapId (id));
+}
+
+void ObjDeleteController::objEnter (CommonLineInfo *info, const char *id,
+ const char *aspect, int prio,
+ const char *funname, const char *args)
+{
+ successor->objEnter (info, mapId (id), aspect, prio, funname, args);
+}
+
+void ObjDeleteController::objLeave (CommonLineInfo *info, const char *id,
+ const char *vals)
+{
+ successor->objLeave (info, mapId (id), vals);
+}
+
+void ObjDeleteController::objCreate (CommonLineInfo *info, const char *id,
+ const char *klass)
+{
+ ensureObjInfo(id)->objCreate ();
+ successor->objCreate (info, mapId (id), klass);
+}
+
+void ObjDeleteController::objIdent (CommonLineInfo *info, const char *id1,
+ const char *id2)
+{
+ successor->objIdent (info, mapId (id1), mapId (id2));
+}
+
+void ObjDeleteController::objNoIdent (CommonLineInfo *info)
+{
+ successor->objNoIdent (info);
+}
+
+void ObjDeleteController::objAssoc (CommonLineInfo *info, const char *parent,
+ const char *child)
+{
+ successor->objAssoc (info, mapId (parent), mapId (child));
+}
+
+void ObjDeleteController::objSet (CommonLineInfo *info, const char *id,
+ const char *var, const char *val)
+{
+ successor->objSet (info, mapId (id), var, val);
+}
+
+void ObjDeleteController::objClassColor (CommonLineInfo *info,
+ const char *klass, const char *color)
+{
+ successor->objClassColor (info, klass, color);
+}
+
+void ObjDeleteController::objObjectColor (CommonLineInfo *info, const char *id,
+ const char *color)
+{
+ successor->objObjectColor (info, mapId (id), color);
+}
+
+void ObjDeleteController::objDelete (CommonLineInfo *info, const char *id)
+{
+ successor->objDelete (info, mapId (id));
+ ensureObjInfo(id)->objDelete ();
+}
+
+const char *ObjDeleteController::mapId (const char *id)
+{
+ ObjInfo *objInfo = ensureObjInfo (id);
+ objInfo->use ();
+ return objInfo->getMappedId ();
+}
+
+ObjDeleteController::ObjInfo *ObjDeleteController::getObjInfo (const char *id)
+{
+ String key (id);
+ return objInfos->get (&key);
+}
+
+ObjDeleteController::ObjInfo *ObjDeleteController::ensureObjInfo (const char
+ *id)
+{
+ ObjInfo *objInfo = getObjInfo (id);
+ if (objInfo == NULL) {
+ objInfo = new ObjInfo (id);
+ objInfos->put (new String (id), objInfo);
+ }
+ return objInfo;
+}
+
+} // namespace objects
+
+} // namespace rtfl
+
diff --git a/objects/objdelete_controller.hh b/objects/objdelete_controller.hh
new file mode 100644
index 0000000..eccee06
--- /dev/null
+++ b/objects/objdelete_controller.hh
@@ -0,0 +1,78 @@
+#ifndef __OBJECTS_OBJDELETE_CONTROLLER_HH__
+#define __OBJECTS_OBJDELETE_CONTROLLER_HH__
+
+#include "objects_parser.hh"
+#include "common/tools.hh"
+
+namespace rtfl {
+
+namespace objects {
+
+/**
+ * \brief Processes `obj-delete` specially and maps ids of deleted objects to
+ * new ones, if they are reused.
+ */
+class ObjDeleteController: public ObjectsControllerBase
+{
+private:
+ class ObjInfo: public lout::object::Object
+ {
+ private:
+ int numCreated, numDeleted;
+ char *origId, *mappedId;
+
+ public:
+ ObjInfo (const char *id);
+ ~ObjInfo ();
+
+ void use ();
+ void objCreate ();
+ void objDelete ();
+
+ inline const char *getMappedId () { return mappedId; }
+ };
+
+ ObjectsController *successor;
+ lout::container::typed::HashTable<lout::object::String, ObjInfo> *objInfos;
+
+ const char *mapId (const char *id);
+ bool objInfoCreated (const char *id);
+ ObjInfo *getObjInfo (const char *id);
+ ObjInfo *ensureObjInfo (const char *id);
+
+public:
+ ObjDeleteController (ObjectsController *successor);
+ ~ObjDeleteController ();
+
+ void objMsg (tools::CommonLineInfo *info, const char *id,
+ const char *aspect, int prio, const char *message);
+ void objMark (tools::CommonLineInfo *info, const char *id,
+ const char *aspect, int prio, const char *message);
+ void objMsgStart (tools::CommonLineInfo *info, const char *id);
+ void objMsgEnd (tools::CommonLineInfo *info, const char *id);
+ void objEnter (tools::CommonLineInfo *info, const char *id,
+ const char *aspect, int prio, const char *funname,
+ const char *args);
+ void objLeave (tools::CommonLineInfo *info, const char *id,
+ const char *vals);
+ void objCreate (tools::CommonLineInfo *info, const char *id,
+ const char *klass);
+ void objIdent (tools::CommonLineInfo *info, const char *id1,
+ const char *id2);
+ void objNoIdent (tools::CommonLineInfo *info);
+ void objAssoc (tools::CommonLineInfo *info, const char *parent,
+ const char *child);
+ void objSet (tools::CommonLineInfo *info, const char *id, const char *var,
+ const char *val);
+ void objClassColor (tools::CommonLineInfo *info, const char *klass,
+ const char *color);
+ void objObjectColor (tools::CommonLineInfo *info, const char *id,
+ const char *color);
+ void objDelete (tools::CommonLineInfo *info, const char *id);
+};
+
+} // namespace objects
+
+} // namespace rtfl
+
+#endif // __OBJECTS_OBJDELETE_CONTROLLER_HH__
diff --git a/objects/objects_buffer.cc b/objects/objects_buffer.cc
new file mode 100644
index 0000000..e669142
--- /dev/null
+++ b/objects/objects_buffer.cc
@@ -0,0 +1,281 @@
+/*
+ * RTFL
+ *
+ * Copyright 2015 Sebastian Geerken <sgeerken@dillo.org>
+ *
+ * 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; with the following exception:
+ *
+ * The copyright holders of RTFL give you permission to link this file
+ * statically or dynamically against all versions of the graphviz
+ * library, which are published by AT&T Corp. under one of the following
+ * licenses:
+ *
+ * - Common Public License version 1.0 as published by International
+ * Business Machines Corporation (IBM), or
+ * - Eclipse Public License version 1.0 as published by the Eclipse
+ * Foundation.
+ *
+ * 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/>.
+ */
+
+#include "objects_buffer.hh"
+
+using namespace lout::object;
+using namespace lout::container::typed;
+using namespace rtfl::tools;
+
+namespace rtfl {
+
+namespace objects {
+
+ObjectsBuffer::ObjectCommand::ObjectCommand (CommandType type,
+ CommonLineInfo *info,
+ const char *fmt, ...)
+{
+ this->type = type;
+ this->info.fileName = strdup (info->fileName);
+ this->info.lineNo = info->lineNo;
+ this->info.processId = info->processId;
+ this->info.completeLine = strdup (info->completeLine);
+
+ numArgs = strlen (fmt);
+ args = new Arg[numArgs];
+
+ va_list vargs;
+ va_start (vargs, fmt);
+
+ char *s;
+ for (int i = 0; fmt[i]; i++) {
+ args[i].type = fmt[i];
+ switch (fmt[i]) {
+ case 'd':
+ args[i].d = va_arg(vargs, int);
+ break;
+
+ case 's':
+ s = va_arg (vargs, char*);
+ args[i].s = s ? strdup (s) : NULL;
+ break;
+ }
+ }
+}
+
+ObjectsBuffer::ObjectCommand::~ObjectCommand ()
+{
+ free (info.fileName);
+ free (info.completeLine);
+
+ for (int i = 0; i < numArgs; i++)
+ if (args[i].type == 's' && args[i].s)
+ free (args[i].s);
+
+ delete[] args;
+}
+
+// ----------------------------------------------------------------------
+
+ObjectsBuffer::ObjectsBuffer (ObjectsController *successor)
+{
+ this->successor = successor;
+ successor->setObjectsSource (this);
+
+ commandsQueue = new Vector<ObjectCommand> (1, true);
+ queued = false;
+
+ setObjectsSink (successor);
+}
+
+ObjectsBuffer::~ObjectsBuffer ()
+{
+ delete commandsQueue;
+}
+
+void ObjectsBuffer::objMsg (CommonLineInfo *info, const char *id,
+ const char *aspect, int prio, const char *message)
+{
+ process (new ObjectCommand (MSG, info, "ssds", id, aspect, prio, message));
+}
+
+void ObjectsBuffer::objMark (CommonLineInfo *info, const char *id,
+ const char *aspect, int prio, const char *message)
+{
+ process (new ObjectCommand (MARK, info, "ssds", id, aspect, prio, message));
+}
+
+void ObjectsBuffer::objMsgStart (CommonLineInfo *info, const char *id)
+{
+ process (new ObjectCommand (MSG_START, info, "s", id));
+}
+
+void ObjectsBuffer::objMsgEnd (CommonLineInfo *info, const char *id)
+{
+ process (new ObjectCommand (MSG_END, info, "s", id));
+}
+
+void ObjectsBuffer::objEnter (CommonLineInfo *info, const char *id,
+ const char *aspect, int prio, const char *funname,
+ const char *args)
+{
+ process (new ObjectCommand (ENTER, info, "ssdss", id, aspect, prio, funname,
+ args));
+}
+
+void ObjectsBuffer::objLeave (CommonLineInfo *info, const char *id,
+ const char *vals)
+{
+ process (new ObjectCommand (LEAVE, info, "ss", id, vals));
+}
+
+void ObjectsBuffer::objCreate (CommonLineInfo *info, const char *id,
+ const char *klass)
+{
+ process (new ObjectCommand (CREATE, info, "ss", id, klass));
+}
+
+void ObjectsBuffer::objIdent (CommonLineInfo *info, const char *id1,
+ const char *id2)
+{
+ process (new ObjectCommand (IDENT, info, "ss", id1, id2));
+}
+
+void ObjectsBuffer::objNoIdent (CommonLineInfo *info)
+{
+ process (new ObjectCommand (NOIDENT, info, ""));
+}
+
+void ObjectsBuffer::objAssoc (CommonLineInfo *info, const char *parent,
+ const char *child)
+{
+ process (new ObjectCommand (ASSOC, info, "ss", parent, child));
+}
+
+void ObjectsBuffer::objSet (CommonLineInfo *info, const char *id,
+ const char *var, const char *val)
+{
+ process (new ObjectCommand (SET, info, "sss", id, var, val));
+}
+
+void ObjectsBuffer::objClassColor (CommonLineInfo *info, const char *klass,
+ const char *color)
+{
+ process (new ObjectCommand (CLASS_COLOR, info, "ss", klass, color));
+}
+
+void ObjectsBuffer::objObjectColor (CommonLineInfo *info, const char *id,
+ const char *color)
+{
+ process (new ObjectCommand (OBJECT_COLOR, info, "ss", id, color));
+}
+
+void ObjectsBuffer::objDelete (CommonLineInfo *info, const char *id)
+{
+ process (new ObjectCommand (DELETE, info, "s", id));
+}
+
+void ObjectsBuffer::queue ()
+{
+ queued = true;
+}
+
+void ObjectsBuffer::pass ()
+{
+ for (int i = 0; i < commandsQueue->size (); i++)
+ pass (commandsQueue->get (i));
+
+ commandsQueue->clear ();
+ queued = false;
+}
+
+void ObjectsBuffer::process (ObjectCommand *command)
+{
+ if (queued)
+ queue (command);
+ else {
+ pass (command);
+ delete command;
+ }
+}
+
+void ObjectsBuffer::queue (ObjectCommand *command)
+{
+ commandsQueue->put (command);
+}
+
+void ObjectsBuffer::pass (ObjectCommand *command)
+{
+ CommonLineInfo info = { command->info.fileName, command->info.lineNo,
+ command->info.processId,
+ command->info.completeLine };
+ ObjectCommand::Arg *a = command->args;
+
+ switch (command->type) {
+ case MSG:
+ successor->objMsg (&info, a[0].s, a[1].s, a[2].d, a[3].s);
+ break;
+
+ case MARK:
+ successor->objMark (&info, a[0].s, a[1].s, a[2].d, a[3].s);
+ break;
+
+ case MSG_START:
+ successor->objMsgStart (&info, a[0].s);
+ break;
+
+ case MSG_END:
+ successor->objMsgEnd (&info, a[0].s);
+ break;
+
+ case ENTER:
+ successor->objEnter (&info, a[0].s, a[1].s, a[2].d, a[3].s, a[4].s);
+ break;
+
+ case LEAVE:
+ successor->objLeave (&info, a[0].s, a[1].s);
+ break;
+
+ case CREATE:
+ successor->objCreate (&info, a[0].s, a[1].s);
+ break;
+
+ case IDENT:
+ successor->objIdent (&info, a[0].s, a[1].s);
+ break;
+
+ case NOIDENT:
+ successor->objNoIdent (&info);
+ break;
+
+ case ASSOC:
+ successor->objAssoc (&info, a[0].s, a[1].s);
+ break;
+
+ case SET:
+ successor->objSet (&info, a[0].s, a[1].s, a[2].s);
+ break;
+
+ case CLASS_COLOR:
+ successor->objClassColor (&info, a[0].s, a[1].s);
+ break;
+
+ case OBJECT_COLOR:
+ successor->objObjectColor (&info, a[0].s, a[1].s);
+ break;
+
+ case DELETE:
+ successor->objDelete (&info, a[0].s);
+ break;
+ }
+}
+
+} // namespace objects
+
+} // namespace rtfl
diff --git a/objects/objects_buffer.hh b/objects/objects_buffer.hh
new file mode 100644
index 0000000..f00ef89
--- /dev/null
+++ b/objects/objects_buffer.hh
@@ -0,0 +1,88 @@
+#ifndef __OBJECTS_OBJECTS_BUFFER_HH__
+#define __OBJECTS_OBJECTS_BUFFER_HH__
+
+#include "objects_parser.hh"
+#include "common/tools.hh"
+
+namespace rtfl {
+
+namespace objects {
+
+class ObjectsBuffer: public ObjectsControllerBase
+{
+private:
+ enum CommandType {
+ MSG, MARK, MSG_START, MSG_END, ENTER, LEAVE, CREATE, IDENT, NOIDENT,
+ ASSOC, SET, CLASS_COLOR, OBJECT_COLOR, DELETE
+ };
+
+ class ObjectCommand: public lout::object::Object
+ {
+ friend class ObjectsBuffer;
+
+ private:
+ CommandType type;
+ tools::CommonLineInfo info;
+
+ int numArgs;
+ struct Arg {
+ char type;
+ union {
+ int d;
+ char *s;
+ };
+ } *args;
+
+ public:
+ ObjectCommand (CommandType type, tools::CommonLineInfo *info,
+ const char *fmt, ...);
+ ~ObjectCommand ();
+ };
+
+ ObjectsController *successor;
+ lout::container::typed::Vector<ObjectCommand> *commandsQueue;
+ bool queued;
+
+ void process (ObjectCommand *command);
+ void queue (ObjectCommand *command);
+ void pass (ObjectCommand *command);
+
+public:
+ ObjectsBuffer (ObjectsController *successor);
+ ~ObjectsBuffer ();
+
+ void objMsg (tools::CommonLineInfo *info, const char *id,
+ const char *aspect, int prio, const char *message);
+ void objMark (tools::CommonLineInfo *info, const char *id,
+ const char *aspect, int prio, const char *message);
+ void objMsgStart (tools::CommonLineInfo *info, const char *id);
+ void objMsgEnd (tools::CommonLineInfo *info, const char *id);
+ void objEnter (tools::CommonLineInfo *info, const char *id,
+ const char *aspect, int prio, const char *funname,
+ const char *args);
+ void objLeave (tools::CommonLineInfo *info, const char *id,
+ const char *vals);
+ void objCreate (tools::CommonLineInfo *info, const char *id,
+ const char *klass);
+ void objIdent (tools::CommonLineInfo *info, const char *id1,
+ const char *id2);
+ void objNoIdent (tools::CommonLineInfo *info);
+ void objAssoc (tools::CommonLineInfo *info, const char *parent,
+ const char *child);
+ void objSet (tools::CommonLineInfo *info, const char *id, const char *var,
+ const char *val);
+ void objClassColor (tools::CommonLineInfo *info, const char *klass,
+ const char *color);
+ void objObjectColor (tools::CommonLineInfo *info, const char *id,
+ const char *color);
+ void objDelete (tools::CommonLineInfo *info, const char *id);
+
+ void queue ();
+ void pass ();
+};
+
+} // namespace objects
+
+} // namespace rtfl
+
+#endif // __OBJECTS_OBJECTS_BUFFER_HH__
diff --git a/objects/objects_parser.cc b/objects/objects_parser.cc
new file mode 100644
index 0000000..9278b56
--- /dev/null
+++ b/objects/objects_parser.cc
@@ -0,0 +1,401 @@
+/*
+ * RTFL
+ *
+ * Copyright 2013-2015 Sebastian Geerken <sgeerken@dillo.org>
+ *
+ * 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; with the following exception:
+ *
+ * The copyright holders of RTFL give you permission to link this file
+ * statically or dynamically against all versions of the graphviz
+ * library, which are published by AT&T Corp. under one of the following
+ * licenses:
+ *
+ * - Common Public License version 1.0 as published by International
+ * Business Machines Corporation (IBM), or
+ * - Eclipse Public License version 1.0 as published by the Eclipse
+ * Foundation.
+ *
+ * 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/>.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include "objects_parser.hh"
+
+#if 0
+# define PRINT(fmt) printf ("---- [%p] " fmt "\n", this)
+# define PRINTF(fmt, ...) printf ("---- [%p] " fmt "\n", this, __VA_ARGS__)
+#else
+# define PRINT(fmt)
+# define PRINTF(fmt, ...)
+#endif
+
+using namespace rtfl::tools;
+
+namespace rtfl {
+
+namespace objects {
+
+namespace timeout {
+
+inline int getActualType (int type)
+{
+ return type >> 8;
+}
+
+inline int getCount (int type)
+{
+ return type & 0xff;
+}
+
+inline int makeType (int actualType, int count)
+{
+ return count | (actualType << 8);
+}
+
+inline int incType (int type)
+{
+ return makeType (getActualType (type), getCount (type) + 1);
+}
+
+inline int decType (int type)
+{
+ return makeType (getActualType (type), getCount (type) - 1);
+}
+
+} // namespace timeout
+
+ObjectsControllerBase::ObjectsControllerBase()
+{
+ predessor = NULL;
+ successor = NULL;
+}
+
+void ObjectsControllerBase::addTimeout (double secs, int type)
+{
+ PRINTF ("ObjectsControllerBase::addTimeout (%g, %d)", secs, type);
+
+ if (predessor)
+ predessor->addTimeout (secs, timeout::incType (type));
+ else
+ fprintf (stderr, "addTimeout (%g, %d): no predessor\n", secs, type);
+}
+
+void ObjectsControllerBase::removeTimeout (int type)
+{
+ if (predessor)
+ predessor->removeTimeout (timeout::incType (type));
+ else
+ fprintf (stderr, "removeTimeout (%d): no predessor\n", type);
+}
+
+void ObjectsControllerBase::setObjectsSource (ObjectsSource *source)
+{
+ predessor = source;
+}
+
+void ObjectsControllerBase::timeout (int type)
+{
+ PRINTF ("ObjectsControllerBase::timeout (%d)", type);
+
+ // We start sending count == 1 to the predessor, so we get back count == 1
+ // from it at the end.
+ if (timeout::getCount (type) == 1)
+ ownTimeout (timeout::getActualType (type));
+ else {
+ if (successor)
+ successor->timeout (timeout::decType (type));
+ else
+ fprintf (stderr, "timeout (%d): no successor\n", type);
+ }
+}
+
+void ObjectsControllerBase::finish ()
+{
+ ownFinish ();
+
+ if (successor)
+ successor->finish ();
+}
+
+void ObjectsControllerBase::setObjectsSink (ObjectsSink *sink)
+{
+ successor = sink;
+}
+
+void ObjectsControllerBase::addOwnTimeout (double secs, int type)
+{
+ PRINTF ("ObjectsControllerBase::addOwnTimeout (%g, %d)", secs, type);
+ addTimeout (secs, timeout::makeType (0, type));
+}
+
+void ObjectsControllerBase::removeOwnTimeout (int type)
+{
+ removeTimeout (timeout::makeType (0, type));
+}
+
+void ObjectsControllerBase::ownTimeout (int type)
+{
+ // No implementation.
+}
+
+void ObjectsControllerBase::ownFinish ()
+{
+ // No implementation.
+}
+
+// ----------------------------------------------------------------------
+
+ObjectsParser::ObjectsParser (ObjectsController *controller)
+{
+ this->controller = controller;
+ source = NULL;
+ controller->setObjectsSource (this);
+}
+
+ObjectsParser::~ObjectsParser ()
+{
+ controller->setObjectsSource (NULL);
+}
+
+void ObjectsParser::processCommand (CommonLineInfo *info, char *cmd, char *args)
+{
+ char **parts = NULL;
+
+ if (args == NULL)
+ // All commands need arguments here.
+ fprintf (stderr, "Missing arguments:%s\n", info->completeLine);
+ else if (strcmp (cmd, "obj-msg") == 0) {
+ parts = split (args, 4);
+ if (parts[1] && parts[2] && parts[3])
+ controller->objMsg (info, parts[0], parts[1], atoi(parts[2]),
+ parts[3]);
+ else
+ fprintf (stderr, "Incomplete line (obj-msg):\n%s\n",
+ info->completeLine);
+ } else if (strcmp (cmd, "obj-mark") == 0) {
+ parts = split (args, 4);
+ if (parts[1] && parts[2] && parts[3])
+ controller->objMark (info, parts[0], parts[1], atoi(parts[2]),
+ parts[3]);
+ else
+ fprintf (stderr, "Incomplete line (obj-mark):\n%s\n",
+ info->completeLine);
+ } else if (strcmp (cmd, "obj-msg-start") == 0)
+ controller->objMsgStart (info, args);
+ else if (strcmp (cmd, "obj-msg-end") == 0)
+ controller->objMsgEnd (info, args);
+ else if (strcmp (cmd, "obj-enter") == 0) {
+ parts = split (args, 5);
+ if (parts[1] && parts[2] && parts[3] && parts[4])
+ controller->objEnter (info, parts[0], parts[1], atoi(parts[2]),
+ parts[3], parts[4]);
+ else
+ fprintf (stderr, "Incomplete line (obj-enter):\n%s\n",
+ info->completeLine);
+ } else if (strcmp (cmd, "obj-leave") == 0)
+ // Pre-version "obj-leave" does not support values.
+ controller->objLeave (info, args, NULL);
+ else if (strcmp (cmd, "obj-create") == 0) {
+ parts = split (args, 2);
+ if (parts[1])
+ controller->objCreate (info, parts[0], parts[1]);
+ else
+ fprintf (stderr, "Incomplete line (obj-create):\n%s\n",
+ info->completeLine);
+ } else if (strcmp (cmd, "obj-ident") == 0) {
+ parts = split (args, 2);
+ if (parts[1])
+ controller->objIdent (info, parts[0], parts[1]);
+ else
+ fprintf (stderr, "Incomplete line (obj-ident):\n%s\n",
+ info->completeLine);
+ } else if (strcmp (cmd, "obj-assoc") == 0) {
+ parts = split (args, 2);
+ if (parts[1])
+ controller->objAssoc (info, parts[0], parts[1]);
+ else
+ fprintf (stderr, "Incomplete line (obj-assoc):\n%s\n",
+ info->completeLine);
+ } else if (strcmp (cmd, "obj-set") == 0) {
+ parts = split (args, 3);
+ if (parts[1] && parts[2])
+ controller->objSet (info, parts[0], parts[1], parts[2]);
+ else
+ fprintf (stderr, "Incomplete line (obj-set):\n%s\n",
+ info->completeLine);
+ } else if (strcmp (cmd, "obj-color") == 0) {
+ parts = split (args, 2);
+ if (parts[1]) {
+ fprintf (stderr, "Warning: obj-color is deprecated; use "
+ "obj-class-color instead:\n%s\n", info->completeLine);
+ controller->objClassColor (info, parts[1], parts[0]);
+ } else
+ fprintf (stderr, "Incomplete line (obj-color):\n%s\n",
+ info->completeLine);
+ } else if (strcmp (cmd, "obj-class-color") == 0) {
+ parts = split (args, 2);
+ if (parts[1])
+ controller->objClassColor (info, parts[1], parts[0]);
+ else
+ fprintf (stderr, "Incomplete line (obj-class-color):\n%s\n",
+ info->completeLine);
+ } else if (strcmp (cmd, "obj-object-color") == 0) {
+ parts = split (args, 2);
+ if (parts[1])
+ controller->objObjectColor (info, parts[0], parts[1]);
+ else
+ fprintf (stderr, "Incomplete line (obj-object-color):\n%s\n",
+ info->completeLine);
+ } else if (strcmp (cmd, "obj-delete") == 0)
+ controller->objDelete (info, args);
+ else
+ fprintf (stderr, "Unknown command identifier '%s':\n%s\n", cmd,
+ info->completeLine);
+
+ if (parts)
+ freeSplit (parts);
+}
+
+void ObjectsParser::processVCommand (CommonLineInfo *info, const char *module,
+ int majorVersion, int minorVersion,
+ const char *cmd, char **args)
+{
+ if (strcmp (module, "obj") == 0) {
+ if (majorVersion > 1)
+ fprintf (stderr, "Last supported version is 1.0:\n%s\n",
+ info->completeLine);
+ if (args[0] == NULL) {
+ if (strcmp (cmd, "noident") == 0)
+ controller->objNoIdent (info);
+ else
+ // All other commands need arguments.
+ fprintf (stderr, "Missing arguments:%s\n", info->completeLine);
+ } else if (strcmp (cmd, "msg") == 0) {
+ if (args[1] && args[2] && args[3])
+ controller->objMsg (info, args[0], args[1], atoi(args[2]), args[3]);
+ else
+ fprintf (stderr, "Incomplete line (msg):\n%s\n",
+ info->completeLine);
+ } else if (strcmp (cmd, "mark") == 0) {
+ if (args[1] && args[2] && args[3])
+ controller->objMark (info, args[0], args[1], atoi(args[2]),
+ args[3]);
+ else
+ fprintf (stderr, "Incomplete line (mark):\n%s\n",
+ info->completeLine);
+ } else if (strcmp (cmd, "msg-start") == 0)
+ controller->objMsgStart (info, args[0]);
+ else if (strcmp (cmd, "msg-end") == 0)
+ controller->objMsgEnd (info, args[0]);
+ else if (strcmp (cmd, "enter") == 0) {
+ if (args[1] && args[2] && args[3] && args[4])
+ controller->objEnter (info, args[0], args[1], atoi(args[2]),
+ args[3], args[4]);
+ else
+ fprintf (stderr, "Incomplete line (enter):\n%s\n",
+ info->completeLine);
+ } else if (strcmp (cmd, "leave") == 0)
+ // Args[1] may be NULL.
+ controller->objLeave (info, args[0], args[1]);
+ else if (strcmp (cmd, "create") == 0) {
+ if (args[1])
+ controller->objCreate (info, args[0], args[1]);
+ else
+ fprintf (stderr, "Incomplete line (create):\n%s\n",
+ info->completeLine);
+ } else if (strcmp (cmd, "ident") == 0) {
+ if (args[1])
+ controller->objIdent (info, args[0], args[1]);
+ else
+ fprintf (stderr, "Incomplete line (ident):\n%s\n",
+ info->completeLine);
+ } else if (strcmp (cmd, "assoc") == 0) {
+ if (args[1])
+ controller->objAssoc (info, args[0], args[1]);
+ else
+ fprintf (stderr, "Incomplete line (assoc):\n%s\n",
+ info->completeLine);
+ } else if (strcmp (cmd, "set") == 0) {
+ if (args[1] && args[2])
+ controller->objSet (info, args[0], args[1], args[2]);
+ else
+ fprintf (stderr, "Incomplete line (set):\n%s\n",
+ info->completeLine);
+ } else if (strcmp (cmd, "class-color") == 0) {
+ if (args[1])
+ // Notice the changed order.
+ controller->objClassColor (info, args[0], args[1]);
+ else
+ fprintf (stderr, "Incomplete line (class-color):\n%s\n",
+ info->completeLine);
+ } else if (strcmp (cmd, "object-color") == 0) {
+ if (args[1])
+ controller->objObjectColor (info, args[0], args[1]);
+ else
+ fprintf (stderr, "Incomplete line (object-color):\n%s\n",
+ info->completeLine);
+ } else if (strcmp (cmd, "delete") == 0)
+ controller->objDelete (info, args[0]);
+ else
+ fprintf (stderr, "Unknown command identifier '%s':\n%s\n", cmd,
+ info->completeLine);
+ }
+}
+
+void ObjectsParser::setLinesSource (LinesSource *source)
+{
+ this->source = source;
+}
+
+void ObjectsParser::timeout (int type)
+{
+ PRINTF ("ObjectsParser::timeout (%d)", type);
+
+ if (timeout::getCount (type) == 0)
+ ; // ownTimeout (timeout::getActualType (type));
+ else
+ controller->timeout (timeout::decType (type));
+}
+
+void ObjectsParser::finish ()
+{
+ controller->finish ();
+}
+
+void ObjectsParser::setObjectsSink (ObjectsSink *sink)
+{
+ // This would be the controller passed in the constructor.
+}
+
+void ObjectsParser::addTimeout (double secs, int type)
+{
+ PRINTF ("ObjectsParser::addTimeout (%g, %d)", secs, type);
+
+ if (source)
+ source->addTimeout (secs, timeout::incType (type));
+ else
+ fprintf (stderr, "addTimeout (%g, %d): no source\n", secs, type);
+}
+
+void ObjectsParser::removeTimeout (int type)
+{
+ if (source)
+ source->removeTimeout (timeout::incType (type));
+ else
+ fprintf (stderr, "removeTimeout (%d): no source\n", type);
+}
+
+} // namespace objects
+
+} // namespace rtfl
diff --git a/objects/objects_parser.hh b/objects/objects_parser.hh
new file mode 100644
index 0000000..e4dd2b0
--- /dev/null
+++ b/objects/objects_parser.hh
@@ -0,0 +1,115 @@
+#ifndef __OBJECTS_OBJECTS_PARSER_HH__
+#define __OBJECTS_OBJECTS_PARSER_HH__
+
+#include "common/parser.hh"
+#include "lout/object.hh"
+
+namespace rtfl {
+
+namespace objects {
+
+class ObjectsSink;
+
+class ObjectsSource
+{
+public:
+ virtual void setObjectsSink (ObjectsSink *sink) = 0;
+ virtual void addTimeout (double secs, int type) = 0;
+ virtual void removeTimeout (int type) = 0;
+};
+
+
+class ObjectsSink
+{
+public:
+ virtual void setObjectsSource (ObjectsSource *source) = 0;
+ virtual void timeout (int type) = 0;
+ virtual void finish () = 0;
+};
+
+
+class ObjectsController: public lout::object::Object, public ObjectsSource,
+ public ObjectsSink
+{
+public:
+ virtual void objMsg (tools::CommonLineInfo *info, const char *id,
+ const char *aspect, int prio, const char *message) = 0;
+ virtual void objMark (tools::CommonLineInfo *info, const char *id,
+ const char *aspect, int prio, const char *message) = 0;
+ virtual void objMsgStart (tools::CommonLineInfo *info, const char *id) = 0;
+ virtual void objMsgEnd (tools::CommonLineInfo *info, const char *id) = 0;
+ virtual void objEnter (tools::CommonLineInfo *info, const char *id,
+ const char *aspect, int prio, const char *funname,
+ const char *args) = 0;
+ virtual void objLeave (tools::CommonLineInfo *info, const char *id,
+ const char *vals) = 0;
+ virtual void objCreate (tools::CommonLineInfo *info, const char *id,
+ const char *klass) = 0;
+ virtual void objIdent (tools::CommonLineInfo *info, const char *id1,
+ const char *id2) = 0;
+ virtual void objNoIdent (tools::CommonLineInfo *info) = 0;
+ virtual void objAssoc (tools::CommonLineInfo *info, const char *parent,
+ const char *child) = 0;
+ virtual void objSet (tools::CommonLineInfo *info, const char *id,
+ const char *var, const char *val) = 0;
+ virtual void objClassColor (tools::CommonLineInfo *info, const char *klass,
+ const char *color) = 0;
+ virtual void objObjectColor (tools::CommonLineInfo *info, const char *id,
+ const char *color) = 0;
+ virtual void objDelete (tools::CommonLineInfo *info, const char *id) = 0;
+};
+
+
+class ObjectsControllerBase: public ObjectsController
+{
+ ObjectsSource *predessor;
+ ObjectsSink *successor;
+
+protected:
+ virtual void ownTimeout (int type);
+ virtual void ownFinish ();
+ void addOwnTimeout (double secs, int type);
+ void removeOwnTimeout (int type);
+
+public:
+ ObjectsControllerBase();
+
+ void setObjectsSink (ObjectsSink *sink);
+ void addTimeout (double secs, int type);
+ void removeTimeout (int type);
+ void setObjectsSource (ObjectsSource *source);
+ void timeout (int type);
+ void finish ();
+};
+
+
+class ObjectsParser: public tools::Parser, public ObjectsSource
+{
+private:
+ ObjectsController *controller;
+ tools::LinesSource *source;
+
+protected:
+ void processCommand (tools::CommonLineInfo *info, char *cmd, char *args);
+ void processVCommand (tools::CommonLineInfo *info, const char *module,
+ int majorVersion, int minorVersion, const char *cmd,
+ char **args);
+
+public:
+ ObjectsParser (ObjectsController *controller);
+ ~ObjectsParser ();
+
+ void setLinesSource (tools::LinesSource *source);
+ void timeout (int type);
+ void finish ();
+
+ void setObjectsSink (ObjectsSink *sink);
+ void addTimeout (double secs, int type);
+ void removeTimeout (int type);
+};
+
+} // namespace objects
+
+} // namespace rtfl
+
+#endif // __OBJECTS_OBJVIEW_PARSER_HH__
diff --git a/objects/objects_writer.cc b/objects/objects_writer.cc
new file mode 100644
index 0000000..b9c2581
--- /dev/null
+++ b/objects/objects_writer.cc
@@ -0,0 +1,145 @@
+/*
+ * RTFL
+ *
+ * Copyright 2015 Sebastian Geerken <sgeerken@dillo.org>
+ *
+ * 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; with the following exception:
+ *
+ * The copyright holders of RTFL give you permission to link this file
+ * statically or dynamically against all versions of the graphviz
+ * library, which are published by AT&T Corp. under one of the following
+ * licenses:
+ *
+ * - Common Public License version 1.0 as published by International
+ * Business Machines Corporation (IBM), or
+ * - Eclipse Public License version 1.0 as published by the Eclipse
+ * Foundation.
+ *
+ * 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/>.
+ */
+
+#include "objects_writer.hh"
+
+#define DBG_RTFL
+
+#include "debug_rtfl.hh"
+
+using namespace rtfl::tools;
+
+// If foreign messages ("F" stands for "foreign") are passed, the original
+// filename, line number and process id must be printed.
+
+#define F_RTFL_PRINT(module, version, cmd, fmt, ...) \
+ rtfl_print (module, version, info->fileName, info->lineNo, info->processId, \
+ "s:" fmt, cmd, __VA_ARGS__)
+
+#define F_RTFL_PRINT0(module, version, cmd) \
+ rtfl_print (module, version, info->fileName, info->lineNo, info->processId, \
+ "s", cmd)
+
+#define F_RTFL_OBJ_PRINT(cmd, fmt, ...) \
+ F_RTFL_PRINT ("obj", RTFL_OBJ_VERSION, cmd, fmt, __VA_ARGS__)
+
+#define F_RTFL_OBJ_PRINT0(cmd) \
+ F_RTFL_PRINT0 ("obj", RTFL_OBJ_VERSION, cmd)
+
+namespace rtfl {
+
+namespace objects {
+
+void ObjectsWriter::objMsg (CommonLineInfo *info, const char *id,
+ const char *aspect, int prio, const char *message)
+{
+ F_RTFL_OBJ_PRINT ("msg", "s:s:d:s", id, aspect, prio, message);
+}
+
+void ObjectsWriter::objMark (CommonLineInfo *info, const char *id,
+ const char *aspect, int prio, const char *message)
+{
+ F_RTFL_OBJ_PRINT ("mark", "s:s:d:s", id, aspect, prio, message);
+}
+
+void ObjectsWriter::objMsgStart (CommonLineInfo *info, const char *id)
+{
+ F_RTFL_OBJ_PRINT ("msg-start", "s", id);
+}
+
+void ObjectsWriter::objMsgEnd (CommonLineInfo *info, const char *id)
+{
+ F_RTFL_OBJ_PRINT ("msg-end", "s", id);
+}
+
+void ObjectsWriter::objEnter (CommonLineInfo *info, const char *id,
+ const char *aspect, int prio, const char *funname,
+ const char *args)
+{
+ F_RTFL_OBJ_PRINT ("enter", "s:s:d:s:s", id, aspect, prio, funname, args);
+}
+
+void ObjectsWriter::objLeave (CommonLineInfo *info, const char *id,
+ const char *vals)
+{
+ if (vals)
+ F_RTFL_OBJ_PRINT ("leave", "s:s", id, vals);
+ else
+ F_RTFL_OBJ_PRINT ("leave", "s", id);
+}
+
+void ObjectsWriter::objCreate (CommonLineInfo *info, const char *id,
+ const char *klass)
+{
+ F_RTFL_OBJ_PRINT ("create", "s:s", id, klass);
+}
+
+void ObjectsWriter::objIdent (CommonLineInfo *info, const char *id1,
+ const char *id2)
+{
+ F_RTFL_OBJ_PRINT ("create", "s:s", id1, id2);
+}
+
+void ObjectsWriter::objNoIdent (CommonLineInfo *info)
+{
+ F_RTFL_OBJ_PRINT0 ("noident");
+}
+
+void ObjectsWriter::objAssoc (CommonLineInfo *info, const char *parent,
+ const char *child)
+{
+ F_RTFL_OBJ_PRINT ("assoc", "s:s", parent, child);
+}
+
+void ObjectsWriter::objSet (CommonLineInfo *info, const char *id,
+ const char *var, const char *val)
+{
+ F_RTFL_OBJ_PRINT ("set", "s:s:s", id, var, val);
+}
+
+void ObjectsWriter::objClassColor (CommonLineInfo *info, const char *klass,
+ const char *color)
+{
+ F_RTFL_OBJ_PRINT ("class-color", "s:s", klass, color);
+}
+
+void ObjectsWriter::objObjectColor (CommonLineInfo *info, const char *id,
+ const char *color)
+{
+ F_RTFL_OBJ_PRINT ("object-color", "s:s", id, color);
+}
+
+void ObjectsWriter::objDelete (CommonLineInfo *info, const char *id)
+{
+ F_RTFL_OBJ_PRINT ("delete", "s", id);
+}
+
+} // namespace objects
+
+} // namespace rtfl
diff --git a/objects/objects_writer.hh b/objects/objects_writer.hh
new file mode 100644
index 0000000..80e629e
--- /dev/null
+++ b/objects/objects_writer.hh
@@ -0,0 +1,44 @@
+#ifndef __OBJECTS_OBJECTS_WRITER_HH__
+#define __OBJECTS_OBJECTS_WRITER_HH__
+
+#include "objects_parser.hh"
+
+namespace rtfl {
+
+namespace objects {
+
+class ObjectsWriter: public ObjectsControllerBase
+{
+public:
+ void objMsg (tools::CommonLineInfo *info, const char *id,
+ const char *aspect, int prio, const char *message);
+ void objMark (tools::CommonLineInfo *info, const char *id,
+ const char *aspect, int prio, const char *message);
+ void objMsgStart (tools::CommonLineInfo *info, const char *id);
+ void objMsgEnd (tools::CommonLineInfo *info, const char *id);
+ void objEnter (tools::CommonLineInfo *info, const char *id,
+ const char *aspect, int prio, const char *funname,
+ const char *args);
+ void objLeave (tools::CommonLineInfo *info, const char *id,
+ const char *vals);
+ void objCreate (tools::CommonLineInfo *info, const char *id,
+ const char *klass);
+ void objIdent (tools::CommonLineInfo *info, const char *id1,
+ const char *id2);
+ void objNoIdent (tools::CommonLineInfo *info);
+ void objAssoc (tools::CommonLineInfo *info, const char *parent,
+ const char *child);
+ void objSet (tools::CommonLineInfo *info, const char *id, const char *var,
+ const char *val);
+ void objClassColor (tools::CommonLineInfo *info, const char *klass,
+ const char *color);
+ void objObjectColor (tools::CommonLineInfo *info, const char *id,
+ const char *color);
+ void objDelete (tools::CommonLineInfo *info, const char *id);
+};
+
+} // namespace objects
+
+} // namespace rtfl
+
+#endif // __OBJECTS_OBJVIEW_WRITER_HH__
diff --git a/objects/objident_controller.cc b/objects/objident_controller.cc
new file mode 100644
index 0000000..deaf2fd
--- /dev/null
+++ b/objects/objident_controller.cc
@@ -0,0 +1,339 @@
+/*
+ * RTFL
+ *
+ * Copyright 2015 Sebastian Geerken <sgeerken@dillo.org>
+ *
+ * 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; with the following exception:
+ *
+ * The copyright holders of RTFL give you permission to link this file
+ * statically or dynamically against all versions of the graphviz
+ * library, which are published by AT&T Corp. under one of the following
+ * licenses:
+ *
+ * - Common Public License version 1.0 as published by International
+ * Business Machines Corporation (IBM), or
+ * - Eclipse Public License version 1.0 as published by the Eclipse
+ * Foundation.
+ *
+ * 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/>.
+ */
+
+#include <stdio.h>
+#include "objident_controller.hh"
+
+using namespace lout::object;
+using namespace lout::misc;
+using namespace lout::container::untyped;
+using namespace rtfl::tools;
+
+#define TIMEOUT_SECS 1
+
+namespace rtfl {
+
+namespace objects {
+
+ObjIdentController::PostController::PostController (ObjectsController
+ *successor)
+{
+ this->successor = successor;
+ successor->setObjectsSource (this);
+ setObjectsSink (successor);
+
+ // The "canonocal" identity is stored both as key and as value. For
+ // this reason, the second argument could be "false". Check whether
+ // this is possible (order of delete etc.).
+ identities = new EquivalenceRelation (true, true);
+}
+
+ObjIdentController::PostController::~PostController ()
+{
+ delete identities;
+}
+
+void ObjIdentController::PostController::objMsg (CommonLineInfo *info,
+ const char *id,
+ const char *aspect, int prio,
+ const char *message)
+{
+ successor->objMsg (info, mapId (id), aspect, prio, message);
+}
+
+void ObjIdentController::PostController::objMark (CommonLineInfo *info,
+ const char *id,
+ const char *aspect, int prio,
+ const char *message)
+{
+ successor->objMark (info, mapId (id), aspect, prio, message);
+}
+
+void ObjIdentController::PostController::objMsgStart (CommonLineInfo *info,
+ const char *id)
+{
+ successor->objMsgStart (info, mapId (id));
+}
+
+void ObjIdentController::PostController::objMsgEnd (CommonLineInfo *info,
+ const char *id)
+{
+ successor->objMsgEnd (info, mapId (id));
+}
+
+void ObjIdentController::PostController::objEnter (CommonLineInfo *info,
+ const char *id,
+ const char *aspect, int prio,
+ const char *funname,
+ const char *args)
+{
+ successor->objEnter (info, mapId (id), aspect, prio, funname, args);
+}
+
+void ObjIdentController::PostController::objLeave (CommonLineInfo *info,
+ const char *id,
+ const char *vals)
+{
+ successor->objLeave (info, mapId (id), vals);
+}
+
+void ObjIdentController::PostController::objCreate (CommonLineInfo *info,
+ const char *id,
+ const char *klass)
+{
+ successor->objCreate (info, mapId (id), klass);
+}
+
+void ObjIdentController::PostController::objIdent (CommonLineInfo *info,
+ const char *id1,
+ const char *id2)
+{
+ // "obj-ident" is not delegated.
+}
+
+void ObjIdentController::PostController::objNoIdent (CommonLineInfo *info)
+{
+ // "obj-noident" is not delegated.
+}
+
+void ObjIdentController::PostController::objAssoc (CommonLineInfo *info,
+ const char *parent,
+ const char *child)
+{
+ successor->objAssoc (info, mapId (parent), mapId (child));
+}
+
+void ObjIdentController::PostController::objSet (CommonLineInfo *info,
+ const char *id,
+ const char *var,
+ const char *val)
+{
+ successor->objSet (info, mapId (id), var, val);
+}
+
+void ObjIdentController::PostController::objClassColor (CommonLineInfo *info,
+ const char *klass,
+ const char *color)
+{
+ successor->objClassColor (info, klass, color);
+}
+
+void ObjIdentController::PostController::objObjectColor (CommonLineInfo *info,
+ const char *id,
+ const char *color)
+{
+ successor->objObjectColor (info, mapId (id), color);
+}
+
+void ObjIdentController::PostController::objDelete (CommonLineInfo *info,
+ const char *id)
+{
+ successor->objDelete (info, mapId (id));
+
+ // TODO Remove from identities.
+}
+
+void ObjIdentController::PostController::addIdentity (const char *id1,
+ const char *id2)
+{
+ String key1 (id1), key2 (id2);
+
+ if (!identities->contains (&key1))
+ identities->put (new String (id1), new String (id1));
+
+ if (!identities->contains (&key2))
+ identities->put (new String (id2), new String (id2));
+
+ identities->relate (&key1, &key2);
+}
+
+const char *ObjIdentController::PostController::mapId (const char *id)
+{
+ String key (id);
+ if (!identities->contains (&key))
+ identities->put (new String (id), new String (id));
+
+ return ((String*)identities->get(&key))->chars ();
+}
+
+// ----------------------------------------------------------------------
+
+ObjIdentController::ObjIdentController (ObjectsController *successor)
+{
+ noIdent = false;
+ stackDepth = 0;
+ createPending = false;
+
+ postController = new PostController (successor);
+ buffer = new ObjectsBuffer (postController);
+ buffer->setObjectsSource (this);
+ setObjectsSink (buffer);
+}
+
+ObjIdentController::~ObjIdentController ()
+{
+}
+
+void ObjIdentController::objMsg (CommonLineInfo *info, const char *id,
+ const char *aspect, int prio,
+ const char *message)
+{
+ buffer->objMsg (info, id, aspect, prio, message);
+}
+
+void ObjIdentController::objMark (CommonLineInfo *info, const char *id,
+ const char *aspect, int prio,
+ const char *message)
+{
+ buffer->objMark (info, id, aspect, prio, message);
+}
+
+void ObjIdentController::objMsgStart (CommonLineInfo *info, const char *id)
+{
+ buffer->objMsgStart (info, id);
+}
+
+void ObjIdentController::objMsgEnd (CommonLineInfo *info, const char *id)
+{
+ buffer->objMsgEnd (info, id);
+}
+
+void ObjIdentController::objEnter (CommonLineInfo *info, const char *id,
+ const char *aspect, int prio,
+ const char *funname, const char *args)
+{
+ stackDepth++;
+
+ buffer->objEnter (info, id, aspect, prio, funname, args);
+}
+
+void ObjIdentController::objLeave (CommonLineInfo *info, const char *id,
+ const char *vals)
+{
+ stackDepth = max (stackDepth - 1, 0);
+
+ if (createPending && stackDepth < minCreateStackDepth) {
+ pass ();
+ removeOwnTimeout (PASS);
+ }
+
+ buffer->objLeave (info, id, vals);
+}
+
+void ObjIdentController::objCreate (CommonLineInfo *info, const char *id,
+ const char *klass)
+{
+ queue ();
+ buffer->objCreate (info, id, klass);
+}
+
+void ObjIdentController::objIdent (CommonLineInfo *info, const char *id1,
+ const char *id2)
+{
+ postController->addIdentity (id1, id2);
+
+ // TODO: Possibly end queueing? Probably not.
+
+ // "obj-ident" is not delegated.
+}
+
+void ObjIdentController::objNoIdent (CommonLineInfo *info)
+{
+ noIdent = true;
+ pass ();
+
+ // "obj-noident" is not delegated.
+}
+
+void ObjIdentController::objAssoc (CommonLineInfo *info, const char *parent,
+ const char *child)
+{
+ buffer->objAssoc (info, parent, child);
+}
+
+void ObjIdentController::objSet (CommonLineInfo *info, const char *id,
+ const char *var, const char *val)
+{
+ buffer->objSet (info, id, var, val);
+}
+
+void ObjIdentController::objClassColor (CommonLineInfo *info, const char *klass,
+ const char *color)
+{
+ buffer->objClassColor (info, klass, color);
+}
+
+void ObjIdentController::objObjectColor (CommonLineInfo *info, const char *id,
+ const char *color)
+{
+ buffer->objObjectColor (info, id, color);
+}
+
+void ObjIdentController::objDelete (CommonLineInfo *info, const char *id)
+{
+ buffer->objDelete (info, id);
+}
+
+void ObjIdentController::ownTimeout (int type)
+{
+ if (type == PASS)
+ pass ();
+}
+
+void ObjIdentController::ownFinish ()
+{
+ pass ();
+}
+
+void ObjIdentController::queue ()
+{
+ if (!noIdent) {
+ if (createPending)
+ minCreateStackDepth = min (minCreateStackDepth, stackDepth);
+ else {
+ buffer->queue ();
+ createPending = true;
+ minCreateStackDepth = stackDepth;
+ }
+
+ removeOwnTimeout (PASS);
+ addOwnTimeout (TIMEOUT_SECS, PASS);
+ }
+}
+
+void ObjIdentController::pass ()
+{
+ buffer->pass ();
+ createPending = false;
+}
+
+} // namespace objects
+
+} // namespace rtfl
+
diff --git a/objects/objident_controller.hh b/objects/objident_controller.hh
new file mode 100644
index 0000000..2d83b20
--- /dev/null
+++ b/objects/objident_controller.hh
@@ -0,0 +1,192 @@
+#ifndef __OBJECTS_OBJIDENT_CONTROLLER_HH__
+#define __OBJECTS_OBJIDENT_CONTROLLER_HH__
+
+#include "objects_parser.hh"
+#include "objects_buffer.hh"
+#include "common/tools.hh"
+
+namespace rtfl {
+
+namespace objects {
+
+/**
+ * \ident Filter Controller for handling `obj-ident`
+ *
+ * Motivation
+ * ----------
+ * When using multiple inheritance in C++, the values for `this` are not
+ * identical in all contexts. Consider a class `C`, with `A` and `B` as base
+ * classes. The following code
+ *
+ * C *c = new C();
+ * A *a = (A*)c;
+ * B *b = (B*)c;
+ * printf("a = %p\n", a);
+ * printf("b = %p\n", b);
+ * printf("c = %p\n", c);
+ *
+ * will output something like this:
+ *
+ * a = 0x1000
+ * b = 0x1010
+ * c = 0x1000
+ *
+ * (Notice the different value of `b`.) The value of `b` will differ from `a` by
+ * `sizeof(A)`.
+ *
+ * For this reason, the tested program has to declare all values as identical,
+ * in the following way:
+ *
+ * [rtfl-obj-1.0]...:create:0x1000:A
+ * [rtfl-obj-1.0]...:create:0x1010:B
+ * [rtfl-obj-1.0]...:ident:0x1000:0x1000
+ * [rtfl-obj-1.0]...:ident:0x1000:0x1010
+ * [rtfl-obj-1.0]...:create:0x1000:C
+ *
+ * The first `ident` line declares `c` (the newly created instance of `C` as
+ * identical to `a` (`(A*)c`), the second declares it identical to `b`
+ * (`(B*)c`).
+ *
+ * General Approach
+ * ----------------
+ * Handling `obj-ident` is kept out of the specific implementations of
+ * `ObjectsController` and implemented in a filter, `ObjIdentController`, which
+ * will translate all identities to actually identical identities; the output of
+ * `ObjIdentController` would, in the example above, be:
+ *
+ * [rtfl-obj-1.0]...:create:0x1000:A
+ * [rtfl-obj-1.0]...:create:0x1000:B
+ * [rtfl-obj-1.0]...:create:0x1000:C
+ *
+ * Details
+ * -------
+ * The general problem is that some messages have to be changed (especially
+ * `...:create:0x1010:B` has to be changed to `...:create:0x1000:B`) before
+ * `obj-ident` is read. Even worse, it is not certain that `obj-ident` will
+ * follow at all: the second `obj-create` may actually define a _different_
+ * object. For this reason, starting with `obj-create`, all messages are held
+ * back until something happens that makes it certain that _no_ related
+ * `obj-ident` will follow.
+ *
+ * Notice that a functioning implementation is possible even if the second
+ * condition is incompletely defined and implemented.
+ *
+ * (For more complex class hierarchies, it is not sufficient to react on
+ * `obj-ident` itself, since another `obj-ident` may follow, dealing with the
+ * same identities.)
+ *
+ * When is it certain that no related `obj-ident` will follow?
+ *
+ * 1. When a method is left (`obj-leave`), in which the objects have been
+ * created.
+ * 2. At the end of the stream.
+ * 3. (Not an exact condition, but a compromise:) After a timeout of a couple of
+ * seconds; after some time, it can be assumed that the construction of
+ * objects is over.
+ *
+ * (May be extended. See rtfl::objects::ObjIdentController::objLeave,
+ * rtfl::objects::ObjIdentController::ownTimeout, and
+ * rtfl::objects::ObjIdentController::ownFinish.
+ *
+ * Nice to have
+ * ------------
+ * - Make timeouts configurable, also whether a timeout is triggered after a
+ * certain time after "obj-create" or a certain time after no commands (latter
+ * is currently implemented).
+ */
+class ObjIdentController: public ObjectsControllerBase
+{
+private:
+ class PostController: public ObjectsControllerBase
+ {
+ tools::EquivalenceRelation *identities;
+ ObjectsController *successor;
+
+ const char *mapId (const char *id);
+
+ public:
+ PostController (ObjectsController *successor);
+ ~PostController ();
+
+ void objMsg (tools::CommonLineInfo *info, const char *id,
+ const char *aspect, int prio, const char *message);
+ void objMark (tools::CommonLineInfo *info, const char *id,
+ const char *aspect, int prio, const char *message);
+ void objMsgStart (tools::CommonLineInfo *info, const char *id);
+ void objMsgEnd (tools::CommonLineInfo *info, const char *id);
+ void objEnter (tools::CommonLineInfo *info, const char *id,
+ const char *aspect, int prio, const char *funname,
+ const char *args);
+ void objLeave (tools::CommonLineInfo *info, const char *id,
+ const char *vals);
+ void objCreate (tools::CommonLineInfo *info, const char *id,
+ const char *klass);
+ void objIdent (tools::CommonLineInfo *info, const char *id1,
+ const char *id2);
+ void objNoIdent (tools::CommonLineInfo *info);
+ void objAssoc (tools::CommonLineInfo *info, const char *parent,
+ const char *child);
+ void objSet (tools::CommonLineInfo *info, const char *id, const char *var,
+ const char *val);
+ void objClassColor (tools::CommonLineInfo *info, const char *klass,
+ const char *color);
+ void objObjectColor (tools::CommonLineInfo *info, const char *id,
+ const char *color);
+ void objDelete (tools::CommonLineInfo *info, const char *id);
+
+ void addIdentity (const char *id1, const char *id2);
+ };
+
+ enum { PASS = 0 };
+
+ ObjectsBuffer *buffer;
+ PostController *postController;
+ bool noIdent;
+
+ int stackDepth;
+ bool createPending;
+ int minCreateStackDepth;
+
+ void queue ();
+ void pass ();
+
+protected:
+ void ownTimeout (int type);
+ void ownFinish ();
+
+public:
+ ObjIdentController (ObjectsController *successor);
+ ~ObjIdentController ();
+
+ void objMsg (tools::CommonLineInfo *info, const char *id,
+ const char *aspect, int prio, const char *message);
+ void objMark (tools::CommonLineInfo *info, const char *id,
+ const char *aspect, int prio, const char *message);
+ void objMsgStart (tools::CommonLineInfo *info, const char *id);
+ void objMsgEnd (tools::CommonLineInfo *info, const char *id);
+ void objEnter (tools::CommonLineInfo *info, const char *id,
+ const char *aspect, int prio, const char *funname,
+ const char *args);
+ void objLeave (tools::CommonLineInfo *info, const char *id,
+ const char *vals);
+ void objCreate (tools::CommonLineInfo *info, const char *id,
+ const char *klass);
+ void objIdent (tools::CommonLineInfo *info, const char *id1,
+ const char *id2);
+ void objNoIdent (tools::CommonLineInfo *info);
+ void objAssoc (tools::CommonLineInfo *info, const char *parent,
+ const char *child);
+ void objSet (tools::CommonLineInfo *info, const char *id, const char *var,
+ const char *val);
+ void objClassColor (tools::CommonLineInfo *info, const char *klass,
+ const char *color);
+ void objObjectColor (tools::CommonLineInfo *info, const char *id,
+ const char *color);
+ void objDelete (tools::CommonLineInfo *info, const char *id);
+};
+
+} // namespace objects
+
+} // namespace rtfl
+
+#endif // __OBJECTS_OBJIDENT_CONTROLLER_HH__
diff --git a/objects/objview_commands.cc b/objects/objview_commands.cc
new file mode 100644
index 0000000..81d03aa
--- /dev/null
+++ b/objects/objview_commands.cc
@@ -0,0 +1,773 @@
+/*
+ * RTFL
+ *
+ * Copyright 2013-2015 Sebastian Geerken <sgeerken@dillo.org>
+ *
+ * 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; with the following exception:
+ *
+ * The copyright holders of RTFL give you permission to link this file
+ * statically or dynamically against all versions of the graphviz
+ * library, which are published by AT&T Corp. under one of the following
+ * licenses:
+ *
+ * - Common Public License version 1.0 as published by International
+ * Business Machines Corporation (IBM), or
+ * - Eclipse Public License version 1.0 as published by the Eclipse
+ * Foundation.
+ *
+ * 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/>.
+ */
+
+#include "objview_graph.hh" // Because ObjViewGraph is needed here.
+
+using namespace lout::object;
+using namespace lout::container::typed;
+using namespace lout::misc;
+using namespace dw::core;
+using namespace dw::core::style;
+using namespace rtfl::dw;
+
+namespace rtfl {
+
+namespace objects {
+
+static void scrollToLabel (Label *label)
+{
+ Widget *parent = label->getParent (), *child = label;
+
+ while (parent != NULL && !parent->instanceOf (ObjViewGraph::CLASS_ID)) {
+ if (parent->instanceOf (Toggle::CLASS_ID)) {
+ Toggle *toggle = (Toggle*)parent;
+ if (toggle->isLargeShown () && child == toggle->getSmall ())
+ toggle->toggle (false);
+ else if (!toggle->isLargeShown () && child == toggle->getLarge ())
+ toggle->toggle (true);
+ }
+
+ child = parent;
+ parent = parent->getParent ();
+ }
+
+ label->scrollTo (HPOS_INTO_VIEW, VPOS_INTO_VIEW);
+}
+
+// ----------------------------------------------------------------------
+
+bool OVGCommonCommand::CommandLinkReceiver::click (Widget *widget, int link,
+ int img, int x, int y,
+ EventButton *event)
+{
+ // "link" is "navigableCommandsIndex".
+ graph->setCommand (link);
+ return true;
+}
+
+// ----------------------------------------------------------------------
+
+OVGCommonCommand::OVGCommonCommand (ObjViewGraph *graph, const char *id,
+ ObjViewFunction *function)
+{
+ this->id = strdup (id);
+ this->graph = graph;
+ this->function = function;
+ relatedCommand = NULL;
+ executed = false;
+ visible = true;
+}
+
+OVGCommonCommand::~OVGCommonCommand ()
+{
+ free (id);
+}
+
+const char *OVGCommonCommand::getFileName ()
+{
+ // Not needed for non-navigable command.
+ assertNotReached ();
+ return NULL;
+}
+
+int OVGCommonCommand::getLineNo ()
+{
+ // Not needed for non-navigable command.
+ assertNotReached ();
+ return 0;
+}
+
+int OVGCommonCommand::getProcessId ()
+{
+ // Not yet clear what to do with this one.
+ assertNotReached ();
+ return 0;
+}
+
+void OVGCommonCommand::exec (ObjViewGraph *graph)
+{
+ assert (!executed);
+ assert (graph == this->graph);
+ doExec ();
+ executed = true;
+}
+
+void OVGCommonCommand::show (ObjViewGraph *graph)
+{
+ assert (executed);
+ assert (graph == this->graph);
+ visible = true;
+ doShow ();
+}
+
+void OVGCommonCommand::hide (ObjViewGraph *graph)
+{
+ assert (executed);
+ assert (graph == this->graph);
+ visible = false;
+ doHide ();
+}
+
+void OVGCommonCommand::scrollTo (ObjViewGraph *graph)
+{
+ assert (executed);
+ assert (graph == this->graph);
+ doScrollTo ();
+}
+
+void OVGCommonCommand::select (ObjViewGraph *graph)
+{
+ assert (executed);
+ assert (graph == this->graph);
+ doSelect ();
+}
+
+void OVGCommonCommand::unselect (ObjViewGraph *graph)
+{
+ assert (executed);
+ assert (graph == this->graph);
+ doUnselect ();
+}
+
+// Most commands do not have to impelemt these:
+
+void OVGCommonCommand::doShow ()
+{
+ assertNotReached ();
+}
+
+void OVGCommonCommand::doHide ()
+{
+ assertNotReached ();
+}
+
+void OVGCommonCommand::doScrollTo ()
+{
+ assertNotReached ();
+}
+
+void OVGCommonCommand::doSelect ()
+{
+ assertNotReached ();
+}
+
+void OVGCommonCommand::doUnselect ()
+{
+ assertNotReached ();
+}
+
+bool OVGCommonCommand::isVisible (ObjViewGraph *graph)
+{
+ return visible;
+}
+
+bool OVGCommonCommand::calcVisibility (ObjViewGraph *graph)
+{
+ return true;
+}
+
+int OVGCommonCommand::getNavigableCommandsIndex (ObjViewGraph *graph)
+{
+ assertNotReached ();
+ return -1;
+}
+
+void OVGCommonCommand::setNavigableCommandsIndex (ObjViewGraph *graph,
+ int navigableCommandsIndex)
+{
+ assertNotReached ();
+}
+
+void OVGCommonCommand::setVisibleIndex (ObjViewGraph *graph,
+ int visibleIndex)
+{
+ assertNotReached ();
+}
+
+// ----------------------------------------------------------------------
+
+OVGNavigableCommand::OVGNavigableCommand (const char *fileName, int lineNo,
+ ObjViewGraph *graph, const char *id,
+ ObjViewFunction *function) :
+ OVGCommonCommand (graph, id, function)
+{
+ this->fileName = strdup (fileName);
+ this->lineNo = lineNo;
+
+ navigableCommandsIndex = -1;
+ label1 = label2 = NULL;
+ hbox = NULL;
+}
+
+OVGNavigableCommand::~OVGNavigableCommand ()
+{
+ free (fileName);
+}
+
+const char *OVGNavigableCommand::getFileName ()
+{
+ return fileName;
+}
+
+int OVGNavigableCommand::getLineNo ()
+{
+ return lineNo;
+}
+
+void OVGNavigableCommand::initWidgets ()
+{
+ label1->setLink (navigableCommandsIndex);
+ label1->connectLink (&linkReceiver);
+ label2->setLink (navigableCommandsIndex);
+ label2->connectLink (&linkReceiver);
+}
+
+void OVGNavigableCommand::removeWidgets ()
+{
+ delete hbox;
+
+ label1 = label2 = NULL;
+ hbox = NULL;
+}
+
+int OVGNavigableCommand::getNavigableCommandsIndex (ObjViewGraph *graph)
+{
+ return navigableCommandsIndex;
+}
+
+void OVGNavigableCommand::setNavigableCommandsIndex (ObjViewGraph *graph,
+ int navigableCommandsIndex)
+{
+ this->navigableCommandsIndex = navigableCommandsIndex;
+ if (label1)
+ label1->setLink (navigableCommandsIndex);
+ if (label2)
+ label2->setLink (navigableCommandsIndex);
+}
+
+void OVGNavigableCommand::setVisibleIndex (ObjViewGraph *graph,
+ int visibleIndex)
+{
+ assert (label1 != NULL);
+
+ // Assume 5 digits (99999) at max.
+ char buf[15];
+ snprintf (buf, 15, "<i>%d:</i> ", visibleIndex);
+ label1->setText (buf);
+}
+
+void OVGNavigableCommand::doShow ()
+{
+ label1->show ();
+ label2->show ();
+}
+
+void OVGNavigableCommand::doHide ()
+{
+ label1->hide ();
+ label2->hide ();
+}
+
+void OVGNavigableCommand::doScrollTo ()
+{
+ scrollToLabel (label2);
+}
+
+void OVGNavigableCommand::doSelect ()
+{
+ label1->select ();
+ label2->select ();
+}
+
+void OVGNavigableCommand::doUnselect ()
+{
+ label1->unselect ();
+ label2->unselect ();
+}
+
+// ----------------------------------------------------------------------
+
+OVGIncIndentCommand::OVGIncIndentCommand (const char *fileName, int lineNo,
+ ObjViewGraph *graph, const char *id,
+ ObjViewFunction *function) :
+ OVGNavigableCommand (fileName, lineNo, graph, id, function)
+{
+ linkReceiver.setData (graph, this);
+}
+
+OVGIncIndentCommand::~OVGIncIndentCommand ()
+{
+}
+
+bool OVGIncIndentCommand::calcVisibility (ObjViewGraph *graph)
+{
+ return graph->filterTool->isTypeSelected (OVG_COMMAND_INDENT);
+}
+
+void OVGIncIndentCommand::doExec ()
+{
+ graph->addMessage (id, "<i>start</i>", &hbox, &label1, &label2);
+ initWidgets ();
+ success = graph->incIndent (id);
+}
+
+// ----------------------------------------------------------------------
+
+OVGDecIndentCommand::OVGDecIndentCommand (const char *fileName, int lineNo,
+ ObjViewGraph *graph, const char *id,
+ OVGIncIndentCommand *startCommand,
+ ObjViewFunction *function) :
+ OVGNavigableCommand (fileName, lineNo, graph, id, function)
+{
+ linkReceiver.setData (graph, this);
+
+ setRelatedCommand (startCommand);
+ startCommand->setRelatedCommand (this);
+}
+
+OVGDecIndentCommand::~OVGDecIndentCommand ()
+{
+}
+
+bool OVGDecIndentCommand::calcVisibility (ObjViewGraph *graph)
+{
+ return graph->filterTool->isTypeSelected (OVG_COMMAND_INDENT);
+}
+
+void OVGDecIndentCommand::doExec ()
+{
+ success = graph->decIndent (id);
+ graph->addMessage (id, "<i>end</i>", &hbox, &label1, &label2);
+ initWidgets ();
+}
+
+// ----------------------------------------------------------------------
+
+OVGEnterCommand::OVGEnterCommand (const char *fileName, int lineNo,
+ ObjViewGraph *graph, const char *id,
+ const char *aspect, int prio,
+ const char *funname, const char *args,
+ ObjViewFunction *function) :
+ OVGNavigableCommand (fileName, lineNo, graph, id, function)
+{
+ linkReceiver.setData (graph, this);
+
+ graph->filterTool->addAspect (aspect);
+ graph->filterTool->addPriority (prio);
+
+ this->aspect = strdup (aspect);
+ this->prio = prio;
+ this->funname = strdup (funname);
+ this->args = strdup (args);
+}
+
+OVGEnterCommand::~OVGEnterCommand ()
+{
+ free (aspect);
+ free (funname);
+ free (args);
+}
+
+bool OVGEnterCommand::calcVisibility (ObjViewGraph *graph)
+{
+ return graph->filterTool->isTypeSelected (OVG_COMMAND_FUNCTION) &&
+ graph->filterTool->isAspectSelected (aspect) &&
+ graph->filterTool->isPrioritySelected (prio);
+}
+
+void OVGEnterCommand::doExec ()
+{
+ char *message = createMessage ("<i>enter</i>: <b>", "</b> (", ")", "");
+ graph->addMessage (id, message, &hbox, &label1, &label2);
+ freeMessage (message);
+ initWidgets ();
+
+ success = graph->incIndent (id);
+}
+
+char *OVGEnterCommand::createMessage (const char *c1, const char *c2,
+ const char *c3a, const char *c3b)
+{
+ size_t l = strlen (c1) + strlen (funname) + strlen (c2) + strlen (args) +
+ strlen (c3a) + strlen (c3b) + 1;
+ char *message = new char[l];
+ snprintf (message, l, "%s%s%s%s%s%s", c1, funname, c2, args, c3a, c3b);
+ return message;
+}
+
+void OVGEnterCommand::freeMessage (char *message)
+{
+ delete[] message;
+}
+
+char *OVGEnterCommand::createName ()
+{
+ size_t l =
+ 1 + strlen (id) + 2 + strlen (funname) + 2 + strlen (args) + 1 + 1;
+ char *message = new char[l];
+ snprintf (message, l, "[%s] %s (%s)", id, funname, args);
+ return message;
+}
+
+void OVGEnterCommand::freeName (char *name)
+{
+ delete[] name;
+}
+
+int OVGEnterCommand::getColor ()
+{
+ return graph->getObjectColor (id);
+}
+
+ObjViewFunction *OVGEnterCommand::getParent ()
+{
+ return getFunction ();
+}
+
+bool OVGEnterCommand::isSelectable ()
+{
+ return isVisible (graph);
+}
+
+void OVGEnterCommand::select ()
+{
+ graph->clearSelection ();
+ graph->navigableCommandsPos = navigableCommandsIndex;
+ graph->unclearSelection ();
+}
+
+// ----------------------------------------------------------------------
+
+OVGLeaveCommand::OVGLeaveCommand (const char *fileName, int lineNo,
+ ObjViewGraph *graph, const char *id,
+ const char *vals,
+ OVGEnterCommand *enterCommand) :
+ OVGNavigableCommand (fileName, lineNo, graph, id, enterCommand)
+{
+ linkReceiver.setData (graph, this);
+
+ this->enterCommand = enterCommand;
+ this->vals = vals ? strdup (vals) : NULL;
+
+ setRelatedCommand (enterCommand);
+ enterCommand->setRelatedCommand (this);
+}
+
+OVGLeaveCommand::~OVGLeaveCommand ()
+{
+ if (vals)
+ free (vals);
+}
+
+bool OVGLeaveCommand::calcVisibility (ObjViewGraph *graph)
+{
+ return enterCommand->calcVisibility (graph);
+}
+
+void OVGLeaveCommand::doExec ()
+{
+ success = graph->decIndent (id);
+
+ char *message = vals ?
+ enterCommand->createMessage ("<i>leave: ", "</i> (", ") ⇒ ", vals) :
+ enterCommand->createMessage ("<i>leave: ", "</i> (", ")", "");
+
+ graph->addMessage (id, message, &hbox, &label1, &label2);
+ enterCommand->freeMessage (message);
+ initWidgets ();
+}
+
+// ----------------------------------------------------------------------
+
+OVGAddMessageCommand::OVGAddMessageCommand (const char *fileName, int lineNo,
+ ObjViewGraph *graph,
+ const char *id, const char *aspect,
+ int prio, const char *message,
+ ObjViewFunction *function) :
+ OVGNavigableCommand (fileName, lineNo, graph, id, function)
+{
+ linkReceiver.setData (graph, this);
+
+ graph->filterTool->addAspect (aspect);
+ graph->filterTool->addPriority (prio);
+
+ this->aspect = strdup (aspect);
+ this->prio = prio;
+ this->message = strdup (message);
+}
+
+OVGAddMessageCommand::~OVGAddMessageCommand ()
+{
+ free (aspect);
+ free (message);
+}
+
+bool OVGAddMessageCommand::calcVisibility (ObjViewGraph *graph)
+{
+ return graph->filterTool->isTypeSelected (OVG_COMMAND_MESSAGE) &&
+ graph->filterTool->isAspectSelected (aspect) &&
+ graph->filterTool->isPrioritySelected (prio);
+}
+
+void OVGAddMessageCommand::doExec ()
+{
+ graph->addMessage (id, message, &hbox, &label1, &label2);
+ initWidgets ();
+}
+
+// ----------------------------------------------------------------------
+
+OVGAddMarkCommand::OVGAddMarkCommand (const char *fileName, int lineNo,
+ ObjViewGraph *graph,
+ const char *id, const char *aspect,
+ int prio, const char *mark,
+ ObjViewFunction *function) :
+ OVGNavigableCommand (fileName, lineNo, graph, id, function)
+{
+ linkReceiver.setData (graph, this);
+
+ graph->filterTool->addAspect (aspect);
+ graph->filterTool->addPriority (prio);
+
+ this->aspect = strdup (aspect);
+ this->prio = prio;
+ this->mark = strdup (mark);
+}
+
+OVGAddMarkCommand::~OVGAddMarkCommand ()
+{
+ free (aspect);
+ free (mark);
+}
+
+bool OVGAddMarkCommand::calcVisibility (ObjViewGraph *graph)
+{
+ return graph->filterTool->isTypeSelected (OVG_COMMAND_MARK) &&
+ graph->filterTool->isAspectSelected (aspect) &&
+ graph->filterTool->isPrioritySelected (prio);
+}
+
+void OVGAddMarkCommand::doExec ()
+{
+ size_t l = 13 + strlen (mark) + 1;
+ char *message = new char[l];
+ snprintf (message, l, "<i>mark:</i> %s", mark);
+
+ graph->addMessage (id, message, &hbox, &label1, &label2);
+ initWidgets ();
+
+ delete[] message;
+}
+
+bool OVGAddMarkCommand::isSelectable ()
+{
+ return isVisible (graph);
+}
+
+void OVGAddMarkCommand::select ()
+{
+ graph->clearSelection ();
+ graph->navigableCommandsPos = navigableCommandsIndex;
+ graph->unclearSelection ();
+}
+
+// ----------------------------------------------------------------------
+
+OVGCreateCommand::OVGCreateCommand (const char *fileName, int lineNo,
+ ObjViewGraph *graph, const char *id,
+ const char *className,
+ ObjViewFunction *function):
+ OVGNavigableCommand (fileName, lineNo, graph, id, function)
+{
+ this->className = strdup (className);
+ linkReceiver.setData (graph, this);
+}
+
+OVGCreateCommand::~OVGCreateCommand ()
+{
+ free (className);
+}
+
+bool OVGCreateCommand::calcVisibility (ObjViewGraph *graph)
+{
+ return graph->filterTool->isTypeSelected (OVG_COMMAND_CREATE);
+}
+
+void OVGCreateCommand::doExec ()
+{
+ size_t l = 15 + strlen (className) + 1;
+ char *message = new char[l];
+ snprintf (message, l, "<i>create:</i> %s", className);
+
+ graph->addMessage (id, message, &hbox, &label1, &label2);
+ initWidgets ();
+
+ delete[] message;
+
+ graph->setClassName (id, className);
+}
+
+// ----------------------------------------------------------------------
+
+OVGAddAssocCommand::OVGAddAssocCommand (const char *fileName, int lineNo,
+ ObjViewGraph *graph,
+ const char *id1, const char *id2,
+ ObjViewFunction *function) :
+ OVGNavigableCommand (fileName, lineNo, graph, id1, function)
+{
+ linkReceiver.setData (graph, this);
+ this->id2 = strdup (id2);
+}
+
+OVGAddAssocCommand::~OVGAddAssocCommand ()
+{
+ free (id2);
+}
+
+bool OVGAddAssocCommand::calcVisibility (ObjViewGraph *graph)
+{
+ return graph->filterTool->isTypeSelected (OVG_COMMAND_ASSOC);
+}
+
+void OVGAddAssocCommand::doExec ()
+{
+ size_t l = 14 + strlen (id2) + 5 + 1;
+ char *message = new char[l];
+ snprintf (message, l, "<i>assoc → %s</i>", id2);
+
+ graph->addMessage (id, message, &hbox, &label1, &label2);
+ initWidgets ();
+
+ delete[] message;
+
+ graph->addAssoc (id, id2);
+}
+
+// ----------------------------------------------------------------------
+
+OVGAddAttrCommand::OVGAddAttrCommand (const char *fileName, int lineNo,
+ ObjViewGraph *graph, const char *id,
+ const char *name,const char *value,
+ ObjViewFunction *function) :
+ OVGNavigableCommand (fileName, lineNo, graph, id, function)
+{
+ linkReceiver.setData (graph, this);
+
+ this->name = strdup (name);
+ this->value = strdup (value);
+
+ smallLabel = NULL;
+ attribute = NULL;
+ childNo = -1;
+}
+
+OVGAddAttrCommand::~OVGAddAttrCommand ()
+{
+ free (name);
+ free (value);
+}
+
+bool OVGAddAttrCommand::calcVisibility (ObjViewGraph *graph)
+{
+ return graph->filterTool->isTypeSelected (OVG_COMMAND_ADD_ATTR);
+}
+
+void OVGAddAttrCommand::doExec ()
+{
+ attribute = graph->addAttribute (id, name, value, &smallLabel, NULL, &label1,
+ &label2);
+ childNo = attribute->registerChild ();
+ initWidgets ();
+}
+
+void OVGAddAttrCommand::doShow ()
+{
+ OVGNavigableCommand::doShow ();
+
+ // Set the appropriate current value (seen when the history is
+ // hidden). It can be assumed that doShow() is called in the order
+ // of the creation, so the last visible command will stay; this
+ // does indeed represent the current value.
+ assert (smallLabel != NULL);
+ smallLabel->setText (value);
+
+ // ...
+ assert (attribute != NULL);
+ assert (childNo != -1);
+ attribute->childShown (childNo);
+}
+
+void OVGAddAttrCommand::doHide ()
+{
+ OVGNavigableCommand::doHide ();
+
+ // ...
+ assert (attribute != NULL);
+ assert (childNo != -1);
+ attribute->childHidden (childNo);
+}
+
+// ----------------------------------------------------------------------
+
+OVGDeleteCommand::OVGDeleteCommand (const char *fileName, int lineNo,
+ ObjViewGraph *graph, const char *id,
+ ObjViewFunction *function) :
+ OVGNavigableCommand (fileName, lineNo, graph, id, function)
+{
+ linkReceiver.setData (graph, this);
+}
+
+OVGDeleteCommand::~OVGDeleteCommand ()
+{
+}
+
+bool OVGDeleteCommand::calcVisibility (ObjViewGraph *graph)
+{
+ return graph->filterTool->isTypeSelected (OVG_COMMAND_DELETE);
+}
+
+void OVGDeleteCommand::doExec ()
+{
+ graph->addMessage (id, "<i>delete</i>", &hbox, &label1, &label2);
+ initWidgets ();
+
+ // Change appearance of window (simple experiment).
+ //Widget *node = graph->ensureObject(id)->node;
+ //StyleAttrs attrs = *(node->getStyle());
+ //attrs.setBorderStyle (BORDER_DOTTED);
+ //node->setStyle (Style::create (&attrs));
+
+ // Furthermore, this message is added often several times, since this command
+ // is printed in all destructors in the class hierarchie. Should be limited
+ // to once.
+}
+
+} // namespace objects
+
+} // namespace rtfl
diff --git a/objects/objview_commands.hh b/objects/objview_commands.hh
new file mode 100644
index 0000000..8e81e99
--- /dev/null
+++ b/objects/objview_commands.hh
@@ -0,0 +1,349 @@
+#ifndef __OBJECTS_OBJVIEW_COMMANDS_HH__
+#define __OBJECTS_OBJVIEW_COMMANDS_HH__
+
+#include "objview_stacktrace.hh"
+#include "dwr/toggle.hh"
+#include "dwr/vbox.hh"
+#include "dwr/hbox.hh"
+#include "dwr/label.hh"
+
+namespace rtfl {
+
+namespace objects {
+
+class ObjViewGraph;
+class OVGAttribute;
+
+/*
+ * TODO: OVGCommand was originally introduced to provide a undo/redo mechanism
+ * needed for handling "obj-ident". Now, after "obj-ident" is handled by
+ * ObjIdentController, OVGCommand can be simplified and reduced to navigable
+ * commands.
+ */
+
+class OVGCommand: public lout::object::Object
+{
+public:
+ virtual const char *getFileName () = 0;
+ virtual int getLineNo () = 0;
+ virtual int getProcessId () = 0;
+
+ virtual void exec (ObjViewGraph *graph) = 0;
+ virtual void show (ObjViewGraph *graph) = 0;
+ virtual void hide (ObjViewGraph *graph) = 0;
+ virtual void scrollTo (ObjViewGraph *graph) = 0;
+ virtual void select (ObjViewGraph *graph) = 0;
+ virtual void unselect (ObjViewGraph *graph) = 0;
+ virtual bool isVisible (ObjViewGraph *graph) = 0;
+ virtual bool calcVisibility (ObjViewGraph *graph) = 0;
+ virtual int getNavigableCommandsIndex (ObjViewGraph *graph) = 0;
+ virtual void setNavigableCommandsIndex (ObjViewGraph *graph,
+ int navigableCommandsIndex) = 0;
+ virtual void setVisibleIndex (ObjViewGraph *graph,
+ int visibleIndex) = 0;
+ virtual ObjViewFunction *getFunction () = 0;
+ virtual void setRelatedCommand (OVGCommand *relatedCommand) = 0;
+ virtual OVGCommand *getRelatedCommand () = 0;
+};
+
+
+class OVGCommonCommand: public OVGCommand
+{
+private:
+ bool executed, visible;
+ ObjViewFunction *function;
+ OVGCommand *relatedCommand;
+
+protected:
+ class CommandLinkReceiver: public ::dw::core::Layout::LinkReceiver
+ {
+ private:
+ ObjViewGraph *graph;
+ OVGCommand *command;
+
+ public:
+ inline CommandLinkReceiver () { graph = NULL; }
+ inline void setData (ObjViewGraph *graph,
+ OVGCommand *command)
+ { this->graph = graph; this->command = command; }
+
+ bool click (::dw::core::Widget *widget, int link, int img, int x, int y,
+ ::dw::core::EventButton *event);
+ };
+
+ char *id;
+ ObjViewGraph *graph;
+
+ virtual void doExec () = 0;
+ virtual void doShow ();
+ virtual void doHide ();
+ virtual void doScrollTo ();
+ virtual void doSelect ();
+ virtual void doUnselect ();
+
+public:
+ OVGCommonCommand (ObjViewGraph *graph, const char *id,
+ ObjViewFunction *function);
+ ~OVGCommonCommand ();
+
+ const char *getFileName ();
+ int getLineNo ();
+ int getProcessId ();
+
+ void exec (ObjViewGraph *graph);
+ void show (ObjViewGraph *graph);
+ void hide (ObjViewGraph *graph);
+ void scrollTo (ObjViewGraph *graph);
+ void select (ObjViewGraph *graph);
+ void unselect (ObjViewGraph *graph);
+ bool isVisible (ObjViewGraph *graph);
+ bool calcVisibility (ObjViewGraph *graph);
+ int getNavigableCommandsIndex (ObjViewGraph *graph);
+ void setNavigableCommandsIndex (ObjViewGraph *graph,
+ int navigableCommandsIndex);
+ void setVisibleIndex (ObjViewGraph *graph, int visibleIndex);
+ ObjViewFunction *getFunction () { return function; }
+ void setRelatedCommand (OVGCommand *relatedCommand)
+ { this->relatedCommand = relatedCommand; }
+ OVGCommand *getRelatedCommand () { return relatedCommand; }
+};
+
+
+class OVGNavigableCommand: public OVGCommonCommand
+{
+private:
+ char *fileName;
+ int lineNo;
+
+protected:
+ int navigableCommandsIndex;
+ dw::HBox *hbox;
+ dw::Label *label1, *label2;
+ CommandLinkReceiver linkReceiver;
+
+ void doShow ();
+ void doHide ();
+ void doScrollTo ();
+ void doSelect ();
+ void doUnselect ();
+
+ void initWidgets ();
+ void removeWidgets ();
+
+public:
+ OVGNavigableCommand (const char *fileName, int lineNo, ObjViewGraph *graph,
+ const char *id, ObjViewFunction *function);
+ ~OVGNavigableCommand ();
+
+ const char *getFileName ();
+ int getLineNo ();
+
+ int getNavigableCommandsIndex (ObjViewGraph *graph);
+ void setNavigableCommandsIndex (ObjViewGraph *graph,
+ int navigableCommandsIndex);
+ void setVisibleIndex (ObjViewGraph *graph, int visibleIndex);
+};
+
+class OVGIncIndentCommand: public OVGNavigableCommand
+{
+private:
+ bool success;
+
+protected:
+ void doExec ();
+
+public:
+ OVGIncIndentCommand (const char *fileName, int lineNo, ObjViewGraph *graph,
+ const char *id, ObjViewFunction *function);
+ ~OVGIncIndentCommand ();
+
+ bool calcVisibility (ObjViewGraph *graph);
+};
+
+
+class OVGDecIndentCommand: public OVGNavigableCommand
+{
+private:
+ bool success;
+
+protected:
+ void doExec ();
+
+public:
+ OVGDecIndentCommand (const char *fileName, int lineNo, ObjViewGraph *graph,
+ const char *id, OVGIncIndentCommand *startCommand,
+ ObjViewFunction *function);
+ ~OVGDecIndentCommand ();
+
+ bool calcVisibility (ObjViewGraph *graph);
+};
+
+class OVGEnterCommand: public OVGNavigableCommand, public ObjViewFunction
+{
+private:
+ char *aspect, *funname, *args;
+ int prio;
+ bool success;
+
+protected:
+ void doExec ();
+
+public:
+ OVGEnterCommand (const char *fileName, int lineNo, ObjViewGraph *graph,
+ const char *id, const char *aspect, int prio,
+ const char *funname, const char *args,
+ ObjViewFunction *function);
+ ~OVGEnterCommand ();
+
+ bool calcVisibility (ObjViewGraph *graph);
+
+ char *createMessage (const char *c1, const char *c2, const char *c3a,
+ const char *c3b);
+ void freeMessage (char *message);
+
+ char *createName ();
+ void freeName (char *name);
+ int getColor ();
+ ObjViewFunction *getParent ();
+ bool isSelectable ();
+ void select ();
+};
+
+class OVGLeaveCommand: public OVGNavigableCommand
+{
+private:
+ OVGEnterCommand *enterCommand;
+ char *vals;
+ bool success;
+
+protected:
+ void doExec ();
+
+public:
+ OVGLeaveCommand (const char *fileName, int lineNo, ObjViewGraph *graph,
+ const char *id, const char *vals,
+ OVGEnterCommand *enterCommand);
+ ~OVGLeaveCommand ();
+
+ bool calcVisibility (ObjViewGraph *graph);
+};
+
+class OVGAddMessageCommand: public OVGNavigableCommand
+{
+private:
+ char *aspect, *message;
+ int prio;
+
+protected:
+ void doExec ();
+
+public:
+ OVGAddMessageCommand (const char *fileName, int lineNo, ObjViewGraph *graph,
+ const char *id, const char *aspect, int prio,
+ const char *message, ObjViewFunction *function);
+ ~OVGAddMessageCommand ();
+
+ bool calcVisibility (ObjViewGraph *graph);
+};
+
+
+class OVGAddMarkCommand: public OVGNavigableCommand
+{
+private:
+ char *aspect, *mark;
+ int prio;
+
+protected:
+ void doExec ();
+
+public:
+ OVGAddMarkCommand (const char *fileName, int lineNo, ObjViewGraph *graph,
+ const char *id, const char *aspect, int prio,
+ const char *mark, ObjViewFunction *function);
+ ~OVGAddMarkCommand ();
+
+ bool calcVisibility (ObjViewGraph *graph);
+
+ const char *getMark () { return mark; }
+ bool isSelectable ();
+ void select ();
+};
+
+
+class OVGCreateCommand: public OVGNavigableCommand
+{
+private:
+ char *className;
+
+protected:
+ void doExec ();
+
+public:
+ OVGCreateCommand (const char *fileName, int lineNo, ObjViewGraph *graph,
+ const char *id, const char *className,
+ ObjViewFunction *function);
+ ~OVGCreateCommand ();
+
+ bool calcVisibility (ObjViewGraph *graph);
+};
+
+
+class OVGAddAssocCommand: public OVGNavigableCommand
+{
+private:
+ char *id2;
+
+protected:
+ void doExec ();
+
+public:
+ OVGAddAssocCommand (const char *fileName, int lineNo, ObjViewGraph *graph,
+ const char *id1, const char *id2,
+ ObjViewFunction *function);
+ ~OVGAddAssocCommand ();
+
+ bool calcVisibility (ObjViewGraph *graph);
+};
+
+
+class OVGAddAttrCommand: public OVGNavigableCommand
+{
+private:
+ char *name, *value;
+ dw::Label *smallLabel;
+ OVGAttribute *attribute;
+ int childNo;
+
+protected:
+ void doExec ();
+ void doShow ();
+ void doHide ();
+
+public:
+ OVGAddAttrCommand (const char *fileName, int lineNo, ObjViewGraph *graph,
+ const char *id, const char *name, const char *value,
+ ObjViewFunction *function);
+ ~OVGAddAttrCommand ();
+
+ bool calcVisibility (ObjViewGraph *graph);
+};
+
+
+class OVGDeleteCommand: public OVGNavigableCommand
+{
+protected:
+ void doExec ();
+
+public:
+ OVGDeleteCommand (const char *fileName, int lineNo, ObjViewGraph *graph,
+ const char *id, ObjViewFunction *function);
+ ~OVGDeleteCommand ();
+
+ bool calcVisibility (ObjViewGraph *graph);
+};
+
+} // namespace objects
+
+} // namespace rtfl
+
+#endif // __OBJECTS_OBJVIEW_COMMANDS_HH__
diff --git a/objects/objview_controller.cc b/objects/objview_controller.cc
new file mode 100644
index 0000000..8d40dbc
--- /dev/null
+++ b/objects/objview_controller.cc
@@ -0,0 +1,171 @@
+/*
+ * RTFL
+ *
+ * Copyright 2013-2015 Sebastian Geerken <sgeerken@dillo.org>
+ *
+ * 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; with the following exception:
+ *
+ * The copyright holders of RTFL give you permission to link this file
+ * statically or dynamically against all versions of the graphviz
+ * library, which are published by AT&T Corp. under one of the following
+ * licenses:
+ *
+ * - Common Public License version 1.0 as published by International
+ * Business Machines Corporation (IBM), or
+ * - Eclipse Public License version 1.0 as published by the Eclipse
+ * Foundation.
+ *
+ * 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/>.
+ */
+
+#include <stdio.h>
+#include "objview_controller.hh"
+
+using namespace rtfl::tools;
+
+namespace rtfl {
+
+namespace objects {
+
+void ObjViewController::objMsg (CommonLineInfo *info, const char *id,
+ const char *aspect, int prio,
+ const char *message)
+{
+ graph->addCommand (new OVGAddMessageCommand (info->fileName, info->lineNo,
+ graph, id, aspect, prio,
+ message,
+ graph->getLastEnterCommand ()),
+ true);
+}
+
+void ObjViewController::objMark (CommonLineInfo *info, const char *id,
+ const char *aspect, int prio,
+ const char *message)
+{
+ OVGAddMarkCommand *markCommand =
+ new OVGAddMarkCommand (info->fileName, info->lineNo, graph, id, aspect,
+ prio, message, graph->getLastEnterCommand ());
+ graph->addCommand (markCommand, true);
+ graph->addCommandMark (markCommand);
+}
+
+void ObjViewController::objMsgStart (CommonLineInfo *info, const char *id)
+{
+ OVGIncIndentCommand *startCommand =
+ new OVGIncIndentCommand (info->fileName, info->lineNo, graph, id,
+ graph->getLastEnterCommand ());
+ graph->addCommand (startCommand, true);
+ graph->pushStartCommand (startCommand);
+}
+
+void ObjViewController::objMsgEnd (CommonLineInfo *info, const char *id)
+{
+ OVGIncIndentCommand *lastStartCommand = graph->getLastStartCommand ();
+ if (lastStartCommand == NULL)
+ fprintf (stderr, "'obj-msg-end' without 'obj-msg-start:\n%s\n",
+ info->completeLine);
+ else {
+ graph->addCommand (new OVGDecIndentCommand (info->fileName, info->lineNo,
+ graph, id, lastStartCommand,
+ graph->getLastEnterCommand()),
+ true);
+ graph->popStartCommand ();
+ }
+}
+
+void ObjViewController::objEnter (CommonLineInfo *info, const char *id,
+ const char *aspect, int prio,
+ const char *funname, const char *args)
+{
+ OVGEnterCommand *enterCommand =
+ new OVGEnterCommand (info->fileName, info->lineNo, graph, id, aspect,
+ prio, funname, args, graph->getLastEnterCommand ());
+ graph->addCommand (enterCommand, true);
+ graph->pushEnterCommand (enterCommand);
+}
+
+void ObjViewController::objLeave (CommonLineInfo *info, const char *id,
+ const char *vals)
+{
+ OVGEnterCommand *lastEnterCommand = graph->getLastEnterCommand ();
+ if (lastEnterCommand == NULL)
+ fprintf (stderr, "'obj-leave' without 'obj-enter:\n%s\n",
+ info->completeLine);
+ else {
+ graph->addCommand (new OVGLeaveCommand (info->fileName, info->lineNo,
+ graph, id, vals,
+ lastEnterCommand),
+ true);
+ graph->popEnterCommand ();
+ }
+}
+
+void ObjViewController::objCreate (CommonLineInfo *info, const char *id,
+ const char *klass)
+{
+ graph->addCommand (new OVGCreateCommand (info->fileName, info->lineNo, graph,
+ id, klass,
+ graph->getLastEnterCommand ()),
+ true);
+}
+
+void ObjViewController::objIdent (CommonLineInfo *info, const char *id1,
+ const char *id2)
+{
+ // TODO Is this not done by ObjdentController?
+ graph->addIdentity (id1, id2);
+}
+
+void ObjViewController::objNoIdent (CommonLineInfo *info)
+{
+}
+
+void ObjViewController::objAssoc (CommonLineInfo *info, const char *parent,
+ const char *child)
+{
+ graph->addCommand (new OVGAddAssocCommand (info->fileName, info->lineNo,
+ graph, parent, child,
+ graph->getLastEnterCommand ()),
+ true);
+}
+
+void ObjViewController::objSet (CommonLineInfo *info, const char *id,
+ const char *var, const char *val)
+{
+ graph->addCommand (new OVGAddAttrCommand (info->fileName, info->lineNo,
+ graph, id, var, val,
+ graph->getLastEnterCommand ()),
+ true);
+}
+
+void ObjViewController::objClassColor (CommonLineInfo *info, const char *klass,
+ const char *color)
+{
+ graph->setClassColor (klass, color);
+}
+
+void ObjViewController::objObjectColor (CommonLineInfo *info, const char *id,
+ const char *color)
+{
+ graph->setObjectColor (id, color);
+}
+
+void ObjViewController::objDelete (CommonLineInfo *info, const char *id)
+{
+ graph->addCommand (new OVGDeleteCommand (info->fileName, info->lineNo, graph,
+ id, graph->getLastEnterCommand ()),
+ true);
+}
+
+} // namespace objects
+
+} // namespace rtfl
diff --git a/objects/objview_controller.hh b/objects/objview_controller.hh
new file mode 100644
index 0000000..cc14a7f
--- /dev/null
+++ b/objects/objview_controller.hh
@@ -0,0 +1,51 @@
+#ifndef __OBJECTS_OBJVIEW_CONTROLLER_HH__
+#define __OBJECTS_OBJVIEW_CONTROLLER_HH__
+
+#include "objects_parser.hh"
+#include "objview_graph.hh"
+
+namespace rtfl {
+
+namespace objects {
+
+class ObjViewController: public ObjectsControllerBase
+{
+private:
+ ObjViewGraph *graph;
+
+public:
+ ObjViewController (ObjViewGraph *graph) { this->graph = graph; }
+
+ void objMsg (tools::CommonLineInfo *info, const char *id,
+ const char *aspect, int prio, const char *message);
+ void objMark (tools::CommonLineInfo *info, const char *id,
+ const char *aspect, int prio, const char *message);
+ void objMsgStart (tools::CommonLineInfo *info, const char *id);
+ void objMsgEnd (tools::CommonLineInfo *info, const char *id);
+ void objEnter (tools::CommonLineInfo *info, const char *id,
+ const char *aspect, int prio, const char *funname,
+ const char *args);
+ void objLeave (tools::CommonLineInfo *info, const char *id,
+ const char *vals);
+ void objCreate (tools::CommonLineInfo *info, const char *id,
+ const char *klass);
+ void objIdent (tools::CommonLineInfo *info, const char *id1,
+ const char *id2);
+ void objNoIdent (tools::CommonLineInfo *info);
+ void objAssoc (tools::CommonLineInfo *info, const char *parent,
+ const char *child);
+ void objSet (tools::CommonLineInfo *info, const char *id, const char *var,
+ const char *val);
+ void objClassColor (tools::CommonLineInfo *info, const char *klass,
+ const char *color);
+ void objObjectColor (tools::CommonLineInfo *info, const char *id,
+ const char *color);
+ void objDelete (tools::CommonLineInfo *info, const char *id);
+
+};
+
+} // namespace objects
+
+} // namespace rtfl
+
+#endif // __OBJECTS_OBJVIEW_CONTROLLER_HH__
diff --git a/objects/objview_graph.cc b/objects/objview_graph.cc
new file mode 100644
index 0000000..6528f8a
--- /dev/null
+++ b/objects/objview_graph.cc
@@ -0,0 +1,984 @@
+/*
+ * RTFL
+ *
+ * Copyright 2013-2015 Sebastian Geerken <sgeerken@dillo.org>
+ *
+ * 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; with the following exception:
+ *
+ * The copyright holders of RTFL give you permission to link this file
+ * statically or dynamically against all versions of the graphviz
+ * library, which are published by AT&T Corp. under one of the following
+ * licenses:
+ *
+ * - Common Public License version 1.0 as published by International
+ * Business Machines Corporation (IBM), or
+ * - Eclipse Public License version 1.0 as published by the Eclipse
+ * Foundation.
+ *
+ * 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/>.
+ */
+
+#include "objview_graph.hh"
+
+#include <fnmatch.h>
+#include <unistd.h>
+
+using namespace lout::object;
+using namespace lout::container;
+using namespace lout::container::typed;
+using namespace lout::misc;
+using namespace dw::core;
+using namespace dw::core::style;
+using namespace rtfl::dw;
+
+namespace rtfl {
+
+namespace objects {
+
+void ObjViewGraphListener::close (ObjViewStacktraceWindow *window)
+{
+ graph->stacktraceWindows->removeRef (window);
+}
+
+// ----------------------------------------------------------------------
+
+OVGAttributesList::OVGAttributesList (OVGAttributesList *parent)
+{
+ this->parent = parent;
+
+ childNoCount = numChildrenShown = 0;
+ childrenShown = new BitSet (8);
+ shown = true;
+
+ if (parent)
+ childNo = parent->registerChild ();
+ else
+ childNo = -1;
+
+ attributes = new HashTable<String, OVGAttribute> (true, true);
+}
+
+OVGAttributesList::~OVGAttributesList ()
+{
+ if (parent)
+ parent->unregisterChild (childNo);
+
+ delete childrenShown;
+
+ delete attributes;
+}
+
+void OVGAttributesList::initWidgets (Style *widgetStyle, dw::Box *parent,
+ bool showLarge)
+{
+ toggle = new Toggle (showLarge);
+ toggle->setStyle (widgetStyle);
+ parent->addChild (toggle);
+
+ vbox = new VBox (false);
+ vbox->setStyle (widgetStyle);
+ toggle->setLarge (vbox);
+}
+
+int OVGAttributesList::registerChild ()
+{
+ int childNo = childNoCount++;
+
+ //printf (" %p (%p) / %d -- registerChild => %d\n",
+ // this, parent, this->childNo, childNo);
+
+ childShown (childNo);
+ return childNo;
+}
+
+void OVGAttributesList::unregisterChild (int childNo)
+{
+ // Should (could?) actually destroy this attribute (if this is an
+ // attribute) when no registered children are left.
+ childHidden (childNo);
+}
+
+void OVGAttributesList::childShown (int childNo)
+{
+ if (!childrenShown->get (childNo)) {
+ childrenShown->set (childNo, true);
+ numChildrenShown++;
+ checkVisibility ();
+ }
+}
+
+void OVGAttributesList::childHidden (int childNo)
+{
+ if (childrenShown->get (childNo)) {
+ childrenShown->set (childNo, false);
+ numChildrenShown--;
+ checkVisibility ();
+ }
+}
+
+void OVGAttributesList::checkVisibility ()
+{
+ //printf (" %p (%p) / %d -- %d children shown\n",
+ // this, parent, childNo, numChildrenShown);
+
+ if (shown) {
+ if (numChildrenShown <= 0) {
+ shown = false;
+ hide ();
+ if (parent)
+ parent->childHidden (childNo);
+ }
+ } else {
+ if (numChildrenShown > 0) {
+ shown = true;
+ show ();
+ if (parent)
+ parent->childShown (childNo);
+ }
+ }
+}
+
+// ----------------------------------------------------------------------
+
+OVGTopAttributes::OVGTopAttributes () : OVGAttributesList (NULL)
+{
+ sortedList = new Vector<String> (4, false);
+}
+
+OVGTopAttributes::~OVGTopAttributes ()
+{
+ delete sortedList;
+}
+
+int OVGTopAttributes::add (String *key, OVGAttribute *attribute)
+{
+ int newPos = sortedList->insertSorted (key);
+ attributes->put (key, attribute);
+ return newPos;
+}
+
+void OVGTopAttributes::show ()
+{
+ // Keep the top list visible.
+}
+
+void OVGTopAttributes::hide ()
+{
+ // Keep the top list visible.
+}
+
+// ----------------------------------------------------------------------
+
+OVGAttribute::OVGAttribute (const char *name, OVGAttributesList *parent) :
+ OVGAttributesList (parent)
+{
+ this->name = strdup (name);
+}
+
+OVGAttribute::~OVGAttribute ()
+{
+ free (name);
+}
+
+void OVGAttribute::initWidgets (Style *widgetStyle, dw::Box *parent,
+ bool showLarge, int newPos)
+{
+ hbox = new HBox (false);
+ hbox->setStyle (widgetStyle);
+ parent->addChild (hbox, newPos);
+
+ label = new Label (name);
+ label->setStyle (widgetStyle);
+ hbox->addChild (label);
+
+ OVGAttributesList::initWidgets (widgetStyle, hbox, showLarge);
+}
+
+int OVGAttribute::add (String *key, OVGAttribute *attribute)
+{
+ attributes->put (key, attribute);
+ return -1;
+}
+
+void OVGAttribute::show ()
+{
+ hbox->show ();
+}
+
+void OVGAttribute::hide ()
+{
+ hbox->hide ();
+}
+
+// ----------------------------------------------------------------------
+
+ObjViewGraph::GraphObject::GraphObject (ObjViewGraph *graph, const char *id)
+{
+ this->graph = graph;
+ this->id = strdup (id);
+
+ className = NULL;
+ node = NULL;
+ attributes = NULL;
+ messageStyle = graph->noBorderStyle;
+ messageStyle->ref ();
+}
+
+ObjViewGraph::GraphObject::~GraphObject ()
+{
+ // Simplified, when the whole graph is deleted.
+ if (node && !graph->inDestructor)
+ delete node;
+
+ free (id);
+ if (className)
+ free (className);
+ if (attributes)
+ delete attributes;
+ if (messageStyle)
+ messageStyle->unref ();
+}
+
+// ----------------------------------------------------------------------
+
+int ObjViewGraph::ColorComparator::specifity (const char *pattern)
+{
+ int s = 0;
+ for (const char *p = pattern; *p; p++) {
+ if (*p == '*')
+ s -= 100;
+ else if (*p == '?')
+ s += 1;
+ else
+ s += 100;
+ }
+ return s;
+}
+
+int ObjViewGraph::ColorComparator::compare (Object *o1, Object *o2)
+{
+ return specifity (((Color*)o2)->identifier)
+ - specifity (((Color*)o1)->identifier);
+}
+
+// ----------------------------------------------------------------------
+
+ObjViewGraph::Color::Color (const char *identifier, const char *color,
+ Layout *layout)
+{
+ this->identifier = strdup (identifier);
+
+ this->color = NULL;
+ if (*color == '#') {
+ char *end;
+ int c = (int)strtol (color + 1, &end, 16);
+ if (*end == 0) {
+ if (end - color == 7)
+ this->color = style::Color::create (layout, c);
+ else if (end - color == 4)
+ this->color =
+ style::Color::create (layout,
+ (c & 0xf00) >> 8 | (c && 0xf0) >> 4
+ | (c & 0xf));
+ this->color->ref ();
+ }
+ }
+
+ if (this->color == NULL)
+ fprintf (stderr, "WARNING: invalid color '%s'.\n", color);
+}
+
+ObjViewGraph::Color::~Color ()
+{
+ free (identifier);
+
+ if (this->color)
+ this->color->unref ();
+}
+
+// ----------------------------------------------------------------------
+
+ObjViewGraph::ObjViewGraph (ObjViewFilterTool *filterTool)
+{
+ inDestructor = false;
+
+ this->filterTool = filterTool;
+
+ commands = new Vector<OVGCommand> (4, true);
+ navigableCommands = new Vector<OVGCommand> (4, false);
+
+ objectsById = new HashTable<String, GraphObject> (true, false);
+ allObjects = new Vector<GraphObject> (1, true);
+ classColors = new Vector<Color> (1, true);
+ objectColors = new Vector<Color> (1, true);
+ enterCommands = new Stack<OVGEnterCommand> (false);
+ startCommands = new Stack<OVGIncIndentCommand> (false);
+
+ navigableCommandsPos = hiddenBefore = hiddenAfter = -1;
+ numVisibleCommands = 0;
+ objectContents = objectMessages = true;
+ codeViewer = strdup ("xterm -e 'vi +%n %p' &");
+
+ stacktraceWindows = new List <ObjViewStacktraceWindow> (true);
+ stacktraceListener = new ObjViewGraphListener (this);
+
+ nodeStyle = noBorderStyle = topBorderStyle = bottomBorderStyle =
+ leftBorderStyle = NULL;
+}
+
+ObjViewGraph::~ObjViewGraph ()
+{
+ inDestructor = true;
+
+ free (codeViewer);
+ delete commands;
+ delete navigableCommands;
+
+ delete objectsById;
+ delete allObjects;
+ delete classColors;
+ delete objectColors;
+ delete enterCommands;
+ delete startCommands;
+
+ delete stacktraceWindows;
+ delete stacktraceListener;
+
+ if (nodeStyle)
+ nodeStyle->unref ();
+ if (noBorderStyle)
+ noBorderStyle->unref ();
+ if (topBorderStyle)
+ topBorderStyle->unref ();
+ if (bottomBorderStyle)
+ bottomBorderStyle->unref ();
+ if (leftBorderStyle)
+ leftBorderStyle->unref ();
+}
+
+void ObjViewGraph::initStyles (const char *fontName, int fontSize, int fgColor,
+ int graphBgColor, int objBgColor,
+ int borderThickness, int graphMargin)
+{
+ StyleAttrs styleAttrs;
+ styleAttrs.initValues ();
+
+ FontAttrs fontAttrs;
+ fontAttrs.name = fontName;
+ fontAttrs.size = fontSize;
+ fontAttrs.weight = 400;
+ fontAttrs.style = FONT_STYLE_NORMAL;
+ fontAttrs.letterSpacing = 0;
+ fontAttrs.fontVariant = FONT_VARIANT_NORMAL;
+ styleAttrs.font = style::Font::create (layout, &fontAttrs);
+
+ styleAttrs.padding.setVal (graphMargin);
+ styleAttrs.color = style::Color::create (layout, fgColor);
+ styleAttrs.setBorderColor (styleAttrs.color);
+ styleAttrs.setBorderStyle (BORDER_SOLID);
+ styleAttrs.backgroundColor = style::Color::create (layout, graphBgColor);
+ Style *graphStyle = Style::create (&styleAttrs);
+ setStyle (graphStyle);
+
+ styleAttrs.padding.setVal (0);
+ styleAttrs.backgroundColor = style::Color::create (layout, objBgColor);
+ styleAttrs.borderWidth.setVal (1);
+ nodeStyle = Style::create (&styleAttrs);
+ setRefStyle (nodeStyle);
+
+ styleAttrs.backgroundColor = NULL;
+ styleAttrs.borderWidth.setVal (0);
+ noBorderStyle = Style::create (&styleAttrs);
+
+ styleAttrs.borderWidth.setVal (0);
+ styleAttrs.borderWidth.top = 1;
+ topBorderStyle = Style::create (&styleAttrs);
+
+ styleAttrs.borderWidth.setVal (0);
+ styleAttrs.borderWidth.bottom = 1;
+ bottomBorderStyle = Style::create (&styleAttrs);
+
+ styleAttrs.borderWidth.setVal (0);
+ styleAttrs.borderWidth.left = 1;
+ leftBorderStyle = Style::create (&styleAttrs);
+}
+
+ObjViewGraph::GraphObject *ObjViewGraph::ensureObject (const char *id)
+{
+ String key (id);
+ if (!objectsById->contains (&key)) {
+ GraphObject *obj = new GraphObject (this, id);
+
+ obj->node = new Toggle (objectContents);
+ applyClassOrObjectStyle (obj);
+ addNode (obj->node);
+
+ obj->id1 = new Label (id);
+ obj->id1->setStyle (noBorderStyle);
+ obj->node->setSmall (obj->id1);
+
+ VBox *large = new VBox (false);
+ large->setStyle (leftBorderStyle);
+ obj->node->setLarge (large);
+
+ obj->id2 = new Label (id);
+ obj->id2->setStyle (bottomBorderStyle);
+ large->addChild (obj->id2);
+
+ obj->attributes = new OVGTopAttributes ();
+ obj->attributes->initWidgets (noBorderStyle, large, true);
+
+ Toggle *mToggle = new Toggle (objectMessages);
+ mToggle->setStyle (topBorderStyle);
+ large->addChild (mToggle);
+
+ obj->messages = new VBox (false);
+ obj->messages->setStyle (noBorderStyle);
+ mToggle->setLarge (obj->messages);
+
+ objectsById->put (new String (id), obj);
+ allObjects->put (obj);
+ }
+
+ return objectsById->get (&key);
+}
+
+void ObjViewGraph::addMessage (const char *id, const char *message,
+ HBox **mainBox, Label **indexLabel,
+ Label **mainLabel)
+{
+ GraphObject *obj = ensureObject (id);
+
+ HBox *hbox = new HBox (false);
+ hbox->setStyle (noBorderStyle);
+ obj->messages->addChild (hbox);
+
+ Label *label1 = new Label ("???: ");
+ label1->setStyle (obj->messageStyle);
+ hbox->addChild (label1);
+
+ Label *label2 = new Label (message);
+ label2->setStyle (noBorderStyle);
+ hbox->addChild (label2);
+
+ if (mainBox)
+ *mainBox = hbox;
+ if (indexLabel)
+ *indexLabel = label1;
+ if (mainLabel)
+ *mainLabel = label2;
+}
+
+bool ObjViewGraph::incIndent (const char *id)
+{
+ GraphObject *obj = ensureObject (id);
+
+ Style *oldMessageStyle = obj->messageStyle;
+ StyleAttrs styleAttrs = *(obj->messageStyle);
+ styleAttrs.padding.left += 3 * obj->messageStyle->font->spaceWidth;
+ obj->messageStyle = Style::create (&styleAttrs);
+ oldMessageStyle->unref ();
+
+ return true; // just for symmetry with decIndent
+}
+
+bool ObjViewGraph::decIndent (const char *id)
+{
+ GraphObject *obj = ensureObject (id);
+
+ Style *oldMessageStyle = obj->messageStyle;
+ int indentWidth = 3 * obj->messageStyle->font->spaceWidth;
+ if (oldMessageStyle->padding.left >= indentWidth) {
+ StyleAttrs styleAttrs = *(obj->messageStyle);
+ styleAttrs.padding.left -= indentWidth;
+ obj->messageStyle = Style::create (&styleAttrs);
+ oldMessageStyle->unref ();
+ return true;
+ } else
+ return false;
+}
+
+OVGAttribute *ObjViewGraph::addAttribute (const char *id, const char *name,
+ const char *value, Label **smallLabel,
+ HBox **histBox, Label **indexLabel,
+ Label **histLabel)
+{
+ GraphObject *obj = ensureObject (id);
+
+ int numDots = 0;
+ for (const char *s = name; *s; s++)
+ if (*s == '.')
+ numDots++;
+
+ //printf ("'%s' contains %d dots\n", name, numDots);
+ char **parts = new char*[numDots + 2];
+
+ int i = 0;
+ const char *s = name;
+ for (const char *e = s; i < numDots + 1; e++)
+ if (*e == '.') {
+ parts[i] = strndup (s, e - s);
+ //printf ("%d of %d: '%s'\n", i, numDots + 1, parts[i]);
+ s = e + 1;
+ i++;
+ } else if (*e == 0) {
+ parts[i] = strdup (s);
+ //printf ("%d of %d (last): '%s'\n", i, numDots + 1, parts[i]);
+ s = e;
+ i++;
+ }
+
+ //printf ("finished\n");
+
+ parts[numDots + 1] = NULL;
+
+ OVGAttribute *attribute = addAttribute (obj->attributes, parts, value,
+ smallLabel, histBox, indexLabel,
+ histLabel);
+
+ for (char **p = parts; *p; p++)
+ free (*p);
+
+ delete[] parts;
+
+ return attribute;
+}
+
+// Returns "large" label.
+OVGAttribute *ObjViewGraph::addAttribute (OVGAttributesList *attributesList,
+ char **parts, const char *value,
+ Label **smallLabel, HBox **histBox,
+ Label **indexLabel, Label **histLabel)
+{
+ if (*parts) {
+ String key (*parts);
+ OVGAttribute *attribute = attributesList->get (&key);
+ if (attribute == NULL) {
+ String *str = new String (*parts);
+ attribute = new OVGAttribute (*parts, attributesList);
+ int newPos = attributesList->add (str, attribute);
+ attribute->initWidgets (noBorderStyle, attributesList->vbox, false,
+ newPos);
+ }
+
+ OVGAttribute *subAttribute = addAttribute (attribute, parts + 1, value,
+ smallLabel, histBox,
+ indexLabel, histLabel);
+ return subAttribute ? subAttribute : attribute;
+ } else {
+ HBox *hbox = new HBox (false);
+ hbox->setStyle (noBorderStyle);
+ attributesList->vbox->addChild (hbox);
+
+ Label *label1 = new Label ("???: ");
+ label1->setStyle (noBorderStyle);
+ hbox->addChild (label1);
+
+ Label *label2 = new Label (value);
+ label2->setStyle (noBorderStyle);
+ hbox->addChild (label2);
+
+ if (attributesList->toggle->getSmall () != NULL) {
+ assert (attributesList->toggle->getSmall()
+ ->instanceOf (Label::CLASS_ID));
+ ((Label*)attributesList->toggle->getSmall())->setText (value);
+ } else {
+ Label *cur = new Label (value);
+ cur->setStyle (noBorderStyle);
+ attributesList->toggle->setSmall (cur);
+ }
+
+ if (smallLabel)
+ *smallLabel = (Label*)attributesList ->toggle->getSmall ();
+ if (histBox)
+ *histBox = hbox;
+ if (indexLabel)
+ *indexLabel = label1;
+ if (histLabel)
+ *histLabel = label2;
+
+ // Here, no attribute is created; the caller must discard this
+ // return value.
+ return NULL;
+ }
+}
+
+void ObjViewGraph::setClassName (const char *id, const char *className)
+{
+ GraphObject *obj = ensureObject (id);
+
+ if (obj->className)
+ free (obj->className);
+ obj->className = strdup (className);
+
+ int bufLen = strlen (id) + 2 + strlen (className) + 1;
+ char *buf = new char[bufLen];
+ snprintf (buf, bufLen, "%s: %s", id, className);
+
+ obj->id1->setText (buf);
+ obj->id2->setText (buf);
+
+ delete[] buf;
+
+ applyClassOrObjectStyle (obj);
+}
+
+style::Color *ObjViewGraph::getObjectColor (GraphObject *obj)
+{
+ style::Color *objectColor = NULL;
+
+ // TODO Identities are currently not considered
+ for (int i = 0; objectColor == NULL && i < objectColors->size (); i++) {
+ Color *color = objectColors->get (i);
+ if (color->color && strcmp (color->identifier, obj->id) == 0)
+ objectColor = color->color;
+ }
+
+ if (obj->className) {
+ for (int i = 0; objectColor == NULL && i < classColors->size (); i++) {
+ Color *color = classColors->get (i);
+ if (color->color &&
+ fnmatch (color->identifier, obj->className, 0) == 0)
+ objectColor = color->color;
+ }
+ }
+
+ return objectColor;
+}
+
+void ObjViewGraph::applyClassOrObjectStyle (GraphObject *obj)
+{
+ style::Color *usedColor = getObjectColor (obj);
+
+ if (usedColor) {
+ // TODO Perhaps it is better to create styles initially (and
+ // change them when setStyle is called?). Should especially
+ // reduce memory usage.
+ StyleAttrs attrs = *nodeStyle;
+ attrs.backgroundColor = usedColor;
+ Style *newStyle = Style::create (&attrs);
+ obj->node->setStyle (newStyle);
+ newStyle->unref ();
+ } else
+ obj->node->setStyle (nodeStyle);
+}
+
+
+void ObjViewGraph::applyClassOrObjectStyles ()
+{
+ for (typed::Iterator<String> it = objectsById->iterator ();
+ it.hasNext (); ) {
+ String *key = it.getNext ();
+ GraphObject *obj = (GraphObject*) objectsById->get(key);
+ applyClassOrObjectStyle (obj);
+ }
+}
+
+int ObjViewGraph::getObjectColor (const char *id)
+{
+ String key (id);
+ GraphObject *obj = (GraphObject*) objectsById->get (&key);
+ if (obj) {
+ style::Color *objectColor = getObjectColor (obj);
+ return objectColor ?
+ objectColor->getColor () : nodeStyle->backgroundColor->getColor ();
+ } else
+ return nodeStyle->backgroundColor->getColor ();
+}
+
+void ObjViewGraph::addIdentity (const char *id1, const char *id2)
+{
+ // Done in ObjIdentController.
+}
+
+void ObjViewGraph::addAssoc (const char *id1, const char *id2)
+{
+ GraphObject *obj1 = ensureObject (id1);
+ GraphObject *obj2 = ensureObject (id2);
+ addEdge (obj1->node, obj2->node);
+}
+
+void ObjViewGraph::setClassColor (const char *klass, const char *color)
+{
+ ColorComparator cmp;
+ classColors->insertSorted (new Color (klass, color, layout), &cmp);
+ applyClassOrObjectStyles ();
+}
+
+void ObjViewGraph::setObjectColor (const char *id, const char *color)
+{
+ objectColors->put (new Color (id, color, layout));
+ applyClassOrObjectStyles ();
+}
+
+void ObjViewGraph::addCommand (OVGCommand *command, bool navigable)
+{
+ commands->put (command);
+ command->exec (this);
+
+ if (navigable) {
+ navigableCommands->put (command);
+ command->setNavigableCommandsIndex (this, navigableCommands->size () -1);
+
+ if (command->calcVisibility (this)) {
+ command->show (this);
+ command->setVisibleIndex (this, numVisibleCommands);
+ numVisibleCommands++;
+ } else
+ command->hide (this);
+ }
+}
+
+void ObjViewGraph::clearSelection ()
+{
+ if (navigableCommandsPos != -1)
+ navigableCommands->get(navigableCommandsPos)->unselect (this);
+}
+
+void ObjViewGraph::unclearSelection ()
+{
+ if (navigableCommandsPos != - 1) {
+ navigableCommands->get(navigableCommandsPos)->select (this);
+ navigableCommands->get(navigableCommandsPos)->scrollTo (this);
+ }
+}
+
+int ObjViewGraph::firstCommand ()
+{
+ if (hiddenBefore != -1)
+ return hiddenBefore;
+ else
+ return navigableCommands->size () > 0 ? 0 : -1;
+}
+
+int ObjViewGraph::lastCommand ()
+{
+ if (hiddenAfter != -1)
+ return hiddenAfter;
+ else
+ return navigableCommands->size () - 1; // may be -1
+}
+
+void ObjViewGraph::previousCommand ()
+{
+ clearSelection ();
+
+ if (numVisibleCommands == 0)
+ // No visible command;
+ navigableCommandsPos = -1;
+ else
+ do {
+ if (navigableCommandsPos == -1)
+ navigableCommandsPos = lastCommand ();
+ else {
+ navigableCommandsPos--;
+ if (navigableCommandsPos < firstCommand ())
+ navigableCommandsPos = lastCommand ();
+ }
+ } while (!navigableCommands->get(navigableCommandsPos)->isVisible (this));
+
+ unclearSelection ();
+}
+
+void ObjViewGraph::nextCommand ()
+{
+ clearSelection ();
+
+ if (numVisibleCommands == 0)
+ // No visible command;
+ navigableCommandsPos = -1;
+ else {
+ do {
+ if (navigableCommandsPos == -1)
+ navigableCommandsPos = firstCommand ();
+ else {
+ navigableCommandsPos++;
+ if (navigableCommandsPos > lastCommand ())
+ navigableCommandsPos = firstCommand ();
+ }
+ } while (!navigableCommands->get(navigableCommandsPos)->isVisible (this));
+ }
+
+ unclearSelection ();
+}
+
+void ObjViewGraph::viewCodeOfCommand ()
+{
+ if (navigableCommandsPos != -1) {
+ OVGCommand *command = navigableCommands->get (navigableCommandsPos);
+
+ char lineNoBuf[32];
+ char partBuf[32] = { 0, 0 };
+ StringBuffer sb;
+
+ snprintf (lineNoBuf, 32, "+%d", command->getLineNo ());
+
+ for (char *s = codeViewer; *s; s++) {
+ if (*s == '%' && (s[1] == 'p' || s[1] == 'n')) {
+ s++;
+ switch (*s) {
+ case 'p':
+ sb.append (command->getFileName ());
+ break;
+
+ case 'n':
+ sb.append (lineNoBuf);
+ break;
+ }
+ } else {
+ *partBuf = *s;
+ sb.append (partBuf);
+ }
+ }
+
+ system (sb.getChars());
+ }
+}
+
+void ObjViewGraph::showStackTraceOfCommand ()
+{
+ if (navigableCommandsPos != -1) {
+ OVGCommand *command = navigableCommands->get (navigableCommandsPos);
+ ObjViewStacktraceWindow *stWin =
+ new ObjViewStacktraceWindow (command->getFunction (),
+ stacktraceListener);
+ stacktraceWindows->append (stWin);
+ stWin->show ();
+ stWin->update ();
+ }
+}
+
+void ObjViewGraph::switchBetweenRelatedCommands ()
+{
+ if (navigableCommandsPos != -1) {
+ OVGCommand *command = navigableCommands->get (navigableCommandsPos);
+ OVGCommand *relatedCommand = command->getRelatedCommand ();
+ if (relatedCommand && relatedCommand->isVisible (this)) {
+ clearSelection ();
+ navigableCommandsPos =
+ relatedCommand->getNavigableCommandsIndex (this);
+ unclearSelection ();
+ }
+ }
+}
+
+void ObjViewGraph::setCommand (int index)
+{
+ clearSelection ();
+ navigableCommandsPos = index;
+ unclearSelection ();
+}
+
+void ObjViewGraph::hideBeforeCommand ()
+{
+ // Note: The selected command cannot be hidden, so there are never
+ // elements to show again.
+
+ if (navigableCommandsPos != -1) {
+ hiddenBefore = navigableCommandsPos;
+ for (int i = 0; i < hiddenBefore; i++)
+ navigableCommands->get(i)->hide (this);
+ }
+
+ recalculateCommandsVisibility (); // Could be faster
+}
+
+void ObjViewGraph::hideAfterCommand ()
+{
+ // See also note in hideBeforeCommand().
+
+ if (navigableCommandsPos != -1) {
+ hiddenAfter = navigableCommandsPos;
+ for (int i = hiddenAfter + 1; i < navigableCommands->size (); i++)
+ navigableCommands->get(i)->hide (this);
+ }
+
+ recalculateCommandsVisibility (); // Could be faster
+}
+
+void ObjViewGraph::hideAllCommands ()
+{
+ navigableCommandsPos = -1;
+ hiddenBefore = navigableCommands->size ();
+ for (int i = 0; i < navigableCommands->size (); i++)
+ navigableCommands->get(i)->hide (this);
+
+ recalculateCommandsVisibility (); // Necessary?
+}
+
+void ObjViewGraph::showBeforeCommand ()
+{
+ if (hiddenBefore != -1) {
+ hiddenBefore = -1;
+ recalculateCommandsVisibility (); // Could be faster
+ }
+}
+
+void ObjViewGraph::showAfterCommand ()
+{
+ if (hiddenAfter != -1) {
+ hiddenAfter = -1;
+ recalculateCommandsVisibility (); // Could be faster
+ }
+}
+
+void ObjViewGraph::showAllCommands ()
+{
+ if (hiddenBefore != -1 || hiddenAfter != -1) {
+ hiddenBefore = hiddenAfter = -1;
+ recalculateCommandsVisibility (); // Could be faster
+ }
+}
+
+void ObjViewGraph::setCodeViewer (const char *codeViewer)
+{
+ free (this->codeViewer);
+ this->codeViewer = strdup (codeViewer);
+}
+
+void ObjViewGraph::recalculateCommandsVisibility ()
+{
+ numVisibleCommands = 0;
+ for (int i = max (firstCommand (), 0); i <= lastCommand (); i++) {
+ OVGCommand *command = navigableCommands->get (i);
+
+ if (command->calcVisibility (this)) {
+ command->show (this);
+ command->setVisibleIndex (this, numVisibleCommands);
+ numVisibleCommands++;
+ } else
+ command->hide (this);
+ }
+
+ if (navigableCommandsPos != -1) {
+ if (!navigableCommands->get(navigableCommandsPos)->isVisible (this))
+ // Selected command has become invisible. Select next one. (May
+ // also be the first one, if, e. g., the selected one was the last
+ // one. Could test this and instead select the last visible
+ // *before*.)
+ nextCommand ();
+ else
+ // May have become out of view.
+ navigableCommands->get(navigableCommandsPos)->scrollTo (this);
+ }
+
+ // Update stacktrace windows (hidden commands should not be selectable).
+ for (lout::container::typed::Iterator <ObjViewStacktraceWindow> it =
+ stacktraceWindows->iterator (); it.hasNext (); ) {
+ ObjViewStacktraceWindow *stWin = it.getNext ();
+ stWin->update ();
+ }
+}
+
+} // namespace objects
+
+} // namespace rtfl
diff --git a/objects/objview_graph.hh b/objects/objview_graph.hh
new file mode 100644
index 0000000..9619f7e
--- /dev/null
+++ b/objects/objview_graph.hh
@@ -0,0 +1,305 @@
+#ifndef __OBJECTS_OBJVIEW_GRAPH_HH__
+#define __OBJECTS_OBJVIEW_GRAPH_HH__
+
+#include "objview_stacktrace.hh"
+#include "objview_commands.hh"
+#include "dwr/graph.hh"
+#include "dwr/graph2.hh"
+#include "dwr/toggle.hh"
+#include "dwr/vbox.hh"
+#include "dwr/hbox.hh"
+#include "dwr/label.hh"
+#include "common/tools.hh"
+
+namespace rtfl {
+
+namespace objects {
+
+enum OVGCommandType {
+ OVG_COMMAND_CREATE,
+ OVG_COMMAND_INDENT,
+ OVG_COMMAND_MESSAGE,
+ OVG_COMMAND_MARK,
+ OVG_COMMAND_FUNCTION,
+ OVG_COMMAND_ASSOC,
+ OVG_COMMAND_ADD_ATTR,
+ OVG_COMMAND_DELETE
+};
+
+class ObjViewGraphListener: public ObjViewListener
+{
+private:
+ ObjViewGraph *graph;
+
+public:
+ ObjViewGraphListener (ObjViewGraph *graph) { this->graph = graph; }
+
+ void close (ObjViewStacktraceWindow *window);
+};
+
+
+class ObjViewFilterTool
+{
+public:
+ virtual void addAspect (const char *aspect) = 0;
+ virtual void addPriority (int priority) = 0;
+ virtual bool isAspectSelected (const char *aspect) = 0;
+ virtual bool isPrioritySelected (int priority) = 0;
+ virtual bool isTypeSelected (OVGCommandType type) = 0;
+ virtual void addMark (OVGAddMarkCommand *markCommand) = 0;
+};
+
+class OVGAttribute;
+
+class OVGAttributesList: public lout::object::Object
+{
+private:
+ OVGAttributesList *parent;
+ int childNoCount, numChildrenShown, childNo;
+ lout::misc::BitSet *childrenShown;
+ bool shown;
+
+ void checkVisibility ();
+
+protected:
+ lout::container::typed::HashTable<lout::object::String,
+ OVGAttribute> *attributes;
+
+ virtual void show () = 0;
+ virtual void hide () = 0;
+
+public:
+ dw::VBox *vbox;
+ dw::Toggle *toggle;
+
+ OVGAttributesList (OVGAttributesList *parent);
+ ~OVGAttributesList ();
+
+ inline OVGAttribute *get (lout::object::String *key)
+ { return attributes->get (key); }
+ virtual int add (lout::object::String *key, OVGAttribute *attribute) = 0;
+
+ void initWidgets (::dw::core::style::Style *widgetStyle, dw::Box *parent,
+ bool showLarge);
+
+ int registerChild ();
+ void unregisterChild (int childNo);
+ void childShown (int childNo);
+ void childHidden (int childNo);
+};
+
+class OVGTopAttributes: public OVGAttributesList
+{
+protected:
+ lout::container::typed::Vector<lout::object::String> *sortedList;
+
+ void show ();
+ void hide ();
+
+public:
+ OVGTopAttributes ();
+ ~OVGTopAttributes ();
+
+ int add (lout::object::String *key, OVGAttribute *attribute);
+};
+
+// Hint: the OVGAttributesList'ness refers to the children.
+class OVGAttribute: public OVGAttributesList
+{
+protected:
+ void show ();
+ void hide ();
+
+public:
+ dw::HBox *hbox;
+ dw::Label *label;
+ char *name;
+
+ OVGAttribute (const char *name, OVGAttributesList *parent);
+ ~OVGAttribute ();
+
+ void initWidgets (::dw::core::style::Style *widgetStyle,
+ dw::Box *parent, bool showLarge, int newPos);
+
+ int add (lout::object::String *key, OVGAttribute *attribute);
+};
+
+class ObjViewGraph: public
+#if USE_GRAPH2
+ dw::Graph2
+#else
+ dw::Graph
+#endif
+{
+ friend class OVGCommonCommand;
+ friend class OVGIncIndentCommand;
+ friend class OVGDecIndentCommand;
+ friend class OVGEnterCommand;
+ friend class OVGLeaveCommand;
+ friend class OVGAddMessageCommand;
+ friend class OVGAddMarkCommand;
+ friend class OVGCreateCommand;
+ friend class OVGAddAssocCommand;
+ friend class OVGAddAttrCommand;
+ friend class OVGDeleteCommand;
+ friend class ObjViewGraphListener;
+
+private:
+ class CreateRefCommand;
+
+ class GraphObject: public lout::object::Object
+ {
+ friend class CreateRefCommand;
+ friend class ObjViewGraph;
+
+ private:
+ ObjViewGraph *graph;
+
+ public:
+ char *id, *className;
+ ::dw::core::style::Style *messageStyle;
+ dw::Toggle *node;
+ dw::Label *id1, *id2;
+ OVGTopAttributes *attributes;
+ dw::VBox *messages;
+
+ GraphObject (ObjViewGraph *graph, const char *id);
+ ~GraphObject ();
+
+ };
+
+ // Inernally added for the first occurence of an identity.
+ class CreateRefCommand: public OVGCommonCommand
+ {
+ protected:
+ void doExec ();
+ void doUndo ();
+
+ public:
+ CreateRefCommand (ObjViewGraph *graph, const char *id,
+ GraphObject *graphObject);
+ };
+
+ class Color: public lout::object::Object
+ {
+ public:
+ char *identifier;
+ ::dw::core::style::Color *color;
+
+ Color (const char *classPattern, const char *color,
+ ::dw::core::Layout *layout);
+ ~Color ();
+ };
+
+ class ColorComparator: public lout::object::Comparator
+ {
+ private:
+ int specifity (const char *pattern);
+
+ public:
+ int compare(Object *o1, Object *o2);
+ };
+
+ ObjViewFilterTool *filterTool;
+
+ lout::container::typed::Vector<OVGCommand> *commands;
+ lout::container::typed::Vector<OVGCommand> *navigableCommands;
+ lout::container::typed::HashTable<lout::object::String,
+ GraphObject> *objectsById;
+ lout::container::typed::Vector<GraphObject> *allObjects;
+ lout::container::typed::Vector<Color> *classColors;
+ lout::container::typed::Vector<Color> *objectColors;
+
+ lout::container::typed::Stack<OVGEnterCommand> *enterCommands;
+ lout::container::typed::Stack<OVGIncIndentCommand> *startCommands;
+
+ bool objectContents, objectMessages;
+ char *codeViewer;
+ int navigableCommandsPos, hiddenBefore, hiddenAfter, numVisibleCommands;
+
+ ::dw::core::style::Style *nodeStyle, *noBorderStyle, *topBorderStyle,
+ *bottomBorderStyle, *leftBorderStyle;
+ bool inDestructor;
+
+ lout::container::typed::List <ObjViewStacktraceWindow> *stacktraceWindows;
+ ObjViewGraphListener *stacktraceListener;
+
+ GraphObject *ensureObject (const char *id);
+ OVGAttribute *addAttribute (OVGAttributesList *attributesList, char **parts,
+ const char *value, dw::Label **smallLabel,
+ dw::HBox **histBox, dw::Label **indexLabel,
+ dw::Label **histLabel);
+
+ ::dw::core::style::Color *getObjectColor (GraphObject *obj);
+ void applyClassOrObjectStyle (GraphObject *obj);
+ void applyClassOrObjectStyles ();
+
+ void addMessage (const char *id, const char *message, dw::HBox **mainBox,
+ dw::Label **indexLabel, dw::Label **mainLabel);
+ bool incIndent (const char *id);
+ bool decIndent (const char *id);
+ OVGAttribute *addAttribute (const char *id, const char *name,
+ const char *value, dw::Label **smallLabel,
+ dw::HBox **histBox, dw::Label **indexLabel,
+ dw::Label **histLabel);
+ void setClassName (const char *id, const char *className);
+ void addAssoc (const char *id1, const char *id2);
+
+ void clearSelection ();
+ void unclearSelection ();
+ int firstCommand ();
+ int lastCommand ();
+
+public:
+ ObjViewGraph (ObjViewFilterTool *objectFilterTool);
+ ~ObjViewGraph ();
+ void initStyles (const char *fontName, int fontSize, int fgColor,
+ int graphBgColor, int objBgColor, int borderThickness,
+ int grraphMargin);
+
+ void addCommand (OVGCommand *command, bool navigable);
+ void addIdentity (const char *id1, const char *id2);
+ void setClassColor (const char *klass, const char *color);
+ void setObjectColor (const char *id, const char *color);
+
+ int getObjectColor (const char *id);
+
+ inline void pushEnterCommand (OVGEnterCommand *enterCommand)
+ { enterCommands->push (enterCommand); }
+ void popEnterCommand () { enterCommands->pop (); }
+ OVGEnterCommand *getLastEnterCommand () { return enterCommands->getTop (); }
+
+ inline void pushStartCommand (OVGIncIndentCommand *startCommand)
+ { startCommands->push (startCommand); }
+ void popStartCommand () { startCommands->pop (); }
+ OVGIncIndentCommand *getLastStartCommand ()
+ { return startCommands->getTop (); }
+
+ inline void addCommandMark (OVGAddMarkCommand *markCommand)
+ { filterTool->addMark (markCommand); }
+
+ void previousCommand ();
+ void nextCommand ();
+ void viewCodeOfCommand ();
+ void showStackTraceOfCommand ();
+ void switchBetweenRelatedCommands ();
+ void setCommand (int index);
+ void hideBeforeCommand ();
+ void hideAfterCommand ();
+ void hideAllCommands ();
+ void showBeforeCommand ();
+ void showAfterCommand ();
+ void showAllCommands ();
+
+ inline void showObjectContents (bool val) { objectContents = val; }
+ inline void showObjectMessages (bool val) { objectMessages = val; }
+ void setCodeViewer (const char *codeViewer);
+
+ void recalculateCommandsVisibility ();
+};
+
+} // namespace objects
+
+} // namespace rtfl
+
+#endif // __OBJECTS_OBJVIEW_GRAPH_HH__
diff --git a/objects/objview_stacktrace.cc b/objects/objview_stacktrace.cc
new file mode 100644
index 0000000..e5c8dc8
--- /dev/null
+++ b/objects/objview_stacktrace.cc
@@ -0,0 +1,127 @@
+/*
+ * RTFL
+ *
+ * Copyright 2014, 2015 Sebastian Geerken <sgeerken@dillo.org>
+ *
+ * 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; with the following exception:
+ *
+ * The copyright holders of RTFL give you permission to link this file
+ * statically or dynamically against all versions of the graphviz
+ * library, which are published by AT&T Corp. under one of the following
+ * licenses:
+ *
+ * - Common Public License version 1.0 as published by International
+ * Business Machines Corporation (IBM), or
+ * - Eclipse Public License version 1.0 as published by the Eclipse
+ * Foundation.
+ *
+ * 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/>.
+ */
+
+#include "objview_stacktrace.hh"
+
+#include "config.h"
+
+#include <FL/Fl_Button.H>
+#include <FL/Fl_Return_Button.H>
+
+namespace rtfl {
+
+namespace objects {
+
+ObjViewStacktraceWindow::ObjViewStacktraceWindow (ObjViewFunction *topFunction,
+ ObjViewListener *listener) :
+ Fl_Window (WIDTH, HEIGHT, "RTFL: Stack trace")
+{
+ callback(windowCallback, this);
+
+ browser =
+ new Fl_Hold_Browser (SPACE, SPACE, WIDTH - 2 * SPACE,
+ HEIGHT - 3 * SPACE - BUTTON_HEIGHT, NULL);
+ Fl_Button *jumpTo =
+ new Fl_Button(WIDTH - 2 * BUTTON_WIDTH - 2 * SPACE,
+ HEIGHT - BUTTON_HEIGHT - SPACE, BUTTON_WIDTH,
+ BUTTON_HEIGHT, "Jump to");
+ jumpTo->callback (ObjViewStacktraceWindow::jumpTo, this);
+ Fl_Return_Button *close =
+ new Fl_Return_Button(WIDTH - BUTTON_WIDTH - SPACE,
+ HEIGHT - BUTTON_HEIGHT - SPACE, BUTTON_WIDTH,
+ BUTTON_HEIGHT, "Close");
+ close->callback (ObjViewStacktraceWindow::close, this);
+
+ resizable (browser);
+
+ this->topFunction = topFunction;
+ this->listener = listener;
+}
+
+ObjViewStacktraceWindow::~ObjViewStacktraceWindow ()
+{
+}
+
+void ObjViewStacktraceWindow::update ()
+{
+ browser->clear ();
+
+ for (ObjViewFunction *fun = topFunction; fun;
+ fun = fun->getParent ()) {
+ char *name = fun->createName ();
+
+ char name2[1024];
+ name2[0] = 0;
+
+ if (!fun->isSelectable ()) {
+ strcpy (name2, "@i");
+ }
+
+ sprintf (name2 + strlen (name2), "@B%ld@.",
+ ((long)fun->getColor ()) << 8);
+
+ char *s = name2 + strlen (name2);
+ for (int i = 0; name[i]; i++) {
+ if (name[i] == '@')
+ *(s++) = '@';
+ *(s++) = name[i];
+ }
+ *s = 0;
+
+ browser->add (name2, NULL);
+
+ fun->freeName (name);
+ }
+}
+
+void ObjViewStacktraceWindow::windowCallback (Fl_Widget *widget, void *data)
+{
+ close (widget, data);
+}
+
+void ObjViewStacktraceWindow::jumpTo (Fl_Widget *widget, void *data)
+{
+ ObjViewStacktraceWindow *win = (ObjViewStacktraceWindow*)data;
+
+ ObjViewFunction *fun = win->topFunction;
+ for (int i = 1; fun; fun = fun->getParent (), i++) {
+ if (win->browser->selected (i) && fun->isSelectable ())
+ fun->select ();
+ }
+}
+
+void ObjViewStacktraceWindow::close (Fl_Widget *widget, void *data)
+{
+ ObjViewStacktraceWindow *win = (ObjViewStacktraceWindow*)data;
+ win->listener->close (win);
+}
+
+} // namespace objects
+
+} // namespace rtfl
diff --git a/objects/objview_stacktrace.hh b/objects/objview_stacktrace.hh
new file mode 100644
index 0000000..5ea8d7e
--- /dev/null
+++ b/objects/objview_stacktrace.hh
@@ -0,0 +1,60 @@
+#ifndef __OBJECTS_OBJVIEW_STRACKTRACE_HH__
+#define __OBJECTS_OBJVIEW_STRACKTRACE_HH__
+
+#include <FL/Fl_Window.H>
+#include <FL/Fl_Hold_Browser.H>
+
+#include "lout/object.hh"
+
+namespace rtfl {
+
+namespace objects {
+
+class ObjViewFunction
+{
+public:
+ virtual char *createName () = 0;
+ virtual void freeName (char *name) = 0;
+ virtual int getColor () = 0; // as 0xRRGGBB
+ virtual ObjViewFunction *getParent () = 0;
+ virtual bool isSelectable () = 0;
+ virtual void select () = 0;
+};
+
+class ObjViewStacktraceWindow;
+
+// Somewhat simpler than using signals
+class ObjViewListener
+{
+public:
+ virtual ~ObjViewListener () { }
+ virtual void close (ObjViewStacktraceWindow *window) = 0;
+};
+
+class ObjViewStacktraceWindow: public Fl_Window, public lout::object::Object
+{
+private:
+ enum { WIDTH = 450, HEIGHT = 300, BUTTON_WIDTH = 80, BUTTON_HEIGHT = 25,
+ SPACE = 10 };
+
+ Fl_Hold_Browser *browser;
+ ObjViewFunction *topFunction;
+ ObjViewListener *listener;
+
+ static void windowCallback (Fl_Widget *widget, void *data);
+ static void jumpTo (Fl_Widget *widget, void *data);
+ static void close (Fl_Widget *widget, void *data);
+
+public:
+ ObjViewStacktraceWindow (ObjViewFunction *topFunction,
+ ObjViewListener *listener);
+ ~ObjViewStacktraceWindow ();
+
+ void update ();
+};
+
+} // namespace objects
+
+} // namespace rtfl
+
+#endif // __OBJECTS_OBJVIEW_STRACKTRACE_HH__
diff --git a/objects/objview_window.cc b/objects/objview_window.cc
new file mode 100644
index 0000000..211076d
--- /dev/null
+++ b/objects/objview_window.cc
@@ -0,0 +1,707 @@
+/*
+ * RTFL
+ *
+ * Copyright 2013-2015 Sebastian Geerken <sgeerken@dillo.org>
+ *
+ * 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; with the following exception:
+ *
+ * The copyright holders of RTFL give you permission to link this file
+ * statically or dynamically against all versions of the graphviz
+ * library, which are published by AT&T Corp. under one of the following
+ * licenses:
+ *
+ * - Common Public License version 1.0 as published by International
+ * Business Machines Corporation (IBM), or
+ * - Eclipse Public License version 1.0 as published by the Eclipse
+ * Foundation.
+ *
+ * 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/>.
+ */
+
+#include <FL/Fl.H>
+#include <limits.h>
+
+#include "objview_window.hh"
+
+#include "dw/core.hh"
+#include "dw/fltkcore.hh"
+#include "dw/fltkviewport.hh"
+
+#include "dwr/graph.hh"
+
+using namespace dw;
+using namespace dw::core;
+using namespace dw::core::style;
+using namespace dw::fltk;
+using namespace lout::object;
+using namespace lout::container::typed;
+using namespace lout::misc;
+
+namespace rtfl {
+
+namespace objects {
+
+ObjViewWindow::Aspect::Aspect (ObjViewWindow *window, const char *name,
+ bool set)
+{
+ this->window = window;
+ this->name = strdup (name);
+ this->set = set;
+}
+
+
+ObjViewWindow::Aspect::~Aspect ()
+{
+ free (name);
+}
+
+
+bool ObjViewWindow::Aspect::equals(Object *other)
+{
+ Aspect *otherAspect = (Aspect*)other;
+ return strcmp (name, otherAspect->name) == 0 &&
+ ((set && otherAspect->set) || (!set && !otherAspect->set));
+}
+
+
+int ObjViewWindow::Aspect::compareTo(Comparable *other)
+{
+ Aspect *otherAspect = (Aspect*)other;
+ return strcmp (name, otherAspect->name);
+}
+
+
+// ----------------------------------------------------------------------
+
+
+ObjViewWindow::Priority::Priority (ObjViewWindow *window, int value)
+{
+ this->window = window;
+ this->value = value;
+}
+
+
+bool ObjViewWindow::Priority::equals(Object *other)
+{
+ Priority *otherPriority = (Priority*)other;
+ return value == otherPriority->value;
+}
+
+
+int ObjViewWindow::Priority::compareTo(Comparable *other)
+{
+ Priority *otherPriority = (Priority*)other;
+ return value - otherPriority->value;
+}
+
+
+// ----------------------------------------------------------------------
+
+
+ObjViewWindow::ObjViewWindow (int width, int height, const char *title):
+ Fl_Window (width, height, title)
+{
+ shown = false;
+
+ aspects = new HashTable<String, Aspect> (true, true);
+ aspectsMenuPositions = new Vector<Integer> (1, true);;
+ aspectsInitiallySet = true;
+
+ priorities = new HashTable<Integer, Priority> (true, true);
+ prioritiesMenuPositions = new Vector<Integer> (1, true);;
+ selectedPriority = INT_MAX;
+
+ // Special priority "no priority" (INT_MAX):
+ Priority *noLimitsPriority = new Priority (this, INT_MAX);
+ priorities->put (new Integer (INT_MAX), noLimitsPriority);
+
+ aboutWindow = NULL;
+
+ int menuHeight = 24;
+
+ FltkPlatform *platform = new FltkPlatform ();
+ layout = new Layout (platform);
+
+ callback(windowCallback, NULL);
+ box(FL_NO_BOX);
+
+ menu = new Fl_Menu_Bar(0, 0, width, menuHeight);
+
+ FltkViewport *viewport =
+ new FltkViewport (0, menuHeight, width, height - menuHeight);
+ layout->attachView (viewport);
+
+ graph = new ObjViewGraph (this);
+ layout->setWidget (graph);
+ graph->initStyles ("DejaVu Sans", 12, 0x000000, 0xffffff, 0xffffd0, 1, 10);
+
+ Fl_Menu_Item menuItems[] = {
+ { "&File", 0, 0, 0, FL_SUBMENU, 0, 0, 0, 0 },
+ { "Quit", FL_COMMAND + 'q', quit, this, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+
+ { "&Command", 0, 0, 0, FL_SUBMENU, 0, 0, 0, 0 },
+ { "&Previous", FL_COMMAND + 'p', previous, this, 0, 0, 0, 0, 0 },
+ { "&Next", FL_COMMAND + 'n', next, this, 0, 0, 0, 0, 0 },
+ { "View &Code", FL_COMMAND + 'c', viewCode, this, FL_MENU_DIVIDER,
+ 0, 0, 0, 0 },
+ { "Hide &before", FL_COMMAND + 'b', hideBefore, this, 0, 0, 0, 0, 0 },
+ { "Hide &after", FL_COMMAND + 'a', hideAfter, this, 0, 0, 0, 0, 0 },
+ { "&Hide all", FL_COMMAND + 'h', hideAll, this, FL_MENU_DIVIDER,
+ 0, 0, 0, 0 },
+ { "Show b&efore", FL_COMMAND + 'e', showBefore, this, 0, 0, 0, 0, 0 },
+ { "Show a&fter", FL_COMMAND + 'f', showAfter, this, 0, 0, 0, 0, 0 },
+ { "&Show all", FL_COMMAND + 's', showAll, this, FL_MENU_DIVIDER,
+ 0, 0, 0, 0 },
+ { "Show stack trace", FL_COMMAND + 't', showStackTrace, this, 0, 0, 0, 0,
+ 0 },
+ { "Switch between related", FL_COMMAND + 'r', switchBetweenRelated, this,
+ FL_MENU_DIVIDER, 0, 0, 0, 0 },
+ { "&Creations", 0, toggleCommandTypeVisibility, this, FL_MENU_TOGGLE,
+ 0, 0, 0, 0 },
+ { "&Indentations", 0, toggleCommandTypeVisibility, this, FL_MENU_TOGGLE,
+ 0, 0, 0, 0 },
+ { "&Messages", 0, toggleCommandTypeVisibility, this,
+ FL_MENU_TOGGLE | FL_MENU_VALUE, 0, 0, 0, 0 },
+ { "M&arks", 0, toggleCommandTypeVisibility, this,
+ FL_MENU_TOGGLE | FL_MENU_VALUE, 0, 0, 0, 0 },
+ { "&Functions", 0, toggleCommandTypeVisibility, this,
+ FL_MENU_TOGGLE | FL_MENU_VALUE, 0, 0, 0, 0 },
+ { "A&ssociations", 0, toggleCommandTypeVisibility, this,
+ FL_MENU_TOGGLE | FL_MENU_VALUE, 0, 0, 0, 0 },
+ { "A&ttributes", 0, toggleCommandTypeVisibility, this,
+ FL_MENU_TOGGLE | FL_MENU_VALUE, 0, 0, 0, 0 },
+ { "&Deletions", 0, toggleCommandTypeVisibility, this,
+ FL_MENU_TOGGLE | FL_MENU_VALUE, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+
+ { "&Aspects", 0, 0, 0, FL_SUBMENU, 0, 0, 0, 0 },
+ { "&Show all", 0, showAllAspects, this, FL_MENU_TOGGLE | FL_MENU_VALUE,
+ 0, 0, 0, 0 },
+ { "&Hide all", 0, hideAllAspects, this, FL_MENU_TOGGLE | FL_MENU_DIVIDER,
+ 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+
+ { "&Priorities", 0, 0, 0, FL_SUBMENU, 0, 0, 0, 0 },
+ { "&No limit", 0, setPriority, noLimitsPriority,
+ FL_MENU_RADIO | FL_MENU_VALUE /*| FL_MENU_DIVIDER*/, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+
+ { "&Marks", 0, 0, 0, FL_SUBMENU, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+
+ { "&Help", 0, 0, 0, FL_SUBMENU, 0, 0, 0, 0 },
+ { "&About RTFL", 0, about, this, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0 }
+ };
+ menu->copy(menuItems);
+
+ noLimitsPriority->menuItem =
+ (Fl_Menu_Item*)(menu->find_item ("&Priorities/&No limit"));
+
+ resizable(viewport);
+}
+
+ObjViewWindow::~ObjViewWindow ()
+{
+ delete aspects;
+ delete aspectsMenuPositions;
+ delete priorities;
+ delete prioritiesMenuPositions;
+ if (aboutWindow)
+ delete aboutWindow;
+ delete layout;
+}
+
+
+void ObjViewWindow::show ()
+{
+ shown = true;
+
+ Integer key (selectedPriority);
+ Priority *priorityEntry = priorities->get (&key);
+ priorityEntry->menuItem->activate ();
+
+ Fl_Window::show ();
+}
+
+void ObjViewWindow::addAspect (const char *aspect)
+{
+ addAspect (aspect, aspectsInitiallySet);
+}
+
+void ObjViewWindow::setAspectsInitiallySet (bool val)
+{
+ aspectsInitiallySet = val;
+ showOrHideAllAspects (aspectsInitiallySet);
+
+ if (aspectsInitiallySet) {
+ getShowAllAspectsMenuItem()->set ();
+ getHideAllAspectsMenuItem()->clear ();
+ } else {
+ getShowAllAspectsMenuItem()->clear ();
+ getHideAllAspectsMenuItem()->set ();
+ }
+}
+
+void ObjViewWindow::addPriority (int priority)
+{
+ addPriority (priority, false);
+}
+
+
+bool ObjViewWindow::isAspectSelected (const char *aspect)
+{
+ String key (aspect);
+ Aspect *aspectEntry = aspects->get (&key);
+ assert (aspectEntry != NULL); // Should have been added before.
+ return aspectEntry->set;
+}
+
+
+bool ObjViewWindow::isPrioritySelected (int priority)
+{
+ return priority <= selectedPriority;
+}
+
+
+bool ObjViewWindow::isTypeSelected (OVGCommandType type)
+{
+ switch (type) {
+ case OVG_COMMAND_CREATE:
+ return getCreateMenuItem()->value ();
+
+ case OVG_COMMAND_INDENT:
+ return getIndentMenuItem()->value ();
+
+ case OVG_COMMAND_MESSAGE:
+ return getMessageMenuItem()->value ();
+
+ case OVG_COMMAND_MARK:
+ return getMarkMenuItem()->value ();
+
+ case OVG_COMMAND_FUNCTION:
+ return getFunctionMenuItem()->value ();
+
+ case OVG_COMMAND_ASSOC:
+ return getAssocMenuItem()->value ();
+
+ case OVG_COMMAND_ADD_ATTR:
+ return getAddAttrMenuItem()->value ();
+
+ case OVG_COMMAND_DELETE:
+ return getDeleteMenuItem()->value ();
+
+ }
+
+ assertNotReached ();
+ return false;
+}
+
+void ObjViewWindow::addMark (OVGAddMarkCommand *markCommand)
+{
+ int pathLen = 6 + strlen (markCommand->getMark ()) + 1;
+ char *path = new char[pathLen];
+ snprintf (path, pathLen, "Marks/%s", markCommand->getMark ());
+ int menuPos = menu->add (path, 0, NULL, NULL, 0);
+ delete[] path;
+ Fl_Menu_Item *menuItem = (Fl_Menu_Item*)(menu->menu() + menuPos);
+ menuItem->callback (jumpToMark, markCommand);
+}
+
+
+void ObjViewWindow::addAspect (const char *aspect, bool val)
+{
+ String key (aspect);
+ Aspect *aspectEntry = aspects->get (&key);
+ if (aspectEntry == NULL) {
+ aspectEntry = new Aspect (this, aspect, val);
+ aspects->put (new String (aspect), aspectEntry);
+
+#if 1
+ int pathLen = 8 + strlen (aspect) + 1;
+ char *path = new char[pathLen];
+ snprintf (path, pathLen, "Aspects/%s", aspect);
+ int menuPos =
+ menu->add (path, 0, NULL, NULL,
+ FL_MENU_TOGGLE | (aspectEntry->set ? FL_MENU_VALUE : 0));
+ delete[] path;
+ aspectEntry->menuItem = (Fl_Menu_Item*)(menu->menu() + menuPos);
+ aspectEntry->menuItem->callback (toggleAspect, aspectEntry);
+
+ // TODO aspectsMenuPositions is only used in the deactivated
+ // code.
+#else
+ // Aspects are sorted alphabetically, so we choose the following
+ // approach:
+ //
+ // 1. Add a new entry, which is not used for the new aspect, but
+ // for the last aspect after sorting. For this reason, a
+ // random name is choosen.
+ //
+ // 2. Sort all aspects.
+ //
+ // 3. Re-assign all aspects to the menu entries.
+
+ // 1. Add new entry.
+ //
+ // It seams that a menu entry must have a unique name, so it is
+ // important to choose a temporary one which does not collide
+ // with an aspect. This one is the result of:
+ //
+ // $ head -c 32 < /dev/random | base64 | sed 's/\///g'
+ //
+ // (Further checks are not done, hoping that noone chooses this
+ // as an aspect.)
+
+ int menuPos =
+ menu->add ("Aspects/xgIUCOm3HTvK5P33Dsk3lPSL1qgXg4Iye3APe0ckMo0=",
+ 0, NULL, NULL, FL_MENU_TOGGLE);
+ aspectsMenuPositions->put (new Integer (menuPos));
+
+ // 2. Sort all aspects.
+
+ Vector<Aspect> sortedAspects (1, false);
+ for (lout::container::typed::Iterator<String> it = aspects->iterator ();
+ it.hasNext (); ) {
+ String *key = it.getNext ();
+ Aspect *value = aspects->get (key);
+ sortedAspects.insertSorted (value);
+ }
+
+ // 3. Re-assign all aspects to the menu entries.
+
+ assert (sortedAspects.size () == aspectsMenuPositions->size ());
+
+ for (int i = 0; i < sortedAspects.size (); i++) {
+ Aspect *aspect = sortedAspects.get (i);
+ int menuPos = aspectsMenuPositions->get(i)->getValue ();
+
+ // This is somewhat ugly (ignoring "const"):
+ aspect->menuItem = (Fl_Menu_Item*)(menu->menu() + menuPos);
+ //aspect->menuItem->label (aspect->name);
+ menu->replace (menuPos, aspect->name);
+ if (aspect->set)
+ aspect->menuItem->set ();
+ else
+ aspect->menuItem->clear ();
+ aspect->menuItem->callback (toggleAspect, aspect);
+ }
+#endif
+ }
+}
+
+
+ObjViewWindow::Priority *ObjViewWindow::addPriority (int priority, bool val)
+{
+ // Similar to addAspect().
+
+ Integer key (priority);
+ Priority *priorityEntry = priorities->get (&key);
+ if (priorityEntry == NULL) {
+ priorityEntry = new Priority (this, priority);
+ priorities->put (new Integer (priority), priorityEntry);
+
+#if 1
+ int pathLen = 11 + 5 + 1;
+ char path[pathLen];
+ snprintf (path, pathLen, "Priorities/%d", priority);
+ int menuPos = menu->add (path, 0, NULL, NULL,
+ FL_MENU_RADIO | (val ? FL_MENU_VALUE : 0));
+ priorityEntry->menuItem = (Fl_Menu_Item*)(menu->menu() + menuPos);
+ priorityEntry->menuItem->callback (setPriority, priorityEntry);
+
+ // TODO prioritiesMenuPositions is only used in the deactivated
+ // code.
+#else
+ // 1. Add new entry.
+
+ int menuPos =
+ menu->add ("Priorities/xgIUCOm3HTvK5P33Dsk3lPSL1qgXg4Iye3APe0ckMo0=",
+ 0, NULL, NULL, FL_MENU_RADIO);
+ prioritiesMenuPositions->put (new Integer (menuPos));
+
+ // 2. Sort all priorities.
+
+ Vector<Priority> sortedPriorities (1, false);
+ for (lout::container::typed::Iterator<Integer> it =
+ priorities->iterator (); it.hasNext (); ) {
+ Integer *key = it.getNext ();
+ Priority *value = priorities->get (key);
+ // "No limits" entry is not sorted.
+ if (value->value != INT_MAX)
+ sortedPriorities.insertSorted (value);
+ }
+
+ // 3. Re-assign all priorities to the menu entries (except "No limits").
+
+ assert (sortedPriorities.size () == prioritiesMenuPositions->size ());
+
+ for (int i = 0; i < sortedPriorities.size (); i++) {
+ Priority *priority = sortedPriorities.get (i);
+ int menuPos = prioritiesMenuPositions->get(i)->getValue ();
+
+ // Assuming maximal priorities of 99999 (snprintf will at
+ // least prevent buffer overflows).
+ snprintf (priority->valueBuf, 6, "%d", priority->value);
+
+ // This is somewhat ugly (ignoring "const"):
+ priority->menuItem = (Fl_Menu_Item*)(menu->menu() + menuPos);
+ //priority->menuItem->label (priority->valueBuf);
+ menu->replace (menuPos, priority->valueBuf);
+ if (priority->value == selectedPriority)
+ priority->menuItem->set ();
+ else
+ priority->menuItem->clear ();
+ priority->menuItem->callback (setPriority, priority);
+ }
+#endif
+ }
+
+ return priorityEntry;
+}
+
+void ObjViewWindow::setPriority (int priority)
+{
+ assert (!shown);
+
+ selectedPriority = priority;
+ addPriority (priority, true);
+ graph->recalculateCommandsVisibility ();
+}
+
+
+void ObjViewWindow::setAnyPriority ()
+{
+ assert (!shown);
+
+ selectedPriority = INT_MAX;
+ graph->recalculateCommandsVisibility ();
+}
+
+
+
+void ObjViewWindow::quit (Fl_Widget *widget, void *data)
+{
+ exit (0);
+}
+
+
+void ObjViewWindow::previous (Fl_Widget *widget, void *data)
+{
+ ((ObjViewWindow*)data)->graph->previousCommand ();
+}
+
+
+void ObjViewWindow::next (Fl_Widget *widget, void *data)
+{
+ ((ObjViewWindow*)data)->graph->nextCommand ();
+}
+
+
+void ObjViewWindow::viewCode (Fl_Widget *widget, void *data)
+{
+ ((ObjViewWindow*)data)->graph->viewCodeOfCommand ();
+}
+
+
+void ObjViewWindow::hideBefore (Fl_Widget *widget, void *data)
+{
+ ((ObjViewWindow*)data)->graph->hideBeforeCommand ();
+}
+
+
+void ObjViewWindow::hideAfter (Fl_Widget *widget, void *data)
+{
+ ((ObjViewWindow*)data)->graph->hideAfterCommand ();
+}
+
+
+void ObjViewWindow::hideAll (Fl_Widget *widget, void *data)
+{
+ ((ObjViewWindow*)data)->graph->hideAllCommands ();
+}
+
+
+void ObjViewWindow::showBefore (Fl_Widget *widget, void *data)
+{
+ ((ObjViewWindow*)data)->graph->showBeforeCommand ();
+}
+
+
+void ObjViewWindow::showAfter (Fl_Widget *widget, void *data)
+{
+ ((ObjViewWindow*)data)->graph->showAfterCommand ();
+}
+
+
+void ObjViewWindow::showAll (Fl_Widget *widget, void *data)
+{
+ ((ObjViewWindow*)data)->graph->showAllCommands ();
+}
+
+void ObjViewWindow::showStackTrace (Fl_Widget *widget, void *data)
+{
+ ((ObjViewWindow*)data)->graph->showStackTraceOfCommand ();
+}
+
+void ObjViewWindow::switchBetweenRelated (Fl_Widget *widget, void *data)
+{
+ ((ObjViewWindow*)data)->graph->switchBetweenRelatedCommands ();
+}
+
+void ObjViewWindow::toggleCommandTypeVisibility (Fl_Widget *widget, void *data)
+{
+ ((ObjViewWindow*)data)->graph->recalculateCommandsVisibility ();
+}
+
+
+void ObjViewWindow::showAllAspects (Fl_Widget *widget, void *data)
+{
+ ObjViewWindow *objectsWindow = (ObjViewWindow*)data;
+ bool showSet = objectsWindow->getShowAllAspectsMenuItem()->value ();
+ objectsWindow->showOrHideAllAspects (showSet);
+
+ if (showSet)
+ objectsWindow->getHideAllAspectsMenuItem()->clear ();
+ else
+ objectsWindow->getHideAllAspectsMenuItem()->set ();
+
+ objectsWindow->aspectsInitiallySet = true;
+}
+
+
+void ObjViewWindow::hideAllAspects (Fl_Widget *widget, void *data)
+{
+ ObjViewWindow *objectsWindow = (ObjViewWindow*)data;
+ bool hideSet = objectsWindow->getHideAllAspectsMenuItem()->value ();
+ objectsWindow->showOrHideAllAspects (!hideSet);
+
+ if (hideSet)
+ objectsWindow->getShowAllAspectsMenuItem()->clear ();
+ else
+ objectsWindow->getShowAllAspectsMenuItem()->set ();
+
+ objectsWindow->aspectsInitiallySet = false;
+}
+
+
+void ObjViewWindow::showOrHideAllAspects (bool value)
+{
+ for (lout::container::typed::Iterator<String> it = aspects->iterator ();
+ it.hasNext (); ) {
+ String *key = it.getNext ();
+ Aspect *aspect = aspects->get (key);
+ aspect->set = value;
+ if (value)
+ aspect->menuItem->set ();
+ else
+ aspect->menuItem->clear ();
+ }
+
+ graph->recalculateCommandsVisibility ();
+}
+
+
+void ObjViewWindow::toggleAspect (Fl_Widget *widget, void *data)
+{
+ Aspect *aspect = (Aspect*)data;
+ aspect->set = aspect->menuItem->value ();
+
+ bool allShown = true, allHidden = true;
+ for (lout::container::typed::Iterator<String> it =
+ aspect->window->aspects->iterator (); it.hasNext (); ) {
+ String *key = it.getNext ();
+ Aspect *value = aspect->window->aspects->get (key);
+ if (value->set)
+ allHidden = false;
+ else
+ allShown = false;
+ }
+
+ // There is at least one entry; otherwise, this method would not be
+ // called. (With no elements, allShown && allHidden would always be
+ // true.)
+ assert (!(allShown && allHidden));
+
+ // If neither all shown, nor all hidden, aspectsInitiallySet is not
+ // changed.
+
+ if (allShown) {
+ aspect->window->getShowAllAspectsMenuItem()->set ();
+ aspect->window->aspectsInitiallySet = true;
+ } else
+ aspect->window->getShowAllAspectsMenuItem()->clear ();
+
+ if (allHidden) {
+ aspect->window->getHideAllAspectsMenuItem()->set ();
+ aspect->window->aspectsInitiallySet = false;
+ } else
+ aspect->window->getHideAllAspectsMenuItem()->clear ();
+
+ aspect->window->graph->recalculateCommandsVisibility ();
+}
+
+
+void ObjViewWindow::setPriority (Fl_Widget *widget, void *data)
+{
+ Priority *priority = (Priority*)data;
+ priority->window->selectedPriority = priority->value;
+ priority->window->graph->recalculateCommandsVisibility ();
+}
+
+void ObjViewWindow::jumpToMark (Fl_Widget *widget, void *data)
+{
+ OVGAddMarkCommand *markCommand = (OVGAddMarkCommand*)data;
+ if (markCommand->isSelectable ())
+ markCommand->select ();
+}
+
+void ObjViewWindow::about (Fl_Widget *widget, void *data)
+{
+ ObjViewWindow *window = (ObjViewWindow*)data;
+
+ if (window->aboutWindow == NULL)
+ window->aboutWindow =
+ new common::AboutWindow("rtfl-objview",
+ "; with the following exception:\n"
+ "\n"
+ "The copyright holders of RTFL give you "
+ "permission to link rtfl-objview "
+ "statically or dynamically against all "
+ "versions of the graphviz library, which are "
+ "published by AT&T Corp. under one of the "
+ "following licenses:\n"
+ "\n"
+ "- Common Public License version 1.0 as "
+ "published by International Business Machines "
+ " Corporation (IBM), or\n"
+ "- Eclipse Public License version 1.0 as "
+ "published by the Eclipse Foundation",
+ common::AboutWindow::HEIGHT_EXCEPTION);
+ window->aboutWindow->show ();
+}
+
+
+void ObjViewWindow::windowCallback (Fl_Widget *widget, void *data)
+{
+ // Ignore escape key. TODO Looks rather hackish to me.
+ if (Fl::event_key() != FL_Escape)
+ quit (widget, data);
+}
+
+
+} // namespace objects
+
+} // namespace rtfl
diff --git a/objects/objview_window.hh b/objects/objview_window.hh
new file mode 100644
index 0000000..053b845
--- /dev/null
+++ b/objects/objview_window.hh
@@ -0,0 +1,189 @@
+#ifndef __OBJECTS_OBJVIEW_WINDOW_HH__
+#define __OBJECTS_OBJVIEW_WINDOW_HH__
+
+#include <FL/Fl_Window.H>
+#include <FL/Fl_Menu_Bar.H>
+#include <FL/Fl_Menu_Item.H>
+#include "objview_graph.hh"
+#include "lout/container.hh"
+#include "common/about.hh"
+
+namespace rtfl {
+
+namespace objects {
+
+class ObjViewWindow: public Fl_Window, public ObjViewFilterTool
+{
+private:
+ class Aspect: public lout::object::Comparable
+ {
+ public:
+ ObjViewWindow *window;
+ char *name;
+ bool set;
+ Fl_Menu_Item *menuItem;
+
+ Aspect (ObjViewWindow *window, const char *name, bool set);
+ ~Aspect ();
+
+ bool equals(Object *other);
+ int compareTo(Comparable *other);
+ };
+
+ class Priority: public lout::object::Comparable
+ {
+ public:
+ ObjViewWindow *window;
+ int value;
+ char valueBuf[6];
+ Fl_Menu_Item *menuItem;
+
+ Priority (ObjViewWindow *window, int value);
+
+ bool equals(Object *other);
+ int compareTo(Comparable *other);
+ };
+
+ bool shown;
+
+ ::dw::core::Layout *layout;
+ ObjViewGraph *graph;
+ Fl_Window *aboutWindow;
+ Fl_Menu_Bar *menu;
+
+ lout::container::typed::HashTable<lout::object::String, Aspect> *aspects;
+ lout::container::typed::Vector<lout::object::Integer> *aspectsMenuPositions;
+ bool aspectsInitiallySet;
+
+ lout::container::typed::HashTable<lout::object::Integer, Priority>
+ *priorities;
+ lout::container::typed::Vector<lout::object::Integer>
+ *prioritiesMenuPositions;
+ int selectedPriority;
+
+ inline Fl_Menu_Item *getCreateMenuItem ()
+ { return (Fl_Menu_Item*)menu->find_item("&Command/&Creations"); }
+
+ inline Fl_Menu_Item *getIndentMenuItem ()
+ { return (Fl_Menu_Item*)menu->find_item("&Command/&Indentations"); }
+
+ inline Fl_Menu_Item *getMessageMenuItem ()
+ { return (Fl_Menu_Item*)menu->find_item("&Command/&Messages"); }
+
+ inline Fl_Menu_Item *getMarkMenuItem ()
+ { return (Fl_Menu_Item*)menu->find_item("&Command/M&arks"); }
+
+ inline Fl_Menu_Item *getFunctionMenuItem ()
+ { return (Fl_Menu_Item*)menu->find_item("&Command/&Functions"); }
+
+ inline Fl_Menu_Item *getAssocMenuItem ()
+ { return (Fl_Menu_Item*)menu->find_item("&Command/A&ssociations"); }
+
+ inline Fl_Menu_Item *getAddAttrMenuItem ()
+ { return (Fl_Menu_Item*)menu->find_item("&Command/A&ttributes"); }
+
+ inline Fl_Menu_Item *getDeleteMenuItem ()
+ { return (Fl_Menu_Item*)menu->find_item("&Command/&Deletions"); }
+
+ inline Fl_Menu_Item *getShowAllAspectsMenuItem ()
+ { return (Fl_Menu_Item*)menu->find_item("&Aspects/&Show all"); }
+
+ inline Fl_Menu_Item *getHideAllAspectsMenuItem ()
+ { return (Fl_Menu_Item*)menu->find_item("&Aspects/&Hide all"); }
+
+ static void quit (Fl_Widget *widget, void *data);
+ static void previous (Fl_Widget *widget, void *data);
+ static void next (Fl_Widget *widget, void *data);
+ static void viewCode (Fl_Widget *widget, void *data);
+ static void hideBefore (Fl_Widget *widget, void *data);
+ static void hideAfter (Fl_Widget *widget, void *data);
+ static void hideAll (Fl_Widget *widget, void *data);
+ static void showBefore (Fl_Widget *widget, void *data);
+ static void showAfter (Fl_Widget *widget, void *data);
+ static void showAll (Fl_Widget *widget, void *data);
+ static void showStackTrace (Fl_Widget *widget, void *data);
+ static void switchBetweenRelated (Fl_Widget *widget, void *data);
+ static void toggleCommandTypeVisibility (Fl_Widget *widget, void *data);
+ static void showAllAspects (Fl_Widget *widget, void *data);
+ static void hideAllAspects (Fl_Widget *widget, void *data);
+ static void toggleAspect (Fl_Widget *widget, void *data);
+ static void setPriority (Fl_Widget *widget, void *data);
+ static void jumpToMark (Fl_Widget *widget, void *data);
+ static void about (Fl_Widget *widget, void *data);
+ static void windowCallback (Fl_Widget *widget, void *data);
+
+ Priority *addPriority (int priority, bool val);
+
+ void showOrHideAllAspects (bool value);
+
+public:
+ ObjViewWindow (int width, int height, const char *title);
+ ~ObjViewWindow ();
+
+ void show();
+
+ void addAspect (const char *aspect);
+ void addPriority (int priority);
+ bool isAspectSelected (const char *aspect);
+ bool isPrioritySelected (int priority);
+ bool isTypeSelected (OVGCommandType type);
+ void addMark (OVGAddMarkCommand *markCommand);
+
+ void addAspect (const char *aspect, bool val);
+ void setAspectsInitiallySet (bool val);
+ void setPriority (int priority);
+ void setAnyPriority ();
+
+ inline ObjViewGraph *getObjViewGraph () { return graph; }
+
+ inline void showCreateCommands (bool val) {
+ if (val) getCreateMenuItem()->set ();
+ else getCreateMenuItem()->clear ();
+ }
+
+ inline void showIndentCommands (bool val) {
+ if (val) getIndentMenuItem()->set ();
+ else getIndentMenuItem()->clear ();
+ }
+
+ inline void showMessageCommands (bool val) {
+ if (val) getMessageMenuItem()->set ();
+ else getMessageMenuItem()->clear ();
+ }
+
+ inline void showMarkCommands (bool val) {
+ if (val) getMarkMenuItem()->set ();
+ else getMarkMenuItem()->clear ();
+ }
+
+ inline void showFunctionCommands (bool val) {
+ if (val) getFunctionMenuItem()->set ();
+ else getFunctionMenuItem()->clear ();
+ }
+
+ inline void showAssocCommands (bool val) {
+ if (val) getAssocMenuItem()->set ();
+ else getAssocMenuItem()->clear ();
+ }
+
+ inline void showAddAttrCommands (bool val) {
+ if (val) getAddAttrMenuItem()->set ();
+ else getAddAttrMenuItem()->clear ();
+ }
+
+ inline void showDeleteCommands (bool val) {
+ if (val) getDeleteMenuItem()->set ();
+ else getDeleteMenuItem()->clear ();
+ }
+
+ inline void showObjectMessages (bool val) { graph->showObjectMessages(val); }
+ inline void showObjectContents (bool val) { graph->showObjectContents(val); }
+ inline void setCodeViewer (const char *codeViewer) {
+ graph->setCodeViewer (codeViewer); }
+};
+
+} // namespace objects
+
+} // namespace rtfl
+
+#endif // __OBJECTS_OBJVIEW_WINDOW_HH__
diff --git a/objects/rtfl_objbase.cc b/objects/rtfl_objbase.cc
new file mode 100644
index 0000000..1da24bb
--- /dev/null
+++ b/objects/rtfl_objbase.cc
@@ -0,0 +1,45 @@
+/*
+ * RTFL
+ *
+ * Copyright 2015 Sebastian Geerken <sgeerken@dillo.org>
+ *
+ * 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/>.
+ */
+
+#include "objects_parser.hh"
+#include "objects_writer.hh"
+#include "objdelete_controller.hh"
+#include "objident_controller.hh"
+
+#include <fcntl.h>
+
+using namespace rtfl::tools;
+using namespace rtfl::objects;
+
+int main(int argc, char **argv)
+{
+ LinesSourceSequence source (true);
+ int fd = open (".rtfl", O_RDONLY);
+ if (fd != -1)
+ source.add (new BlockingLinesSource (fd));
+ source.add (new BlockingLinesSource (0));
+
+ ObjectsWriter writer;
+ ObjIdentController identController (&writer);
+ ObjDeleteController deleteController (&identController);
+ ObjectsParser parser (&deleteController);
+ source.setup (&parser);
+
+ return 0;
+}
diff --git a/objects/rtfl_objcount.cc b/objects/rtfl_objcount.cc
new file mode 100644
index 0000000..fb71fbb
--- /dev/null
+++ b/objects/rtfl_objcount.cc
@@ -0,0 +1,40 @@
+/*
+ * RTFL
+ *
+ * Copyright 2013-2015 Sebastian Geerken <sgeerken@dillo.org>
+ *
+ * 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/>.
+ */
+
+#include "common/fltk_lines.hh"
+#include "objcount_window.hh"
+#include "objcount_controller.hh"
+
+using namespace rtfl::objects;
+using namespace rtfl::common;
+
+int main(int argc, char **argv)
+{
+ ObjCountWindow *window = new ObjCountWindow(800, 600, "RTFL: Objects count");
+ window->show();
+
+ FltkDefaultSource source;
+ ObjCountController controller (window->getTable ());
+ ObjectsParser parser (&controller);
+ source.setup (&parser);
+
+ int errorCode = Fl::run();
+ delete window;
+ return errorCode;
+}
diff --git a/objects/rtfl_objview.cc b/objects/rtfl_objview.cc
new file mode 100644
index 0000000..bed41bd
--- /dev/null
+++ b/objects/rtfl_objview.cc
@@ -0,0 +1,218 @@
+/*
+ * RTFL
+ *
+ * Copyright 2013-2015 Sebastian Geerken <sgeerken@dillo.org>
+ *
+ * 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; with the following exception:
+ *
+ * The copyright holders of RTFL give you permission to link this file
+ * statically or dynamically against all versions of the graphviz
+ * library, which are published by AT&T Corp. under one of the following
+ * licenses:
+ *
+ * - Common Public License version 1.0 as published by International
+ * Business Machines Corporation (IBM), or
+ * - Eclipse Public License version 1.0 as published by the Eclipse
+ * Foundation.
+ *
+ * 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/>.
+ */
+
+#include <unistd.h>
+#include <FL/Fl.H>
+#include "common/fltk_lines.hh"
+#include "objview_window.hh"
+#include "objview_controller.hh"
+#include "objdelete_controller.hh"
+#include "objident_controller.hh"
+
+using namespace rtfl::objects;
+using namespace rtfl::common;
+
+static void printHelp (const char *argv0)
+{
+ fprintf
+ (stderr, "Usage: %s <options>\n"
+ "\n"
+ "Options:\n"
+ " -a <aspect> Show,\n"
+ " -A <aspect> hide aspects. <aspect> may be '*'.\n"
+ " -b Do,\n"
+ " -B do not apply \".rtfl\" and filtering identities "
+ "(what \n"
+ " \"rtfl-objbase\" does).\n"
+ " -m Show,\n"
+ " -M hide the messages of all object boxes.\n"
+ " -o Show,\n"
+ " -O hide the contents of all object boxes.\n"
+ " -p <prio> Set priority. <prio> is a number or '*'.\n"
+ " -t <types> Show,\n"
+ " -T <types> hide command types. <types> is a sequence of any "
+ "of the\n"
+ " characters 'c', 'i', 'm', 'a', 'f', 's', 't', "
+ "'d'.\n"
+ " -v <viewer> Use <viewer> to view code. Contains '%%p' as "
+ "variable for\n"
+ " the path, and '%%n' for the line number.\n"
+ "\n"
+ "See RTFL documentation for more details.\n",
+ argv0);
+}
+
+static bool toggleCommandTypes (ObjViewWindow *window, const char *arg,
+ bool val)
+{
+ for (const char *s = arg; *s; s++) {
+ switch (*s) {
+ case 'c':
+ window->showCreateCommands (val);
+ break;
+
+ case 'i':
+ window->showIndentCommands (val);
+ break;
+
+ case 'm':
+ window->showMessageCommands (val);
+ break;
+
+ case 'a':
+ window->showMarkCommands (val);
+ break;
+
+ case 'f':
+ window->showFunctionCommands (val);
+ break;
+
+ case 's':
+ window->showAssocCommands (val);
+ break;
+
+ case 't':
+ window->showAddAttrCommands (val);
+ break;
+
+ case 'd':
+ window->showDeleteCommands (val);
+ break;
+
+ default:
+ return false;
+ }
+ }
+
+ return true;
+}
+
+int main(int argc, char **argv)
+{
+ ObjViewWindow *window = new ObjViewWindow(800, 600, "RTFL: Objects view");
+
+ int opt;
+ bool baseFiltering = true;
+
+ while ((opt = getopt(argc, argv, "a:A:bBMmOop:t:T:v:")) != -1) {
+ switch (opt) {
+ case 'a':
+ if (strcmp (optarg, "*") == 0)
+ window->setAspectsInitiallySet (true);
+ else
+ window->addAspect (optarg, true);
+ break;
+
+ case 'A':
+ if (strcmp (optarg, "*") == 0)
+ window->setAspectsInitiallySet (false);
+ else
+ window->addAspect (optarg, false);
+ break;
+
+ case 'b':
+ baseFiltering = true;
+ break;
+
+ case 'B':
+ baseFiltering = false;
+ break;
+
+ case 'm':
+ window->showObjectMessages (true);
+ break;
+
+ case 'M':
+ window->showObjectMessages (false);
+ break;
+
+ case 'o':
+ window->showObjectContents (true);
+ break;
+
+ case 'O':
+ window->showObjectContents (false);
+ break;
+
+ case 'p':
+ if (strcmp (optarg, "*") == 0)
+ window->setAnyPriority ();
+ else
+ window->setPriority (atoi (optarg));
+ break;
+
+ case 't':
+ if (!toggleCommandTypes (window, optarg, true)) {
+ printHelp (argv[0]);
+ delete window;
+ return 1;
+ }
+ break;
+
+ case 'T':
+ if (!toggleCommandTypes (window, optarg, false)) {
+ printHelp (argv[0]);
+ delete window;
+ return 1;
+ }
+ break;
+
+ case 'v':
+ window->setCodeViewer (optarg);
+ break;
+
+ default:
+ printHelp (argv[0]);
+ delete window;
+ return 1;
+ }
+ }
+
+ int errorCode;
+ ObjViewController viewController (window->getObjViewGraph ());
+
+ if (baseFiltering) {
+ FltkDefaultSource source;
+ ObjIdentController identController (&viewController);
+ ObjDeleteController deleteController (&identController);
+ ObjectsParser parser (&deleteController);
+ source.setup (&parser);
+ window->show();
+ errorCode = Fl::run();
+ } else {
+ FltkLinesSource source;
+ ObjectsParser parser (&viewController);
+ source.setup (&parser);
+ window->show();
+ errorCode = Fl::run();
+ }
+
+ delete window;
+ return errorCode;
+}
diff --git a/scripts/Makefile.am b/scripts/Makefile.am
new file mode 100644
index 0000000..6929095
--- /dev/null
+++ b/scripts/Makefile.am
@@ -0,0 +1,6 @@
+dist_bin_SCRIPTS = \
+ rtfl-check-objects \
+ rtfl-filter-out-classes \
+ rtfl-objfilter \
+ rtfl-objtail \
+ rtfl-stacktraces
diff --git a/scripts/rtfl-check-objects b/scripts/rtfl-check-objects
new file mode 100644
index 0000000..0e29e82
--- /dev/null
+++ b/scripts/rtfl-check-objects
@@ -0,0 +1,60 @@
+#!/usr/bin/perl
+
+# RTFL
+#
+# Copyright 2014 Sebastian Geerken <sgeerken@dillo.org>
+#
+# 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/>.
+
+# Usage: rtfl-check-objects
+#
+# Use RTFL messages to check for invalid object access.
+#
+# N. b. that parsing is incorrect, see <doc/rtfl.html#scripts>.
+
+%exist_objects = { };
+%all_objects = { };
+%ident_objects = { };
+
+sub check_object
+{
+ my $id1 = $_[0], $id2 = $ident_objects{$_[0]};
+ if (!($exist_objects{$id1} || ($id2 && $exist_objects{$id2}))) {
+ if ($all_objects{$id1} || ($id2 && $all_objects{$id2})) {
+ print "--- Object $id1 has been deleted: ---\n$_";
+ } else {
+ print "--- Object $id1 has never existed: ---\n$_";
+ }
+ }
+}
+
+while(<STDIN>) {
+ if (/^\[rtfl[^\]]*\][^:]*:[^:]*:[^:]*:(obj-)?create:([^:]*):/) {
+ $exist_objects{$2}++;
+ $all_objects{$2} = 1;
+ } elsif (/^\[rtfl[^\]]*\][^:]*:[^:]*:[^:]*:(obj-)?delete:(.*)$/) {
+ $exist_objects{$2}--;
+ } elsif (/^\[rtfl[^\]]*\][^:]*:[^:]*:[^:]*:(obj-)?ident:([^:]*):(.*)$/) {
+ if($2 ne $3) {
+ $ident_objects{$2} = $3;
+ $ident_objects{$3} = $2;
+ }
+ } elsif (/^\[rtfl[^\]]*\][^:]*:[^:]*:[^:]*:(obj-)?(msg|set|enter|leave):([^:]*):/ ||
+ /^\[rtfl[^\]]*\][^:]*:[^:]*:[^:]*:(obj-)?(msg-start|msg-end|leave):(.*)$/) {
+ check_object ($3);
+ } elsif (/^\[rtfl[^\]]*\][^:]*:[^:]*:[^:]*:(obj-)?assoc:([^:]*):(.*)$/) {
+ check_object ($2);
+ check_object ($3);
+ }
+}
diff --git a/scripts/rtfl-filter-out-classes b/scripts/rtfl-filter-out-classes
new file mode 100644
index 0000000..5c0d2f9
--- /dev/null
+++ b/scripts/rtfl-filter-out-classes
@@ -0,0 +1,63 @@
+#!/usr/bin/perl
+
+# RTFL
+#
+# Copyright 2014, 2015 Sebastian Geerken <sgeerken@dillo.org>
+#
+# 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/>.
+
+# Usage: rtfl-filter-out-classes [<classes> ...]
+#
+# Filter out all RTFL messages referring to objects belonging to a
+# specified set of classes. Each command line argument is a concrete
+# class or a (filename) pattern. The latter is useful to exclude whole
+# namespaces ("path::to::namespace::*").
+#
+# N. b. that parsing is slightly incorrect; escaping is (except partly
+# for classes) not considered.
+
+use File::FnMatch qw(:fnmatch);
+
+%removed_objects = { };
+
+open PIPE, "rtfl-objbase |";
+
+while(<PIPE>) {
+ if (/^\[rtfl-obj-1.[0-9]+][^:]*:[^:]*:[^:]*:(obj-)?create:([^:]*):(.*)$/) {
+ $removed = 0;
+ $o = $2;
+ $c1 = $3;
+ $c1 =~ s/\\:/:/g;
+ foreach $c2 (@ARGV) {
+ if (fnmatch ($c2, $c1)) {
+ $removed_objects{$o} = 1;
+ $removed = 1;
+ }
+ }
+ if (!$removed) { print; }
+ } elsif (/^\[rtfl-obj-1.[0-9]+][^:]*:[^:]*:[^:]*:(obj-)?(msg|set|enter|leave):([^:]*):/ &&
+ $removed_objects{$3}) {
+ # Suppress.
+ } elsif (/^\[rtfl-obj-1.[0-9]+][^:]*:[^:]*:[^:]*:(obj-)?(msg-(start|end)|delete|leave):(.*)$/ &&
+ $removed_objects{$4}) {
+ # Suppress.
+ } elsif (/^\[rtfl-obj-1.[0-9]+][^:]*:[^:]*:[^:]*:(obj-)?assoc:([^:]*):(.*)$/ &&
+ ($removed_objects{$2} || $removed_objects{$3})) {
+ # Suppress.
+ } else {
+ print;
+ }
+}
+
+close PIPE;
diff --git a/scripts/rtfl-objfilter b/scripts/rtfl-objfilter
new file mode 100755
index 0000000..2947e21
--- /dev/null
+++ b/scripts/rtfl-objfilter
@@ -0,0 +1,110 @@
+#!/usr/bin/perl
+
+# RTFL
+#
+# Copyright 2014 Sebastian Geerken <sgeerken@dillo.org>
+#
+# 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/>.
+
+# Usage: rtfl-objfilter [options]
+#
+# Filters a stream of RTFL messages by types, aspects and priorities.
+# The options -a, -A, -t, -T, and -p are supported and work in the
+# same way as for rtfl-objview. By default, nothing is filtered.
+#
+# N. b. that parsing is incorrect, see <doc/rtfl.html#scripts>.
+
+$LARGE_INT = 1000000000;
+
+sub helpAndExit {
+ die "Syntax: $0 uses same arguments -a, -A, -t, -T, and -p as rtfl-objview.";
+}
+
+sub filter1 {
+ return $shownTypes{$_[0]};
+}
+
+sub filter2 {
+ return $shownTypes{$_[0]} &&
+ (($defaultShow && !$hiddenAspects{$_[1]}) ||
+ (!$defaultShow && !$shownAspects{$_[1]})) &&
+ $_[2] >= $prio;
+}
+
+
+%shownAspects = {};
+%hiddenAspects = {};
+$defaultShow = 1;
+%shownTypes =
+ ( "i" => 1, "m" => 1, "a" => 1, "f" => 1, "s" => 1, "t" => 1, "d" => 1 );
+$prio = $LARGE_INT;
+
+for ($i = 0; $i < scalar @ARGV; $i++) {
+ $opt = $ARGV[$i];
+ helpAndExit if ($i == scalar @ARGV -1);
+ $arg = $ARGV[++$i];
+
+ if ($opt eq "-a") {
+ if (arg eq "*") { $defaultShow = 1; }
+ else { $shownAspects{$arg} = 1; }
+ } elsif ($opt eq "-A") {
+ if (arg eq "*") { $defaultShow = 0; }
+ else { $hiddenAspects{$arg} = 1; }
+ } elsif ($opt eq "-t" || $opt eq "-T") {
+ $show = $opt eq "-t";
+ for ($i = 0; $i < length ($arg); $i++) {
+ $shownTypes{substr ($arg, $i, 1)} = $show;
+ }
+ } elsif ($opt eq "-p") {
+ if ($arg eq "*") { $prio = $LARGE_INT; }
+ else { $prio = $arg; }
+ } else {
+ helpAndExit if ($method eq "");
+ }
+}
+
+@shownFuns = ();
+
+while(<STDIN>) {
+ if (/^\[rtfl[^\]]*\]/) {
+ if (/^\[rtfl[^\]]*\][^:]*:[^:]*:[^:]*:(obj-)?mark:[^:]*:([^:]*):([^:]*):/) {
+ print if (filter2 ("a", $2, $3));
+ } elsif (/^\[rtfl[^\]]*\][^:]*:[^:]*:[^:]*:(obj-)?msg:[^:]*:([^:]*):([^:]*):/) {
+ print if (filter2 ("m", $2, $3));
+ } elsif (/^\[rtfl[^\]]*\][^:]*:[^:]*:[^:]*:(obj-)?msg-start:/ ||
+ /^\[rtfl[^\]]*\][^:]*:[^:]*:[^:]*:(obj-)?msg-end:/) {
+ print if (filter1 ("i"));
+ } elsif (/^\[rtfl[^\]]*\][^:]*:[^:]*:[^:]*:(obj-)?set:/) {
+ print if (filter1 ("t"));
+ } elsif (/^\[rtfl[^\]]*\][^:]*:[^:]*:[^:]*:(obj-)?delete:/) {
+ print if (filter1 ("d"));
+ } elsif (/^\[rtfl[^\]]*\][^:]*:[^:]*:[^:]*:(obj-)?enter:[^:]*:([^:]*):([^:]*):/) {
+ $shown = filter2 ("f", $2, $3);
+ print if ($shown);
+ push @shownFuns, $shown;
+ } elsif (/^\[rtfl[^\]]*\][^:]*:[^:]*:[^:]*:(obj-)?leave:/) {
+ $show = pop @shownFuns;
+ print if ($shown);
+ } elsif (/^\[rtfl[^\]]*\][^:]*:[^:]*:[^:]*:(obj-)?create:/ ||
+ /^\[rtfl[^\]]*\][^:]*:[^:]*:[^:]*:(obj-)?assoc:/ ||
+ /^\[rtfl[^\]]*\][^:]*:[^:]*:[^:]*:(obj-)?color:/ ||
+ /^\[rtfl[^\]]*\][^:]*:[^:]*:[^:]*:(obj-)?class-color:/ ||
+ /^\[rtfl[^\]]*\][^:]*:[^:]*:[^:]*:(obj-)?object-color:/ ||
+ /^\[rtfl[^\]]*\][^:]*:[^:]*:[^:]*:(obj-)?ident:/) {
+ print;
+ } else {
+ print STDERR "Invalid line: $_";
+ }
+ }
+}
diff --git a/scripts/rtfl-objtail b/scripts/rtfl-objtail
new file mode 100644
index 0000000..d0ec9c0
--- /dev/null
+++ b/scripts/rtfl-objtail
@@ -0,0 +1,134 @@
+#!/usr/bin/perl
+
+# RTFL
+#
+# Copyright 2014 Sebastian Geerken <sgeerken@dillo.org>
+#
+# 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/>.
+
+# Usage: rtfl-objtail [-a <attributes> ...] [-A <attributes> ...] <len>
+#
+# Print only the last lines of a stream of RTFL messages, but include
+# those RTFL messages which are necessary to understand the last ones,
+# like "obj-create", "obj-assoc" etc., when they refer to objects in
+# the last lines.
+#
+# Any number of options "-a" and "-A" may be added with fnmatch(3)
+# like patterns; for those attributes specified by "-a", but not
+# excluded by "-A", the last attribute definitions before the actual
+# tail is shown for relevant objects.
+#
+# Example: "-a 'foo.*' -A '*.bar'" will show attribute values for
+# 'foo.qix', but not for, say, 'foo.bar', since "-A '*.bar'" overrides
+# "-a 'foo.*'".
+#
+# The opposite, "rtfl-objhead", is not needed; simply use "head" to
+# get the first lines.
+#
+# N. b. that parsing is slightly incorrect; escaping is not considered.
+
+use File::FnMatch qw(:fnmatch);
+
+sub helpAndExit {
+ die "Syntax: $0 [-a <attributes> ...] [-A <attributes> ...] <number of lines>";
+}
+
+$tlen = "";
+@attrs = ();
+@neg_attrs = ();
+
+for ($i = 0; $i < scalar @ARGV; $i++) {
+ if ($ARGV[$i] eq "-a") {
+ helpAndExit if ($i == scalar @ARGV -1);
+ push @attrs, $ARGV[++$i];
+ } elsif ($ARGV[$i] eq "-A") {
+ helpAndExit if ($i == scalar @ARGV -1);
+ push @neg_attrs, $ARGV[++$i];
+ } else {
+ $tlen = $ARGV[$i];
+ }
+}
+
+helpAndExit if ($tlen eq "");
+
+@all_lines = ();
+%rel_objects = { };
+%last_attrs = { };
+
+open PIPE, "rtfl-objbase |";
+
+while(<PIPE>) {
+ if (/^\[rtfl-obj-1.[0-9]+]/) { push @all_lines, $_; }
+}
+
+close PIPE;
+
+$len = scalar (@all_lines);
+if ($tlen > $len) {
+ $tlen = $len;
+}
+
+# Determine relevant objects from the last lines.
+for ($i = $len - $tlen; $i < $len; $i++) {
+ $_ = $all_lines[$i];
+ if (/^\[rtfl-obj-1.[0-9]+][^:]*:[^:]*:[^:]*:(obj-)?(create|msg|set|enter|leave):([^:]*):/ ||
+ /^\[rtfl-obj-1.[0-9]+][^:]*:[^:]*:[^:]*:(obj-)?(msg-start|msg-end|delete|leave):(.*)$/) {
+ $rel_objects{$3} = 1;
+ } elsif (/^\[rtfl-obj-1.[0-9]+][^:]*:[^:]*:[^:]*:(obj-)?assoc:([^:]*):(.*)$/) {
+ $rel_objects{$2} = 1;
+ $rel_objects{$3} = 1;
+ }
+}
+
+# Determine the last attribute values before the last lines.
+for ($i = 0; $i < $len - $tlen; $i++) {
+ $_ = $all_lines[$i];
+ if (/^\[rtfl-obj-1.[0-9]+][^:]*:[^:]*:[^:]*:(obj-)?set:([^:]*):([^:]*):(.*)/ &&
+ $rel_objects{$2}) {
+ $found = 0;
+ for ($j = 0; $j < scalar (@attrs) && !$found; $j++) {
+ if (fnmatch ($attrs[i], $3)) { $found = 1; }
+ }
+ for ($j = 0; $j < scalar (@neg_attrs) && $found; $j++) {
+ if (fnmatch ($neg_attrs[i], $3)) { $found = 0; }
+ }
+
+ if ($found) {
+ $last_attrs{"$2:$3"} = $_;
+ }
+ }
+}
+
+foreach (keys %last_attrs) {
+ print $last_attrs{$_};
+}
+
+# Print all relevant lines (both before the last lines and the last lines).
+for ($i = 0; $i < $len; $i++) {
+ $_ = $all_lines[$i];
+ if (/^\[rtfl-obj-1.[0-9]+][^:]*:[^:]*:[^:]*:(obj-)?color:/ ||
+ /^\[rtfl-obj-1.[0-9]+][^:]*:[^:]*:[^:]*:(obj-)?class-color:/ ||
+ /^\[rtfl-obj-1.[0-9]+][^:]*:[^:]*:[^:]*:(obj-)?object-color:/) {
+ print;
+ } elsif ($i >= $len - $tlen) {
+ print;
+ } elsif ((/^\[rtfl-obj-1.[0-9]+][^:]*:[^:]*:[^:]*:(obj-)?create:([^:]*):/ ||
+ /^\[rtfl-obj-1.[0-9]+][^:]*:[^:]*:[^:]*:(obj-)?delete:(.*)$/) &&
+ $rel_objects{$2}) {
+ print;
+ } elsif (/^\[rtfl-obj-1.[0-9]+][^:]*:[^:]*:[^:]*:(obj-)?assoc:([^:]*):(.*)$/
+ && $rel_objects{$2} && $rel_objects{$3}) {
+ print;
+ }
+}
diff --git a/scripts/rtfl-stacktraces b/scripts/rtfl-stacktraces
new file mode 100755
index 0000000..a9e953b
--- /dev/null
+++ b/scripts/rtfl-stacktraces
@@ -0,0 +1,117 @@
+#!/usr/bin/perl
+
+# RTFL
+#
+# Copyright 2014 Sebastian Geerken <sgeerken@dillo.org>
+#
+# 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/>.
+
+# Usage: rtfl-stracktraces <method name>
+#
+# Prints stacktraces which lead to a specific method given as command line
+# argument (based on "obj-enter" and "obj-leave").
+#
+# Further Arguments:
+#
+# -s Short format.
+# -n <n> Regard only stacktraces with at least <n> occurences of the method.
+# -e <n> Do not print stack traces, but all messages; if a stacktrace would
+# have been printed, exit after <n> further messages. Can be used
+# together with -m.
+# -m <mark> Do not print stack traces, but all messages; if a stacktrace would
+# have been printed, edit a obj-mark with all parameters (file name,
+# line number, process id, object, aspect, priority) taken from the
+# last "obj-enter" command. Can be used together with -e.
+#
+# N. b. that parsing is incorrect, see <doc/rtfl.html#scripts>.
+
+sub helpAndExit {
+ die "Syntax: $0 [-s] [-n <n>] [-e <n>] [-m <mark>] <method name>";
+}
+
+$method = "";
+$short = 0;
+$minNumCalls = 1;
+$willEnd = 0;
+$willEndCount = 0;
+$mark = "";
+
+for ($i = 0; $i < scalar @ARGV; $i++) {
+ if ($ARGV[$i] eq "-s") {
+ $short = 1;
+ } elsif ($ARGV[$i] eq "-n") {
+ helpAndExit if ($i == scalar @ARGV -1);
+ $minNumCalls = $ARGV[++$i];
+ } elsif ($ARGV[$i] eq "-e") {
+ helpAndExit if ($i == scalar @ARGV -1);
+ $willEnd = 1;
+ $willEndCount = $ARGV[++$i];
+ } elsif ($ARGV[$i] eq "-m") {
+ helpAndExit if ($i == scalar @ARGV -1);
+ $mark = $ARGV[++$i];
+ } else {
+ $method = $ARGV[$i];
+ }
+}
+
+helpAndExit if ($method eq "");
+
+@stack = ();
+$first = 1;
+$numCalls = 0;
+
+while(<STDIN>) {
+ if (($mark ne "" || $willEnd) && (!$endSoon || $endCount > 0)) {
+ print;
+ if ($endSoon && /^\[rtfl[^\]]*\]/) { $endCount--; };
+ }
+
+ if (/^(\[rtfl[^\]]*\][^:]*:[^:]*:[^:]*):(obj-)?enter:([^:]*:[^:]*:[^:]*):([^:]*):.*$/) {
+ push @stack, ($short ? $4 : $_);
+
+ if ($4 eq $method) {
+ $numCalls++;
+
+ if ($numCalls >= $minNumCalls) {
+ if ($willEnd) {
+ if (!$endSoon) {
+ $endSoon = 1;
+ $endCount = $willEndCount;
+ }
+ } elsif ($mark ne "") {
+ print "$2:(obj-)?mark:$3:$mark\n";
+ } else {
+ if ($short) {
+ $firstInLine = 1;
+ foreach $frame (@stack) {
+ print " > " unless $firstInLine;
+ print $frame;
+ $firstInLine = 0;
+ }
+ print "\n";
+ } else {
+ print "-" x 79, "\n" unless $first;
+ foreach $frame (@stack) { print $frame; }
+ }
+ $first = 0;
+ }
+ }
+ }
+ } elsif (/^\[rtfl[^\]]*\][^:]*:[^:]*:[^:]*:(obj-)?leave:.*$/) {
+ $l = pop @stack;
+ if ($l =~
+ /^\[rtfl[^\]]*\][^:]*:[^:]*:[^:]*:(obj-)?enter:[^:]*:[^:]*:[^:]*:$method:.*$/)
+ { $numCalls--; }
+ }
+}
diff --git a/tests/Makefile.am b/tests/Makefile.am
new file mode 100644
index 0000000..e63bcbc
--- /dev/null
+++ b/tests/Makefile.am
@@ -0,0 +1,137 @@
+AM_CPPFLAGS = \
+ -I$(top_srcdir) \
+ -DCUR_WORKING_DIR='"@BASE_CUR_WORKING_DIR@/tests"'
+
+noinst_PROGRAMS = \
+ rtfl-cat \
+ rtfl-trickle \
+ test-pipes-1 \
+ test-select-1 \
+ test-version-cmp \
+ test-fltk-1 \
+ test-fltk-2 \
+ test-rtfl-objects-1-without-rtfl \
+ test-rtfl-objects-1-with-rtfl \
+ test-rtfl-objects-2-without-rtfl \
+ test-rtfl-objects-2-with-rtfl \
+ test-rtfl-objects-3-without-rtfl \
+ test-rtfl-objects-3-with-rtfl \
+ test-rtfl-stats-1-without-rtfl \
+ test-rtfl-stats-1-with-rtfl \
+ test-tools-1 \
+ test-tools-2 \
+ test-tools-3 \
+ test-tools-4 \
+ test-tools-5 \
+ test-tools-6 \
+ test-widgets-1 \
+ test-widgets-2 \
+ test-widgets-3 \
+ test-widget-b-splines
+
+if HAS_GRAPHVIZ
+noinst_PROGRAMS += \
+ test-graphviz-1
+endif
+
+rtfl_cat_SOURCES = rtfl_cat.c
+
+rtfl_trickle_SOURCES = rtfl_trickle.c
+
+test_pipes_1_SOURCES = test_pipes_1.c
+
+test_select_1_SOURCES = test_select_1.c
+
+test_version_cmp_SOURCES = test_version_cmp.c
+
+test_fltk_1_SOURCES = test_fltk_1.cc
+test_fltk_1_LDADD = @LIBFLTK_LIBS@
+
+test_fltk_2_SOURCES = test_fltk_2.cc
+test_fltk_2_LDADD = @LIBFLTK_LIBS@
+
+test_graphviz_1_SOURCES = test_graphviz_1.c
+test_graphviz_1_LDADD = @GRAPHVIZ_LIBS@
+
+test_rtfl_objects_1_without_rtfl_SOURCES = test_rtfl_objects_1.cc
+test_rtfl_objects_1_without_rtfl_LDADD = ../lout/liblout.a
+test_rtfl_objects_1_with_rtfl_SOURCES = test_rtfl_objects_1_with_rtfl.cc
+test_rtfl_objects_1_with_rtfl_LDADD = ../lout/liblout.a
+
+test_rtfl_objects_2_without_rtfl_SOURCES = test_rtfl_objects_2.cc
+test_rtfl_objects_2_with_rtfl_SOURCES = test_rtfl_objects_2_with_rtfl.cc
+
+test_rtfl_objects_3_without_rtfl_SOURCES = test_rtfl_objects_3.cc
+test_rtfl_objects_3_with_rtfl_SOURCES = test_rtfl_objects_3_with_rtfl.cc
+
+test_rtfl_stats_1_without_rtfl_SOURCES = test_rtfl_stats_1.cc
+test_rtfl_stats_1_without_rtfl_LDADD = ../lout/liblout.a
+test_rtfl_stats_1_with_rtfl_SOURCES = test_rtfl_stats_1_with_rtfl.cc
+test_rtfl_stats_1_with_rtfl_LDADD = ../lout/liblout.a
+
+test_tools_1_SOURCES = test_tools_1.cc
+test_tools_1_LDADD = \
+ ../common/librtfl-tools.a \
+ ../lout/liblout.a
+
+test_tools_2_SOURCES = test_tools_2.cc simple_sink.hh simple_sink.cc \
+ testtools.hh testtools.cc
+test_tools_2_LDADD = \
+ ../common/librtfl-tools.a \
+ ../lout/liblout.a
+
+test_tools_3_SOURCES = test_tools_3.cc simple_sink.hh simple_sink.cc
+test_tools_3_LDADD = \
+ ../common/librtfl-tools.a \
+ ../lout/liblout.a
+
+test_tools_4_SOURCES = test_tools_4.cc simple_sink.hh simple_sink.cc \
+ testtools.hh testtools.cc
+test_tools_4_LDADD = \
+ ../common/librtfl-tools.a \
+ ../lout/liblout.a
+
+test_tools_5_SOURCES = test_tools_5.cc simple_sink.hh simple_sink.cc \
+ testtools.hh testtools.cc
+test_tools_5_LDADD = \
+ ../common/librtfl-tools.a \
+ ../lout/liblout.a
+
+test_tools_6_SOURCES = test_tools_6.cc simple_sink.hh simple_sink.cc \
+ testtools.hh testtools.cc
+test_tools_6_LDADD = \
+ ../common/librtfl-tools.a \
+ ../lout/liblout.a
+
+test_widgets_1_SOURCES = test_widgets_1.cc
+test_widgets_1_LDADD = \
+ ../dwr/libDw-rtfl.a \
+ ../dw/libDw-fltk.a \
+ ../dw/libDw-core.a \
+ ../lout/liblout.a \
+ @LIBFLTK_LIBS@
+
+test_widgets_2_SOURCES = test_widgets_2.cc
+test_widgets_2_LDADD = \
+ ../dwr/libDw-rtfl.a \
+ ../dw/libDw-fltk.a \
+ ../dw/libDw-core.a \
+ ../lout/liblout.a \
+ @LIBFLTK_LIBS@
+
+test_widgets_3_SOURCES = test_widgets_3.cc
+test_widgets_3_LDADD = \
+ ../dwr/libDw-rtfl.a \
+ ../dw/libDw-fltk.a \
+ ../dw/libDw-core.a \
+ ../lout/liblout.a \
+ @LIBFLTK_LIBS@
+
+test_widget_b_splines_SOURCES = test_widget_b_splines.cc
+test_widget_b_splines_LDADD = \
+ ../dwr/libDw-rtfl.a \
+ ../dw/libDw-fltk.a \
+ ../dw/libDw-core.a \
+ ../lout/liblout.a \
+ @LIBFLTK_LIBS@
+
diff --git a/tests/rtfl_cat.c b/tests/rtfl_cat.c
new file mode 100644
index 0000000..65d2e06
--- /dev/null
+++ b/tests/rtfl_cat.c
@@ -0,0 +1,53 @@
+/*
+ * RTFL
+ *
+ * Copyright 2014 Sebastian Geerken <sgeerken@dillo.org>
+ *
+ * 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/>.
+ */
+
+/*
+ * Simply copy stdin to stdout, with some debug messages printed to
+ * stderr. Used to test rtfl-tee.
+ */
+
+#include <unistd.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+
+static void syserr (const char *fmt, ...)
+{
+ va_list args;
+ va_start (args, fmt);
+ vfprintf (stderr, fmt, args);
+ fprintf (stderr, ": %s\n", strerror (errno));
+ exit (1);
+}
+
+int main (int argc, char *argv[])
+{
+ char buf[2048];
+ ssize_t n;
+
+ do {
+ if ((n = read (0, buf, sizeof (buf))) == -1) syserr ("read failed");
+ fprintf (stderr, "==> [%s] n = %d\n", argv[0], (int)n);
+ if (write (1, buf, n) == -1) syserr ("write failed");
+ } while (n > 0);
+
+ return 0;
+}
diff --git a/tests/rtfl_trickle.c b/tests/rtfl_trickle.c
new file mode 100644
index 0000000..391534e
--- /dev/null
+++ b/tests/rtfl_trickle.c
@@ -0,0 +1,55 @@
+/*
+ * RTFL
+ *
+ * Copyright 2014 Sebastian Geerken <sgeerken@dillo.org>
+ *
+ * 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/>.
+ */
+
+/*
+ * Simply copy stdin to stdout, but slowly character by character.
+ * Used to test rtfl-tee.
+ */
+
+#include <unistd.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+
+static void syserr (const char *fmt, ...)
+{
+ va_list args;
+ va_start (args, fmt);
+ vfprintf (stderr, fmt, args);
+ fprintf (stderr, ": %s\n", strerror (errno));
+ exit (1);
+}
+
+int main (int argc, char *argv[])
+{
+ char buf[2048];
+ ssize_t n, i;
+
+ do {
+ if ((n = read (0, buf, sizeof (buf))) == -1) syserr ("read failed");
+ for (i = 0; i < n; i++) {
+ if (write (1, buf + i, 1) == -1) syserr ("write failed");
+ usleep (250000);
+ }
+ } while (n > 0);
+
+ return 0;
+}
diff --git a/tests/simple_sink.cc b/tests/simple_sink.cc
new file mode 100644
index 0000000..d27fd18
--- /dev/null
+++ b/tests/simple_sink.cc
@@ -0,0 +1,61 @@
+#include "simple_sink.hh"
+#include "common/tools.hh"
+
+#include <unistd.h>
+#include <sys/timeb.h>
+
+namespace rtfl {
+
+namespace tests {
+
+using namespace rtfl::tools;
+
+SimpleSink::SimpleSink ()
+{
+ startTime = getCurrentTime ();
+ msg ("<init>");
+}
+
+void SimpleSink::setLinesSource (LinesSource *source)
+{
+ msg ("setLinesSource: souce = %p", source);
+}
+
+void SimpleSink::processLine (char *line)
+{
+ msg ("processLine: %s", line);
+}
+
+void SimpleSink::timeout (int type)
+{
+ msg ("timeout: type = %d", type);
+}
+
+void SimpleSink::finish ()
+{
+ msg ("finish");
+}
+
+long SimpleSink::getCurrentTime ()
+{
+ struct timeb t;
+ if (ftime (&t) == -1)
+ syserr ("ftime() failed");
+ return t.time * 1000L + t.millitm;
+}
+
+void SimpleSink::msg (const char *fmt, ...)
+{
+ va_list args;
+ va_start (args, fmt);
+
+ long time = getCurrentTime () - startTime;
+ printf ("[SimpleSink] %2ld.%03ld -- ", time / 1000, time % 1000);
+
+ vprintf (fmt, args);
+ putchar ('\n');
+}
+
+} // namespace tests
+
+} // namespace rtfl
diff --git a/tests/simple_sink.hh b/tests/simple_sink.hh
new file mode 100644
index 0000000..fb0a87a
--- /dev/null
+++ b/tests/simple_sink.hh
@@ -0,0 +1,30 @@
+#ifndef __TESTS_SIMPLE_SINK_HH__
+#define __TESTS_SIMPLE_SINK_HH__
+
+#include "common/lines.hh"
+
+namespace rtfl {
+
+namespace tests {
+
+class SimpleSink: public rtfl::tools::LinesSink {
+private:
+ long getCurrentTime ();
+ void msg (const char *fmt, ...);
+
+ long startTime;
+
+public:
+ SimpleSink ();
+
+ void setLinesSource (rtfl::tools::LinesSource *source);
+ void processLine (char *line);
+ void timeout (int type);
+ void finish ();
+};
+
+} // namespace tests
+
+} // namespace rtfl
+
+#endif // __TESTS_SIMPLE_SINK_HH__
diff --git a/tests/test_fltk_1.cc b/tests/test_fltk_1.cc
new file mode 100644
index 0000000..84d1cac
--- /dev/null
+++ b/tests/test_fltk_1.cc
@@ -0,0 +1,64 @@
+/*
+ * RTFL
+ *
+ * Copyright 2014, 2015 Sebastian Geerken <sgeerken@dillo.org>
+ *
+ * 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/>.
+ */
+
+#include <FL/Fl_Window.H>
+#include <FL/Fl_Menu_Bar.H>
+#include <FL/Fl_Menu_Item.H>
+#include <FL/Fl.H>
+
+Fl_Window *window;
+Fl_Menu_Bar *menu;
+
+static void changed (Fl_Widget *widget, void *data);
+
+Fl_Menu_Item menuItems[] = {
+ { "&Week", 0, 0, 0, FL_SUBMENU, 0, 0, 0, 0 },
+ { "Monday", 0, changed, NULL, FL_MENU_TOGGLE, 0, 0, 0, 0 },
+ { "Tuesday", 0, changed, NULL, FL_MENU_TOGGLE, 0, 0, 0, 0 },
+ { "Wednesday", 0, changed, NULL, FL_MENU_TOGGLE, 0, 0, 0, 0 },
+ { "Thursday", 0, changed, NULL, FL_MENU_TOGGLE, 0, 0, 0, 0 },
+ { "Friday", 0, changed, NULL, FL_MENU_TOGGLE, 0, 0, 0, 0 },
+ { "Saturday", 0, changed, NULL, FL_MENU_TOGGLE, 0, 0, 0, 0 },
+ { "Sunday", 0, changed, NULL, FL_MENU_TOGGLE, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0 }
+ };
+
+void changed (Fl_Widget *widget, void *data)
+{
+ printf ("Monday: %s\n",
+ menu->find_item("&Week/Monday")->value () ? "set" : "clear");
+ printf ("Tuesday: %s\n",
+ menu->find_item("&Week/Tuesday")->value () ? "set" : "clear");
+ printf ("etc.\n");
+}
+
+int main(int argc, char **argv)
+{
+ window = new Fl_Window(100, 24, "FLTK Test 1");
+ window->box(FL_NO_BOX);
+ window->begin();
+
+ menu = new Fl_Menu_Bar(0, 0, 100, 24);
+ menu->copy(menuItems);
+
+ window->show();
+ int errorCode = Fl::run();
+ return errorCode;
+}
diff --git a/tests/test_fltk_2.cc b/tests/test_fltk_2.cc
new file mode 100644
index 0000000..6dacce3
--- /dev/null
+++ b/tests/test_fltk_2.cc
@@ -0,0 +1,47 @@
+/*
+ * RTFL
+ *
+ * Copyright 2014, 2015 Sebastian Geerken <sgeerken@dillo.org>
+ *
+ * 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/>.
+ */
+
+#include <FL/Fl_Window.H>
+#include <FL/Fl_Hold_Browser.H>
+#include <FL/Fl.H>
+
+Fl_Window *window;
+Fl_Hold_Browser *browser;
+
+int main(int argc, char **argv)
+{
+ window = new Fl_Window(500, 500, "FLTK Test 2");
+ window->begin();
+
+ browser = new Fl_Hold_Browser (0, 0, 500, 500, NULL);
+
+ for (int n = 0; n < 255; n++) {
+ char buf[256];
+
+ snprintf (buf, sizeof(buf), "@B%d@.0x%02x - %d", n, n, n);
+ browser->add (buf, NULL);
+
+ snprintf (buf, sizeof(buf), "@i@B%d@.0x%02x - %d", n, n, n);
+ browser->add (buf, NULL);
+ }
+
+ window->show();
+ int errorCode = Fl::run();
+ return errorCode;
+}
diff --git a/tests/test_graphviz_1.c b/tests/test_graphviz_1.c
new file mode 100644
index 0000000..9199b25
--- /dev/null
+++ b/tests/test_graphviz_1.c
@@ -0,0 +1,46 @@
+#include <graphviz/gvc.h>
+
+int main(int argc, char *argv[])
+{
+ Agnode_t *node1, *node2;
+ Agedge_t *edge1;
+ Agraph_t *graph;
+ GVC_t *gvc;
+
+ gvc = gvContext ();
+ graph = agopen ("graph", Agdirected, NULL);
+
+ node1 = agnode(graph, "node1", TRUE);
+ agsafeset (node1, "width", "1", "");
+ agsafeset (node1, "height", "1", "");
+
+ node2 = agnode(graph, "node2", TRUE);
+ agsafeset (node2, "width", "1", "");
+ agsafeset (node2, "height", "1", "");
+
+ edge1 = agedge(graph, node1, node2, "edge1", TRUE);
+
+ puts ("---------- initially ----------");
+ agwrite (graph, stdout);
+
+ gvLayout (gvc, graph, "dot");
+ gvRender(gvc, graph, "dot", NULL);
+ gvFreeLayout(gvc, graph);
+
+ puts ("---------- after first layouting ----------");
+ agwrite (graph, stdout);
+
+ agsafeset (node2, "height", "2", "");
+
+ gvLayout (gvc, graph, "dot");
+ gvRender(gvc, graph, "dot", NULL);
+ gvFreeLayout(gvc, graph);
+
+ puts ("---------- after second layouting ----------");
+ agwrite (graph, stdout);
+
+ agclose (graph);
+ gvFreeContext(gvc);
+
+ return 0;
+}
diff --git a/tests/test_pipes_1.c b/tests/test_pipes_1.c
new file mode 100644
index 0000000..89e3256
--- /dev/null
+++ b/tests/test_pipes_1.c
@@ -0,0 +1,76 @@
+/*
+ * RTFL
+ *
+ * Copyright 2014 Sebastian Geerken <sgeerken@dillo.org>
+ *
+ * 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/>.
+ */
+
+#include <unistd.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/select.h>
+
+static void syserr (const char *fmt, ...)
+{
+ va_list args;
+ va_start (args, fmt);
+ vfprintf (stderr, fmt, args);
+ fprintf (stderr, ": %s\n", strerror (errno));
+ exit (1);
+}
+
+int main (int argc, char *argv[])
+{
+ int parent2child[2];
+ char buf[2048];
+ ssize_t n;
+
+ if (pipe (parent2child) == -1) syserr ("pipe failed");
+
+ switch (fork ()) {
+ case -1:
+ syserr ("fork failed");
+ break;
+
+ case 0:
+ if (close (parent2child[1]) == -1)
+ syserr ("close(%d) failed", parent2child[0]);
+ if (close (0) == -1) syserr ("close(0) failed");
+ if (dup2 (parent2child[0], 0) == -1)
+ syserr ("dup2(%d, 0) failed", parent2child[0]);
+ if (close (parent2child[0]) == -1)
+ syserr ("close(%d) failed", parent2child[0]);
+
+ do {
+ if ((n = read (0, buf, sizeof (buf))) == -1) syserr ("read failed");
+ fprintf (stderr, "[child] %d bytes read\n", (int)n);
+ } while (n > 0);
+ break;
+
+ default:
+ if (close (parent2child[0]) == -1)
+ syserr ("close(%d) failed", parent2child[0]);
+ if (write (parent2child[1], "Hi!", 3) == -1) syserr ("write failed");
+ if (close (parent2child[1]) == -1)
+ syserr ("close(%d) failed", parent2child[0]);
+
+ break;
+ }
+
+ return 0;
+}
diff --git a/tests/test_rtfl_objects_1.cc b/tests/test_rtfl_objects_1.cc
new file mode 100644
index 0000000..11e16c4
--- /dev/null
+++ b/tests/test_rtfl_objects_1.cc
@@ -0,0 +1,118 @@
+/*
+ * RTFL
+ *
+ * Copyright 2013-2015 Sebastian Geerken <sgeerken@dillo.org>
+ *
+ * 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/>.
+ */
+
+#include <stdlib.h>
+#include "debug_rtfl.hh"
+#include "lout/object.hh"
+#include "lout/container.hh"
+
+using namespace lout::object;
+using namespace lout::container::typed;
+
+class A
+{
+private:
+ A *other;
+ List<Integer> *numbers;
+
+public:
+ A ();
+ ~A ();
+ void setOther (A *other);
+ int doSomething (int n);
+};
+
+class B: public A
+{
+public:
+ B ();
+};
+
+class C: public A
+{
+public:
+ C ();
+};
+
+
+A::A ()
+{
+ DBG_OBJ_CREATE ("A");
+
+ other = NULL;
+ numbers = new List<Integer> (true);
+}
+
+A::~A ()
+{
+ delete numbers;
+}
+
+void A::setOther (A *other)
+{
+ DBG_OBJ_ASSOC_CHILD (other);
+
+ this->other = other;
+}
+
+int A::doSomething (int n)
+{
+ DBG_OBJ_ENTER ("", 0, "doSomething", "%d", n);
+
+ DBG_OBJ_MSGF ("", 0, "some message: n = %d", n);
+
+ int r = random () % 251;
+ numbers->append (new Integer (r));
+ DBG_OBJ_ARRSET_NUM ("numbers", numbers->size () - 1, r);
+
+ if (other && n > 0)
+ other->doSomething (n - 1);
+
+ DBG_OBJ_LEAVE_VAL ("%d", r);
+ return r;
+}
+
+B::B ()
+{
+ DBG_OBJ_CREATE ("B");
+}
+
+C::C ()
+{
+ DBG_OBJ_CREATE ("C");
+}
+
+int main (int argc, char *argv[])
+{
+ DBG_OBJ_CLASS_COLOR ("A", "#ffa0a0");
+ DBG_OBJ_CLASS_COLOR ("B", "#60ff60");
+ DBG_OBJ_CLASS_COLOR ("C", "#b0b0ff");
+
+ A x;
+ B y;
+ C z;
+
+ x.setOther (&y);
+ y.setOther (&z);
+ z.setOther (&x);
+
+ x.doSomething (8);
+
+ return 0;
+}
diff --git a/tests/test_rtfl_objects_1_with_rtfl.cc b/tests/test_rtfl_objects_1_with_rtfl.cc
new file mode 100644
index 0000000..c1eb983
--- /dev/null
+++ b/tests/test_rtfl_objects_1_with_rtfl.cc
@@ -0,0 +1,2 @@
+#define DBG_RTFL
+#include "test_rtfl_objects_1.cc"
diff --git a/tests/test_rtfl_objects_2.cc b/tests/test_rtfl_objects_2.cc
new file mode 100644
index 0000000..1cd134e
--- /dev/null
+++ b/tests/test_rtfl_objects_2.cc
@@ -0,0 +1,69 @@
+/*
+ * RTFL
+ *
+ * Copyright 2013-2015 Sebastian Geerken <sgeerken@dillo.org>
+ *
+ * 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/>.
+ */
+
+#include <stdlib.h>
+#include "../debug_rtfl.hh"
+
+class A
+{
+private:
+ int a;
+
+public:
+ inline A (int a) { DBG_OBJ_CREATE ("x::A"); this->a = a; }
+ inline void behaveAsA () { DBG_OBJ_MSGF ("", 0, "behaveAsA: a = %d", a); }
+};
+
+class B
+{
+private:
+ int b;
+
+public:
+ inline B (int b) { DBG_OBJ_CREATE ("y::B"); this->b = b; }
+ inline void behaveAsB () { DBG_OBJ_MSGF ("", 0, "behaveAsB: b = %d", b); }
+};
+
+class C: public A, public B
+{
+private:
+ int c;
+
+public:
+ inline C (int c): A (c / 3), B (c / 2) {
+ DBG_OBJ_CREATE ("z::C");
+ DBG_OBJ_BASECLASS (A);
+ DBG_OBJ_BASECLASS (B);
+ this->c = c;
+ }
+ inline void behaveAsC () { DBG_OBJ_MSGF ("", 0, "behaveAsC: c = %d", c); }
+};
+
+
+int main (int argc, char *argv[])
+{
+ DBG_OBJ_CLASS_COLOR ("x::A", "#c0ff80");
+ DBG_OBJ_CLASS_COLOR ("y::B", "#c0c0ff");
+ DBG_OBJ_CLASS_COLOR ("z::C", "#ffa0a0");
+
+ C c (6);
+ c.behaveAsA ();
+ c.behaveAsB ();
+ c.behaveAsC ();
+}
diff --git a/tests/test_rtfl_objects_2_with_rtfl.cc b/tests/test_rtfl_objects_2_with_rtfl.cc
new file mode 100644
index 0000000..2158044
--- /dev/null
+++ b/tests/test_rtfl_objects_2_with_rtfl.cc
@@ -0,0 +1,2 @@
+#define DBG_RTFL
+#include "test_rtfl_objects_2.cc"
diff --git a/tests/test_rtfl_objects_3.cc b/tests/test_rtfl_objects_3.cc
new file mode 100644
index 0000000..6cbeb4f
--- /dev/null
+++ b/tests/test_rtfl_objects_3.cc
@@ -0,0 +1,85 @@
+/*
+ * RTFL
+ *
+ * Copyright 2014, 2015 Sebastian Geerken <sgeerken@dillo.org>
+ *
+ * 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/>.
+ */
+
+#include <stdlib.h>
+#include "../debug_rtfl.hh"
+
+class A
+{
+private:
+ A *otherA;
+
+public:
+ A ();
+ ~A ();
+ void setOtherA (A *newOtherA);
+ void doSomething (int level);
+ void doActualStuff ();
+};
+
+A::A ()
+{
+ DBG_OBJ_CREATE ("A");
+ otherA = NULL;
+}
+
+A::~A ()
+{
+ DBG_OBJ_DELETE ();
+}
+
+void A::setOtherA (A *newOtherA)
+{
+ DBG_OBJ_ENTER ("all", 0, "setOtherA", "%p", newOtherA);
+
+ otherA = newOtherA;
+ DBG_OBJ_ASSOC_CHILD (otherA);
+
+ DBG_OBJ_LEAVE ();
+}
+
+void A::doSomething (int level)
+{
+ DBG_OBJ_ENTER ("all", 0, "doSomething", "%d", level);
+
+ if (level > 0) {
+ doActualStuff ();
+ if (otherA)
+ otherA->doSomething (level - 1);
+ }
+
+ DBG_OBJ_LEAVE ();
+}
+
+void A::doActualStuff ()
+{
+ DBG_OBJ_ENTER0 ("all", 0, "doActualStuff");
+
+ DBG_OBJ_MSG ("all", 1, "(pretending ...)");
+
+ DBG_OBJ_LEAVE ();
+}
+
+int main (int argc, char *argv[])
+{
+ A a1, a2;
+ a1.setOtherA (&a2);
+ a2.setOtherA (&a1);
+ a1.doSomething (20);
+}
diff --git a/tests/test_rtfl_objects_3_with_rtfl.cc b/tests/test_rtfl_objects_3_with_rtfl.cc
new file mode 100644
index 0000000..032f6aa
--- /dev/null
+++ b/tests/test_rtfl_objects_3_with_rtfl.cc
@@ -0,0 +1,2 @@
+#define DBG_RTFL
+#include "test_rtfl_objects_3.cc"
diff --git a/tests/test_rtfl_stats_1.cc b/tests/test_rtfl_stats_1.cc
new file mode 100644
index 0000000..9be443d
--- /dev/null
+++ b/tests/test_rtfl_stats_1.cc
@@ -0,0 +1,54 @@
+/*
+ * RTFL
+ *
+ * Copyright 2015 Sebastian Geerken <sgeerken@dillo.org>
+ *
+ * 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/>.
+ */
+
+// See "collect-stats" in this directory.
+
+#include "debug_rtfl.hh"
+#include "lout/object.hh"
+#include "lout/container.hh"
+
+using namespace lout::object;
+using namespace lout::container::typed;
+
+
+static void sortvec (Vector<Integer> *vec)
+{
+ DBG_GEN_TIME ();
+ DBG_OBJ_ENTER0_O ("", 0, NULL, "sortvec");
+
+ DBG_OBJ_MSGF_O ("", 0, NULL, "size = %d", vec->size ());
+
+ vec->sort ();
+
+ DBG_GEN_TIME ();
+ DBG_OBJ_LEAVE_O (NULL);
+}
+
+int main (int argc, char *argv[])
+{
+ for (int i = 0; i < 20; i++) {
+ int n = 20000 * i;
+ Vector<Integer> vec (n, true);
+ for (int j = 0; j < n; j++)
+ vec.put (new Integer (random ()));
+ sortvec (&vec);
+ }
+
+ return 0;
+}
diff --git a/tests/test_rtfl_stats_1_with_rtfl.cc b/tests/test_rtfl_stats_1_with_rtfl.cc
new file mode 100644
index 0000000..da23c75
--- /dev/null
+++ b/tests/test_rtfl_stats_1_with_rtfl.cc
@@ -0,0 +1,2 @@
+#define DBG_RTFL
+#include "test_rtfl_stats_1.cc"
diff --git a/tests/test_select_1.c b/tests/test_select_1.c
new file mode 100644
index 0000000..db92d06
--- /dev/null
+++ b/tests/test_select_1.c
@@ -0,0 +1,67 @@
+/*
+ * RTFL
+ *
+ * Copyright 2015 Sebastian Geerken <sgeerken@dillo.org>
+ *
+ * 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/>.
+ */
+
+#include <unistd.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/select.h>
+
+static void syserr (const char *fmt, ...)
+{
+ va_list args;
+ va_start (args, fmt);
+ vfprintf (stderr, fmt, args);
+ fprintf (stderr, ": %s\n", strerror (errno));
+ exit (1);
+}
+
+int main (int argc, char *argv[])
+{
+ int eos = 0;
+ while (!eos) {
+ fd_set readfds;
+ FD_ZERO (&readfds);
+ FD_SET (0, &readfds);
+
+ struct timeval tv;
+ tv.tv_sec = 1;
+ tv.tv_usec = 0;
+
+ if (select (1, &readfds, NULL, NULL, &tv) == -1)
+ syserr ("select failed");
+
+ if (FD_ISSET (0, &readfds)) {
+ char buf[1024];
+ int n = read (0, buf, 1024);
+ if (n == -1)
+ syserr ("select read");
+ else if (n == 0)
+ eos = 1;
+ else
+ if (write (1, buf, n) == -1)
+ syserr ("write failed");
+ } else
+ puts ("---------- timeout? ----------");
+ }
+
+ return 0;
+}
diff --git a/tests/test_tools_1.cc b/tests/test_tools_1.cc
new file mode 100644
index 0000000..a09b7aa
--- /dev/null
+++ b/tests/test_tools_1.cc
@@ -0,0 +1,97 @@
+/*
+ * RTFL
+ *
+ * Copyright 2015 Sebastian Geerken <sgeerken@dillo.org>
+ *
+ * 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/>.
+ */
+
+#include "common/tools.hh"
+
+using namespace lout::object;
+using namespace lout::misc;
+using namespace lout::container::untyped;
+using namespace rtfl::tools;
+
+class TestObject: public Object
+{
+private:
+ int n;
+
+public:
+ TestObject (int n);
+ ~TestObject ();
+
+ void intoStringBuffer (StringBuffer *sb);
+};
+
+TestObject::TestObject (int n)
+{
+ this->n = n;
+}
+
+TestObject::~TestObject ()
+{
+ printf("(~TestObject: %d)\n", n);
+}
+
+void TestObject::intoStringBuffer (StringBuffer *sb)
+{
+ sb->append ("TestObject: ");
+ sb->appendInt (n);
+}
+
+int main(int argc, char **argv)
+{
+ String *id[4];
+ TestObject *testObject[4];
+ EquivalenceRelation rel (true, true);
+
+ for (int i = 0; i < 4; i++) {
+ char idBuf[] = { 'i', (char)('1' + i), 0 };
+ id[i] = new String(idBuf);
+ testObject[i] = new TestObject (i);
+
+ // New key since they are deleted by EquivalenceRelation.remove()
+ // but later still needed for EquivalenceRelation.contains().
+ rel.put (new String(id[i]->chars ()), testObject[i]);
+ }
+
+ for (int i = 0; i < 4; i++) {
+ puts ("--------------------------------------------------");
+ for (int j = 0; j < 4; j++) {
+ if (rel.contains (id[j])) {
+ Object *obj = rel.get (id[j]);
+ StringBuffer sb;
+ obj->intoStringBuffer (&sb);
+ puts (sb.getChars ());
+ } else
+ puts ("(removed)");
+ }
+
+ if (i == 0)
+ rel.relate (id[0], id[1]);
+
+ if (i == 1)
+ rel.relate (id[0], id[2]);
+
+ if (i == 2)
+ rel.remove (id[0]);
+ }
+
+ for (int i = 0; i < 4; i++)
+ delete id[i];
+
+ puts ("--------------------------------------------------");
+}
diff --git a/tests/test_tools_2.cc b/tests/test_tools_2.cc
new file mode 100644
index 0000000..0cf4cad
--- /dev/null
+++ b/tests/test_tools_2.cc
@@ -0,0 +1,26 @@
+#include "simple_sink.hh"
+#include "testtools.hh"
+
+using namespace rtfl::tools;
+using namespace rtfl::tests;
+
+int main (int argc, char *argv[])
+{
+ int fd1 = openPipe ("echo Hello; sleep 2");
+ BlockingLinesSource s1 (fd1);
+ // Both commands start at the same time, even if fd2 is processed later; thus
+ // the "sleep" at the beginning of the second command.
+ int fd2 = openPipe ("sleep 2; echo World; sleep 2");
+ BlockingLinesSource s2 (fd2);
+
+ LinesSourceSequence lss (false);
+ lss.add (&s1);
+ lss.add (&s2);
+ lss.addTimeout(1, 123);
+ lss.addTimeout(3, 124);
+
+ SimpleSink sink;
+ lss.setup (&sink);
+
+ return 0;
+}
diff --git a/tests/test_tools_3.cc b/tests/test_tools_3.cc
new file mode 100644
index 0000000..5762c90
--- /dev/null
+++ b/tests/test_tools_3.cc
@@ -0,0 +1,16 @@
+#include "simple_sink.hh"
+
+using namespace rtfl::tools;
+using namespace rtfl::tests;
+
+int main (int argc, char *argv[])
+{
+ BlockingLinesSource source (0);
+ for(int i = 0; i < 5; i++)
+ source.addTimeout(1 + i, 123 + i);
+
+ SimpleSink sink;
+ source.setup (&sink);
+
+ return 0;
+}
diff --git a/tests/test_tools_4.cc b/tests/test_tools_4.cc
new file mode 100644
index 0000000..8727fa4
--- /dev/null
+++ b/tests/test_tools_4.cc
@@ -0,0 +1,19 @@
+#include "simple_sink.hh"
+#include "testtools.hh"
+
+using namespace rtfl::tools;
+using namespace rtfl::tests;
+
+int main (int argc, char *argv[])
+{
+ int fd =
+ openPipe ("for i in $(seq 1 10); do echo Hello world $i; sleep 1; done");
+ BlockingLinesSource source (fd);
+ for(int i = 0; i < 5; i++)
+ source.addTimeout(1 + i, 123 + i);
+
+ SimpleSink sink;
+ source.setup (&sink);
+
+ return 0;
+}
diff --git a/tests/test_tools_5.cc b/tests/test_tools_5.cc
new file mode 100644
index 0000000..9f5f957
--- /dev/null
+++ b/tests/test_tools_5.cc
@@ -0,0 +1,37 @@
+#include "simple_sink.hh"
+#include "testtools.hh"
+
+using namespace rtfl::tools;
+using namespace rtfl::tests;
+
+class NotSoSimpleSink: public SimpleSink
+{
+private:
+ LinesSource *source;
+
+public:
+ NotSoSimpleSink (LinesSource *source);
+ void processLine (char *line);
+};
+
+NotSoSimpleSink::NotSoSimpleSink (LinesSource *source)
+{
+ this->source = source;
+}
+
+void NotSoSimpleSink::processLine (char *line)
+{
+ SimpleSink::processLine (line);
+ if (strcmp (line, "create") == 0)
+ source->addTimeout (2, 0);
+}
+
+int main (int argc, char *argv[])
+{
+ int fd = openPipe ("echo create; echo msg; sleep 5");
+ BlockingLinesSource source (fd);
+ NotSoSimpleSink sink (&source);
+ source.setup (&sink);
+
+ return 0;
+}
diff --git a/tests/test_tools_6.cc b/tests/test_tools_6.cc
new file mode 100644
index 0000000..f02a19e
--- /dev/null
+++ b/tests/test_tools_6.cc
@@ -0,0 +1,29 @@
+#include "simple_sink.hh"
+#include "testtools.hh"
+
+using namespace rtfl::tools;
+using namespace rtfl::tests;
+
+// Test LinesSourceSequence: make sure that LinesSourceSequence deals correctly
+// with timeouts.
+int main (int argc, char *argv[])
+{
+ int fd1 = openPipe ("sleep 5");
+ BlockingLinesSource s1 (fd1);
+ // Both commands start at the same time, even if fd2 is processed later; so
+ // it takes 10, not 15 secs totally.
+ int fd2 = openPipe ("sleep 10");
+ BlockingLinesSource s2 (fd2);
+
+ LinesSourceSequence lss (false);
+ lss.add (&s1);
+ lss.add (&s2);
+
+ for (int i = 2; i <= 20; i += 2)
+ lss.addTimeout(i, i);
+
+ SimpleSink sink;
+ lss.setup (&sink);
+
+ return 0;
+}
diff --git a/tests/test_version_cmp.c b/tests/test_version_cmp.c
new file mode 100644
index 0000000..98667d6
--- /dev/null
+++ b/tests/test_version_cmp.c
@@ -0,0 +1,49 @@
+// Used for "../configure.ac".
+
+#include <ctype.h>
+#include <stdlib.h>
+
+static int version_cmp (const char *v1, const char *v2)
+{
+ const char *s1 = v1, *s2 = v2;
+ while (*s1 && *s2) {
+ if (isdigit (*s1) && isdigit (*s2)) {
+ char buf1[10], buf2[10];
+ int n1 = 0, n2 = 0;
+
+ while (isdigit (*s1)) {
+ if (n1 < 9) buf1[n1++] = *s1;
+ s1++;
+ }
+
+ while (isdigit (*s2)) {
+ if (n2 < 9) buf2[n2++] = *s2;
+ s2++;
+ }
+
+ buf1[n1] = buf2[n2] = 0;
+ int c = atoi (buf1) - atoi (buf2);
+ if (c != 0)
+ return c;
+ } else {
+ if (*s1 != *s2)
+ return *s1 - *s2;
+ s1++;
+ s2++;
+ }
+ }
+
+ return *s1 - *s2;
+}
+
+#include <stdio.h>
+
+int main (int argc, char *argv[])
+{
+ printf ("%d, %d, %d %d\n",
+ version_cmp ("0.1", "0.001"),
+ version_cmp ("0.1", "0.002"),
+ version_cmp ("0.1a", "0.1"),
+ version_cmp ("2.38.0", "2.38.1"));
+ return 0;
+}
diff --git a/tests/test_widget_b_splines.cc b/tests/test_widget_b_splines.cc
new file mode 100644
index 0000000..a4a5f02
--- /dev/null
+++ b/tests/test_widget_b_splines.cc
@@ -0,0 +1,123 @@
+/*
+ * RTFL
+ *
+ * Copyright 2015 Sebastian Geerken <sgeerken@dillo.org>
+ *
+ * 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/>.
+ */
+
+
+#include <FL/Fl_Window.H>
+#include <FL/Fl.H>
+
+#include "dw/core.hh"
+#include "dw/fltkcore.hh"
+#include "dw/fltkviewport.hh"
+#include "dwr/tools.hh"
+
+using namespace dw;
+using namespace dw::core;
+using namespace dw::core::style;
+using namespace dw::fltk;
+using namespace rtfl::dw::tools;
+
+class BSplineWidget: public Widget
+{
+public:
+ void sizeRequestImpl (Requisition *requisition);
+ void getExtremesImpl(Extremes *extremes);
+ void draw (View *view, Rectangle *area);
+ Iterator *iterator (Content::Type mask, bool atEnd);
+};
+
+void BSplineWidget::sizeRequestImpl (Requisition *requisition)
+{
+ requisition->width = getAvailWidth (true);
+ requisition->ascent = getAvailHeight (true);
+ requisition->descent = 0;
+}
+
+void BSplineWidget::getExtremesImpl(Extremes *extremes)
+{
+ extremes->minWidth = extremes->maxWidth = extremes->minWidthIntrinsic =
+ extremes->maxWidthIntrinsic = 1;
+}
+
+void BSplineWidget::draw (View *view, Rectangle *area)
+{
+ double xp[7] = { 0.4, 0.1, 0.2, 0.5, 0.5, 0.9, 0.7 };
+ double yp[7] = { 0.1, 0.5, 0.8, 0.7, 0.2, 0.4, 0.9 };
+ int x[7], y[7];
+
+ for (int i = 0; i < 7; i++) {
+ x[i] = allocation.x + xp[i] * allocation.width;
+ y[i] = allocation.y + yp[i] * getHeight ();
+ }
+
+ for(int i = 0; i < 7; i++) {
+ view->drawArc (getStyle()->color, core::style::Color::SHADING_NORMAL,
+ true, x[i], y[i], 5, 5, 0, 360);
+ }
+
+ drawBSpline (view, getStyle(), 4, 7, x, y);
+}
+
+Iterator *BSplineWidget::iterator (Content::Type mask, bool atEnd)
+{
+ return new core::EmptyIterator (this, mask, atEnd);
+}
+
+int main(int argc, char **argv)
+{
+ FltkPlatform *platform = new FltkPlatform ();
+ Layout *layout = new Layout (platform);
+
+ Fl_Window *window = new Fl_Window(500, 400, "Dw Example");
+ window->box(FL_NO_BOX);
+ window->begin();
+
+ FltkViewport *viewport = new FltkViewport (0, 0, 500, 400);
+ layout->attachView (viewport);
+
+ StyleAttrs styleAttrs;
+ styleAttrs.initValues ();
+ styleAttrs.padding.setVal (5);
+
+ FontAttrs fontAttrs;
+ fontAttrs.name = "DejaVu Sans";
+ fontAttrs.size = 14;
+ fontAttrs.weight = 400;
+ fontAttrs.style = FONT_STYLE_NORMAL;
+ fontAttrs.letterSpacing = 0;
+ fontAttrs.fontVariant = FONT_VARIANT_NORMAL;
+ styleAttrs.font = style::Font::create (layout, &fontAttrs);
+
+ styleAttrs.color = Color::create (layout, 0x000000);
+ styleAttrs.backgroundColor = Color::create (layout, 0xffffff);
+
+ Style *style = Style::create (&styleAttrs);
+
+ BSplineWidget *widget = new BSplineWidget ();
+ widget->setStyle (style);
+ layout->setWidget (widget);
+ style->unref();
+
+ window->resizable(viewport);
+ window->show();
+ int errorCode = Fl::run();
+
+ delete layout;
+
+ return errorCode;
+}
diff --git a/tests/test_widgets_1.cc b/tests/test_widgets_1.cc
new file mode 100644
index 0000000..c6e2fed
--- /dev/null
+++ b/tests/test_widgets_1.cc
@@ -0,0 +1,142 @@
+/*
+ * RTFL
+ *
+ * Copyright 2013-2015 Sebastian Geerken <sgeerken@dillo.org>
+ *
+ * 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/>.
+ */
+
+#include <FL/Fl_Window.H>
+#include <FL/Fl.H>
+
+#include "dw/core.hh"
+#include "dw/fltkcore.hh"
+#include "dw/fltkviewport.hh"
+
+#include "dwr/graph.hh"
+#include "dwr/label.hh"
+#include "dwr/hbox.hh"
+#include "dwr/vbox.hh"
+#include "dwr/toggle.hh"
+
+using namespace dw;
+using namespace dw::core;
+using namespace dw::core::style;
+using namespace dw::fltk;
+
+using namespace rtfl::dw;
+
+int main(int argc, char **argv)
+{
+ FltkPlatform *platform = new FltkPlatform ();
+ Layout *layout = new Layout (platform);
+
+ Fl_Window *window = new Fl_Window(500, 400, "Dw Example");
+ window->box(FL_NO_BOX);
+ window->begin();
+
+ FltkViewport *viewport = new FltkViewport (0, 0, 500, 400);
+ layout->attachView (viewport);
+
+ StyleAttrs styleAttrs;
+ styleAttrs.initValues ();
+ styleAttrs.padding.setVal (5);
+
+ FontAttrs fontAttrs;
+ fontAttrs.name = "DejaVu Sans";
+ fontAttrs.size = 14;
+ fontAttrs.weight = 400;
+ fontAttrs.style = FONT_STYLE_NORMAL;
+ fontAttrs.letterSpacing = 0;
+ fontAttrs.fontVariant = FONT_VARIANT_NORMAL;
+ styleAttrs.font = style::Font::create (layout, &fontAttrs);
+
+ styleAttrs.color = Color::create (layout, 0x000000);
+ styleAttrs.backgroundColor = Color::create (layout, 0xffffff);
+
+ Style *graphStyle = Style::create (&styleAttrs);
+ Graph *graph = new Graph ();
+ graph->setStyle (graphStyle);
+ layout->setWidget (graph);
+ graphStyle->unref();
+
+ styleAttrs.borderWidth.setVal (1);
+ styleAttrs.setBorderStyle (BORDER_OUTSET);
+ styleAttrs.setBorderColor (Color::create (layout, 0x000000));
+ Style *textblockStyle = Style::create (&styleAttrs);
+
+ styleAttrs.borderWidth.setVal (0);
+ styleAttrs.padding.setVal (0);
+ Style *textStyle = Style::create (&styleAttrs);
+
+ graph->setRefStyle (textblockStyle);
+
+ HBox *n1 = new HBox (false);
+ n1->setStyle (textblockStyle);
+ graph->addNode (n1);
+
+ Label *l11 = new Label ("Hello <i>w<b>or</i>ld!</b>");
+ l11->setStyle (textblockStyle);
+ n1->addChild (l11);
+
+ Label *l12 = new Label ("More text ...");
+ l12->setStyle (textblockStyle);
+ n1->addChild (l12);
+
+ VBox *n2 = new VBox (false);
+ n2->setStyle (textblockStyle);
+ graph->addNode (n2);
+
+ Label *l21 = new Label ("Ἐν ἀρχῇ ἦν ὁ Λόγος, καὶ ὁ Λόγος ἦν πρὸς τὸν Θεόν, "
+ "καὶ Θεὸς ἦν ὁ Λόγος.");
+ l21->setStyle (textblockStyle);
+ n2->addChild (l21);
+
+ Label *l22 = new Label ("Οὗτος ἦν ἐν ἀρχῇ πρὸς τὸν Θεόν. πάντα δι' αὐτοῦ "
+ "ἐγένετο, καὶ χωρὶς αὐτοῦ ἐγένετο οὐδὲ ἕν ὃ "
+ "γέγονεν.");
+ l22->setStyle (textblockStyle);
+ n2->addChild (l22);
+
+ Toggle *n3 = new Toggle (true);
+ n3->setStyle (textblockStyle);
+ graph->addNode (n3);
+
+ Label *l31 = new Label ("small");
+ l31->setStyle (textblockStyle);
+ n3->setSmall (l31);
+
+ Label *l33 = new Label ("LLLAAAAARRRRRGGGEEE");
+ l33->setStyle (textblockStyle);
+ n3->setLarge (l33);
+
+ Label *n4 = new Label ("#4");
+ n4->setStyle (textblockStyle);
+ graph->addNode (n4);
+
+ graph->addEdge (n1, n2);
+ graph->addEdge (n1, n3);
+ graph->addEdge (n2, n1);
+
+ textStyle->unref();
+ textblockStyle->unref();
+
+ window->resizable(viewport);
+ window->show();
+ int errorCode = Fl::run();
+
+ delete layout;
+
+ return errorCode;
+}
diff --git a/tests/test_widgets_2.cc b/tests/test_widgets_2.cc
new file mode 100644
index 0000000..c20b50c
--- /dev/null
+++ b/tests/test_widgets_2.cc
@@ -0,0 +1,97 @@
+/*
+ * RTFL
+ *
+ * Copyright 2013-2015 Sebastian Geerken <sgeerken@dillo.org>
+ *
+ * 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/>.
+ */
+
+#include <FL/Fl_Window.H>
+#include <FL/Fl.H>
+
+#include "dw/core.hh"
+#include "dw/fltkcore.hh"
+#include "dw/fltkviewport.hh"
+
+#include "dwr/vbox.hh"
+#include "dwr/label.hh"
+
+using namespace dw;
+using namespace dw::core;
+using namespace dw::core::style;
+using namespace dw::fltk;
+
+using namespace rtfl::dw;
+
+int main(int argc, char **argv)
+{
+ FltkPlatform *platform = new FltkPlatform ();
+ Layout *layout = new Layout (platform);
+
+ Fl_Window *window = new Fl_Window(500, 400, "Dw Example");
+ window->box(FL_NO_BOX);
+ window->begin();
+
+ FltkViewport *viewport = new FltkViewport (0, 0, 500, 400);
+ layout->attachView (viewport);
+
+ FontAttrs fontAttrs;
+ fontAttrs.name = "DejaVu Serif";
+ fontAttrs.size = 14;
+ fontAttrs.weight = 400;
+ fontAttrs.style = FONT_STYLE_NORMAL;
+ fontAttrs.letterSpacing = 0;
+ fontAttrs.fontVariant = FONT_VARIANT_NORMAL;
+
+ StyleAttrs styleAttrs;
+ styleAttrs.font = style::Font::create (layout, &fontAttrs);
+ styleAttrs.initValues ();
+ styleAttrs.margin.setVal (5);
+ styleAttrs.borderWidth.setVal (1);
+ styleAttrs.setBorderStyle (BORDER_OUTSET);
+ styleAttrs.padding.setVal (5);
+ styleAttrs.setBorderColor (Color::create (layout, 0x000000));
+ styleAttrs.color = Color::create (layout, 0x000000);
+
+ Style *boxStyle = Style::create (&styleAttrs);
+
+ styleAttrs.margin.setVal (0);
+ styleAttrs.borderWidth.setVal (0);
+ styleAttrs.padding.setVal (0);
+ styleAttrs.setBorderColor (Color::create (layout, 0x000000));
+ Style *labelStyle = Style::create (&styleAttrs);
+
+ VBox *box = new VBox (false);
+ box->setStyle (boxStyle);
+ layout->setWidget (box);
+
+ for (int i = 0; i < 100000; i++) {
+ char buf[32];
+ sprintf (buf, "Label №%d", i);
+ Label *label = new Label (buf);
+ label->setStyle (labelStyle);
+ box->addChild (label);
+ }
+
+ boxStyle->unref();
+ labelStyle->unref();
+
+ window->resizable(viewport);
+ window->show();
+ int errorCode = Fl::run();
+
+ delete layout;
+
+ return errorCode;
+}
diff --git a/tests/test_widgets_3.cc b/tests/test_widgets_3.cc
new file mode 100644
index 0000000..5329200
--- /dev/null
+++ b/tests/test_widgets_3.cc
@@ -0,0 +1,97 @@
+/*
+ * RTFL
+ *
+ * Copyright 2014, 2015 Sebastian Geerken <sgeerken@dillo.org>
+ *
+ * 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/>.
+ */
+
+#include <FL/Fl_Window.H>
+#include <FL/Fl.H>
+
+#include "dw/core.hh"
+#include "dw/fltkcore.hh"
+#include "dw/fltkviewport.hh"
+
+#include "dwr/vbox.hh"
+#include "dwr/label.hh"
+
+using namespace dw;
+using namespace dw::core;
+using namespace dw::core::style;
+using namespace dw::fltk;
+
+using namespace rtfl::dw;
+
+int main(int argc, char **argv)
+{
+ FltkPlatform *platform = new FltkPlatform ();
+ Layout *layout = new Layout (platform);
+
+ Fl_Window *window = new Fl_Window(500, 400, "Dw Example");
+ window->box(FL_NO_BOX);
+ window->begin();
+
+ FltkViewport *viewport = new FltkViewport (0, 0, 500, 400);
+ layout->attachView (viewport);
+
+ FontAttrs fontAttrs;
+ fontAttrs.name = "DejaVu Serif";
+ fontAttrs.size = 14;
+ fontAttrs.weight = 400;
+ fontAttrs.style = FONT_STYLE_NORMAL;
+ fontAttrs.letterSpacing = 0;
+ fontAttrs.fontVariant = FONT_VARIANT_NORMAL;
+
+ StyleAttrs styleAttrs;
+ styleAttrs.font = style::Font::create (layout, &fontAttrs);
+ styleAttrs.initValues ();
+ styleAttrs.margin.setVal (5);
+ styleAttrs.borderWidth.setVal (1);
+ styleAttrs.setBorderStyle (BORDER_OUTSET);
+ styleAttrs.padding.setVal (5);
+ styleAttrs.setBorderColor (Color::create (layout, 0x000000));
+ styleAttrs.color = Color::create (layout, 0x000000);
+
+ Style *boxStyle = Style::create (&styleAttrs);
+
+ styleAttrs.margin.setVal (0);
+ styleAttrs.borderWidth.setVal (0);
+ styleAttrs.padding.setVal (0);
+ styleAttrs.setBorderColor (Color::create (layout, 0x000000));
+ Style *labelStyle = Style::create (&styleAttrs);
+
+ VBox *box = new VBox (false);
+ box->setStyle (boxStyle);
+ layout->setWidget (box);
+
+ for (int i = 0; i < 1000; i++) {
+ char buf[32];
+ sprintf (buf, "Label №%d", i);
+ Label *label = new Label (buf);
+ label->setStyle (labelStyle);
+ box->addChild (label, i / 10);
+ }
+
+ boxStyle->unref();
+ labelStyle->unref();
+
+ window->resizable(viewport);
+ window->show();
+ int errorCode = Fl::run();
+
+ delete layout;
+
+ return errorCode;
+}
diff --git a/tests/testtools.cc b/tests/testtools.cc
new file mode 100644
index 0000000..175f482
--- /dev/null
+++ b/tests/testtools.cc
@@ -0,0 +1,49 @@
+#include "testtools.hh"
+#include "common/tools.hh"
+
+#include <unistd.h>
+
+using namespace rtfl::tools;
+
+namespace rtfl {
+
+namespace tests {
+
+int openPipe (const char *command)
+{
+ int pipefd[2];
+
+ if (pipe (pipefd) == -1)
+ syserr ("pipe failed");
+
+ switch (fork ()) {
+ case -1:
+ syserr ("fork failed");
+ break;
+
+ case 0:
+ if (close (pipefd[0]) == -1)
+ syserr ("close(%d) failed", pipefd[0]);
+ if (close (1) == -1)
+ syserr ("close(%d) failed", 1);
+ if (dup2 (pipefd[1], 1) == -1)
+ syserr ("dup2(%d, %d) failed", pipefd[1], 1);
+ if (close (pipefd[1]) == -1)
+ syserr ("close(%d) failed", pipefd[1]);
+ execlp ("sh", "sh", "-c", command, NULL);
+ syserr ("exec(\"%s\", \"%s\", \"%s\", \"%s\", NULL) failed",
+ "sh", "sh", "-c", command);
+ break;
+
+ default:
+ if (close (pipefd[1]) == -1)
+ syserr ("close(%d) failed", pipefd[1]);
+ return pipefd[0];
+ }
+
+ return -1;
+}
+
+} // namespace tests
+
+} // namespace rtfl
diff --git a/tests/testtools.hh b/tests/testtools.hh
new file mode 100644
index 0000000..77c52da
--- /dev/null
+++ b/tests/testtools.hh
@@ -0,0 +1,14 @@
+#ifndef __TESTS_TEST_TOOLS_HH__
+#define __TESTS_TEST_TOOLS_HH__
+
+namespace rtfl {
+
+namespace tests {
+
+int openPipe (const char *command);
+
+} // namespace tests
+
+} // namespace rtfl
+
+#endif // __TESTS_TEST_TOOLS_HH__