tkHTML-4ee7aaa953d6cb59000075500000000000000000000000001151224263100140365ustar00nobodynobodytkHTML-4ee7aaa953d6cb59/COMPILE.txt000064400000000000000000000132661151224263100157560ustar00nobodynobody This file has two sections: 1. How to compile the Tkhtml widget. 2. How to run Hv3, the Tkhtml web browser. -------------------------------------------------------------------------------- 1. HOW TO COMPILE THE TKHTML WIDGET There are two ways to build the Tkhtml widget: * Using the configure script. This is quick and easy if it works, virtually impossible to debug if it doesn't. * Modifying the Makefile template. This takes a few minutes to set up, but it's easier to understand what's going on. Both systems have been tested on Suse linux 9.2 and Mingw/Msys on Windows XP. Using the configure script -------------------------- 1. If you're reading this you have already obtained the sources and they are likely in a directory called "htmlwidget". 2. Create a new empty directory to build in. 3. Cd into the new directory. 4. Run the "configure" script located in the htmlwidget directory. The configure script will probably need the --with-tcl and --with-tk options passed to it. 5. Run "make". 6. If everything worked, run "make install". The sequence of commands might look like this: $ tar -xzf tkhtml-3.alpha1.tar.gz $ ls -o htmlwidget/configure -rwxr-xr-x 1 user 233035 2005-07-06 17:37 htmlwidget/configure $ mkdir bld $ cd bld $ ../htmlwidget/configure --with-tcl=/usr/local/ActiveTcl/lib --with-tk=/usr/local/ActiveTcl/lib $ make $ make install Modifying a Makefile template ----------------------------- There are two similar makefiles in the root directory of the source tree. "main.mk" is for linux, and "mingw.mk" is for Mingw/Msys on windows. Both require a handful of variables to be modified before they can be used. Instructions are in comments in either file. 1. If you're reading this you have already obtained the sources and they are likely in a directory called "htmlwidget". 2. Edit the appropriate makefile ("linux-gcc.mk" or "mingw.mk"). 2. Create a new empty directory to build in. 3. Cd into the new directory. 5. Run "make". 6. If everything worked, run "make install" (linux only). The sequence of commands might look like this: $ tar -xzf tkhtml-3.alpha1.tar.gz $ ls -o htmlwidget/main.mk -rw-r--r-- 1 dan 4143 2005-07-10 19:45 htmlwidget/main.mk $ vi htmlwidget/main.mk $ mkdir bld $ cd bld $ make -f ../htmlwidget/main.mk $ make install 2. HOW TO RUN HV3, THE TKHTML WEB BROWSER Hv3 uses the following compiled components: * Tkhtml3 * Tls * Img * Sqlite3 * tclsee (requires: SEE and optionally GC) Compiling Tclsee (javascript support) ------------------------------------- When Hv3 is run, it tries to load package "Tclsee". If successful, javascript support will be enabled. Tclsee is an extension developed as part of Hv3 to provide access to the "Simple ECMAScript Engine" (SEE) library from Tcl scripts. The SEE library depends on the Boehm garbage-collector libary. To build "Tclsee", the following third-party components are required: SEE: http://www.adaptive-enterprises.com.au/~d/software/see/ Boehm GC: http://www.hpl.hp.com/personal/Hans_Boehm/gc/ Libraries need to be built from these two packages (files libsee.a and libgc.a). Refer to the respective package documentation for details on how to do that. The SEE library should be configured to use Boehm GC routines by default. Then, file "hv/hv3see.c" from the source distribution should be compiled into a shared object linked with the two libraries above. The shared object will contain the binary extension "Tclsee" (C init function Tclsee_Init). The template makefiles (linux-gcc.mk and mingw.mk) include a target "tclsee" to build this package, complete with pkgIndex.tcl file. This target requires configuration of makefile variables JSLIB, JSFLAGS and JS_SHARED_LIB. Hints for compiling SEE: If Boehm GC is not in the various paths, need to set CFLAGS, LDFLAGS and LD_LIBRARY_PATH before running configure: INSTALL_PATH=/home/dan/work/tkhtml/js/ export CFLAGS="-I${INSTALL_PATH}/include/ -O2 -DNDEBUG" export LDFLAGS=-L${INSTALL_PATH}/lib/ export LD_LIBRARY_PATH=${INSTALL_PATH}/lib/ Then supply an installation path to configure: ../see-2.1.1206_snapshot/configure --prefix=${INSTALL_PATH}/ This worked on a stock Suse 10.1. Part of the target - "ssp" fails on linux. Run [make -k install] and you get both the shell and libary, so no problem... UPDATE: As of SEE version 2.1.1206, it looks like ssp is not built by default. Compiling hv3_polipo -------------------- TODO 3. NOTES FOR CROSS COMPILING One way to build Tkhtml3 and/or Hv3 for windows is to use a cross compiler from Linux using mingw. Binaries for the mingw gcc are available here: http://mirzam.it.vu.nl/mingw/ Note: If anyone reading this knows how to cross-compile from linux for mac, please tell me! (danielk1977@gmail.com) Both SEE and GC can be cross-compiled with a command like: ..//configure --host=i386-mingw32 --prefix= make make install Details: 1. In version 2.1.1206 of SEE, do the following to the configure script (pattern occurs twice): s/ac_cv_func_memcmp_working=no/ac_cv_func_memcmp_working=yes/ 2. I can't compile a working libgc for mingw. Same problem is reported by these folk (kaya scripting language): http://kayalang.org/download/compiling/windows For the starkits, I took their advice and downloaded a binary package. tkHTML-4ee7aaa953d6cb59/COPYING000064400000000000000000000616451151224263100151640ustar00nobodynobodyGNU LESSER GENERAL PUBLIC LICENSE Version 2.1, February 1999 Copyright (C) 1991, 1999 Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. [This is the first released version of the Lesser GPL. It also counts as the successor of the GNU Library Public License, version 2, hence the version number 2.1.] Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This license, the Lesser General Public License, applies to some specially designated software packages--typically libraries--of the Free Software Foundation and other authors who decide to use it. You can use it too, but we suggest you first think carefully about whether this license or the ordinary General Public License is the better strategy to use in any particular case, based on the explanations below. When we speak of free software, we are referring to freedom of use, 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 this service if you wish); that you receive source code or can get it if you want it; that you can change the software and use pieces of it in new free programs; and that you are informed that you can do these things. To protect your rights, we need to make restrictions that forbid distributors to deny you these rights or to ask you to surrender these rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library or if you modify it. For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link other code with the library, you must provide complete object files to the recipients, so that they can relink them with the library after making changes to the library and recompiling it. And you must show them these terms so they know their rights. We protect your rights with a two-step method: (1) we copyright the library, and (2) we offer you this license, which gives you legal permission to copy, distribute and/or modify the library. To protect each distributor, we want to make it very clear that there is no warranty for the free library. Also, if the library is modified by someone else and passed on, the recipients should know that what they have is not the original version, so that the original author's reputation will not be affected by problems that might be introduced by others. Finally, software patents pose a constant threat to the existence of any free program. We wish to make sure that a company cannot effectively restrict the users of a free program by obtaining a restrictive license from a patent holder. Therefore, we insist that any patent license obtained for a version of the library must be consistent with the full freedom of use specified in this license. Most GNU software, including some libraries, is covered by the ordinary GNU General Public License. This license, the GNU Lesser General Public License, applies to certain designated libraries, and is quite different from the ordinary General Public License. We use this license for certain libraries in order to permit linking those libraries into non-free programs. When a program is linked with a library, whether statically or using a shared library, the combination of the two is legally speaking a combined work, a derivative of the original library. The ordinary General Public License therefore permits such linking only if the entire combination fits its criteria of freedom. The Lesser General Public License permits more lax criteria for linking other code with the library. We call this license the "Lesser" General Public License because it does Less to protect the user's freedom than the ordinary General Public License. It also provides other free software developers Less of an advantage over competing non-free programs. These disadvantages are the reason we use the ordinary General Public License for many libraries. However, the Lesser license provides advantages in certain special circumstances. For example, on rare occasions, there may be a special need to encourage the widest possible use of a certain library, so that it becomes a de-facto standard. To achieve this, non-free programs must be allowed to use the library. A more frequent case is that a free library does the same job as widely used non-free libraries. In this case, there is little to gain by limiting the free library to free software only, so we use the Lesser General Public License. In other cases, permission to use a particular library in non-free programs enables a greater number of people to use a large body of free software. For example, permission to use the GNU C Library in non-free programs enables many more people to use the whole GNU operating system, as well as its variant, the GNU/Linux operating system. Although the Lesser General Public License is Less protective of the users' freedom, it does ensure that the user of a program that is linked with the Library has the freedom and the wherewithal to run that program using a modified version of the Library. The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, whereas the latter must be combined with the library in order to run. TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any software library or other program which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Lesser General Public License (also called "this License"). Each licensee is addressed as "you". A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables. The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".) "Source code" for a work means the preferred form of the work for making modifications to it. For a library, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the library. Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does. 1. You may copy and distribute verbatim copies of the Library's complete source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and distribute a copy of this License along with the Library. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Library or any portion of it, thus forming a work based on the Library, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: * a) The modified work must itself be a software library. * b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change. * c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License. * d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful. (For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Library, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Library. In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. This option is useful when you wish to copy part of the code of the Library into a program that is not a library. 4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange. If distribution of object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code. 5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License. However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables. When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law. If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.) Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. 6. As an exception to the Sections above, you may also combine or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications. You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things: * a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.) * b) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (1) uses at run time a copy of the library already present on the user's computer system, rather than copying library functions into the executable, and (2) will operate properly with a modified version of the library, if the user installs one, as long as the modified version is interface-compatible with the version that the work was made with. * c) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution. * d) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place. * e) Verify that the user has already received a copy of these materials or that you have already sent this user a copy. For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the materials to be distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. 7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things: * a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above. * b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 9. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it. 10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties with this License. 11. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), 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 distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Library. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply, and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 13. The Free Software Foundation may publish revised and/or new versions of the Lesser 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 Library specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. 14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "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 LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE LIBRARY 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 LIBRARY (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 LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS tkHTML-4ee7aaa953d6cb59/COPYING.html000064400000000000000000000614561151224263100161270ustar00nobodynobody

GNU LESSER GENERAL PUBLIC LICENSE

Version 2.1, February 1999

Copyright (C) 1991, 1999 Free Software Foundation, Inc.
59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.

[This is the first released version of the Lesser GPL.  It also counts
 as the successor of the GNU Library Public License, version 2, hence
 the version number 2.1.]

Preamble

The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users.

This license, the Lesser General Public License, applies to some specially designated software packages--typically libraries--of the Free Software Foundation and other authors who decide to use it. You can use it too, but we suggest you first think carefully about whether this license or the ordinary General Public License is the better strategy to use in any particular case, based on the explanations below.

When we speak of free software, we are referring to freedom of use, 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 this service if you wish); that you receive source code or can get it if you want it; that you can change the software and use pieces of it in new free programs; and that you are informed that you can do these things.

To protect your rights, we need to make restrictions that forbid distributors to deny you these rights or to ask you to surrender these rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library or if you modify it.

For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link other code with the library, you must provide complete object files to the recipients, so that they can relink them with the library after making changes to the library and recompiling it. And you must show them these terms so they know their rights.

We protect your rights with a two-step method: (1) we copyright the library, and (2) we offer you this license, which gives you legal permission to copy, distribute and/or modify the library.

To protect each distributor, we want to make it very clear that there is no warranty for the free library. Also, if the library is modified by someone else and passed on, the recipients should know that what they have is not the original version, so that the original author's reputation will not be affected by problems that might be introduced by others.

Finally, software patents pose a constant threat to the existence of any free program. We wish to make sure that a company cannot effectively restrict the users of a free program by obtaining a restrictive license from a patent holder. Therefore, we insist that any patent license obtained for a version of the library must be consistent with the full freedom of use specified in this license.

Most GNU software, including some libraries, is covered by the ordinary GNU General Public License. This license, the GNU Lesser General Public License, applies to certain designated libraries, and is quite different from the ordinary General Public License. We use this license for certain libraries in order to permit linking those libraries into non-free programs.

When a program is linked with a library, whether statically or using a shared library, the combination of the two is legally speaking a combined work, a derivative of the original library. The ordinary General Public License therefore permits such linking only if the entire combination fits its criteria of freedom. The Lesser General Public License permits more lax criteria for linking other code with the library.

We call this license the "Lesser" General Public License because it does Less to protect the user's freedom than the ordinary General Public License. It also provides other free software developers Less of an advantage over competing non-free programs. These disadvantages are the reason we use the ordinary General Public License for many libraries. However, the Lesser license provides advantages in certain special circumstances.

For example, on rare occasions, there may be a special need to encourage the widest possible use of a certain library, so that it becomes a de-facto standard. To achieve this, non-free programs must be allowed to use the library. A more frequent case is that a free library does the same job as widely used non-free libraries. In this case, there is little to gain by limiting the free library to free software only, so we use the Lesser General Public License.

In other cases, permission to use a particular library in non-free programs enables a greater number of people to use a large body of free software. For example, permission to use the GNU C Library in non-free programs enables many more people to use the whole GNU operating system, as well as its variant, the GNU/Linux operating system.

Although the Lesser General Public License is Less protective of the users' freedom, it does ensure that the user of a program that is linked with the Library has the freedom and the wherewithal to run that program using a modified version of the Library.

The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, whereas the latter must be combined with the library in order to run.

TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION

0. This License Agreement applies to any software library or other program which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Lesser General Public License (also called "this License"). Each licensee is addressed as "you".

A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables.

The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".)

"Source code" for a work means the preferred form of the work for making modifications to it. For a library, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the library.

Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does.

1. You may copy and distribute verbatim copies of the Library's complete source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and distribute a copy of this License along with the Library.

You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee.

2. You may modify your copy or copies of the Library or any portion of it, thus forming a work based on the Library, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions:

  • a) The modified work must itself be a software library.
  • b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change.
  • c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License.
  • d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful.

    (For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.)

    These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Library, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it.

    Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Library.

    In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License.

3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices.

Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy.

This option is useful when you wish to copy part of the code of the Library into a program that is not a library.

4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange.

If distribution of object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code.

5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License.

However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables.

When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law.

If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.)

Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself.

6. As an exception to the Sections above, you may also combine or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications.

You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things:

  • a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.)
  • b) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (1) uses at run time a copy of the library already present on the user's computer system, rather than copying library functions into the executable, and (2) will operate properly with a modified version of the library, if the user installs one, as long as the modified version is interface-compatible with the version that the work was made with.
  • c) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution.
  • d) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place.
  • e) Verify that the user has already received a copy of these materials or that you have already sent this user a copy.

For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the materials to be distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable.

It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute.

7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things:

  • a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above.
  • b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work.

8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance.

9. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it.

10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties with this License.

11. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), 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 distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Library.

If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply, and the section as a whole is intended to apply in other circumstances.

It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice.

This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License.

12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License.

13. The Free Software Foundation may publish revised and/or new versions of the Lesser 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 Library specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation.

14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally.

NO WARRANTY

15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "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 LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.

16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE LIBRARY 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 LIBRARY (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 LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.

END OF TERMS AND CONDITIONS

tkHTML-4ee7aaa953d6cb59/COPYRIGHT000064400000000000000000000031261151224263100154120ustar00nobodynobodyCopyright (c) 2005 Dan Kennedy. All rights reserved. This Open Source project was made possible through the financial support of Eolas Technologies Inc. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of Eolas Technologies Inc. nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. tkHTML-4ee7aaa953d6cb59/ChangeLog000064400000000000000000000011311151224263100156630ustar00nobodynobody 2006-02-25 * 3.0 Alpha 2 release. 2002-09-27 Andreas Kupries * doc/spec.html: Added two paragraph markers for paragraphs without. * src/htmltcl.c (lockcopycmd): Extended to handle HPUX and AIX. * src/htmlform.c (HtmlFormIdx, HtmlAddFormInfo): See below, this time branches in a switch. * src/htmlwidget.c (TclConfigureWidgetObj, TclConfigureWidget): Fixed syntax, HP compilers do not like label without any statement after them. Inserted semantically no-op to satisfy these demands. * started a regular change log. tkHTML-4ee7aaa953d6cb59/Makefile.in000064400000000000000000000423561151224263100161740ustar00nobodynobody# Makefile.in -- # # This file is a Makefile for Sample TEA Extension. If it has the name # "Makefile.in" then it is a template for a Makefile; to generate the # actual Makefile, run "./configure", which is a configuration script # generated by the "autoconf" program (constructs like "@foo@" will get # replaced in the actual Makefile. # # Copyright (c) 1999 Scriptics Corporation. # Copyright (c) 2002-2005 ActiveState Corporation. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. # # RCS: @(#) $Id: Makefile.in,v 1.35 2008/03/02 15:00:13 danielk1977 Exp $ #======================================================================== # Add additional lines to handle any additional AC_SUBST cases that # have been added in a customized configure script. #======================================================================== #SAMPLE_NEW_VAR = @SAMPLE_NEW_VAR@ #======================================================================== # Nothing of the variables below this line should need to be changed. # Please check the TARGETS section below to make sure the make targets # are correct. #======================================================================== #======================================================================== # The names of the source files is defined in the configure script. # The object files are used for linking into the final library. # This will be used when a dist target is added to the Makefile. # It is not important to specify the directory, as long as it is the # $(srcdir) or in the generic, win or unix subdirectory. #======================================================================== PKG_SOURCES = @PKG_SOURCES@ PKG_OBJECTS = @PKG_OBJECTS@ cssprop.$(OBJEXT) PKG_STUB_SOURCES = @PKG_STUB_SOURCES@ PKG_STUB_OBJECTS = @PKG_STUB_OBJECTS@ #======================================================================== # PKG_TCL_SOURCES identifies Tcl runtime files that are associated with # this package that need to be installed, if any. #======================================================================== PKG_TCL_SOURCES = @PKG_TCL_SOURCES@ #======================================================================== # This is a list of public header files to be installed, if any. #======================================================================== PKG_HEADERS = @PKG_HEADERS@ #======================================================================== # "PKG_LIB_FILE" refers to the library (dynamic or static as per # configuration options) composed of the named objects. #======================================================================== PKG_LIB_FILE = @PKG_LIB_FILE@ PKG_STUB_LIB_FILE = @PKG_STUB_LIB_FILE@ lib_BINARIES = $(PKG_LIB_FILE) BINARIES = $(lib_BINARIES) html.css SHELL = @SHELL@ srcdir = @srcdir@ prefix = @prefix@ exec_prefix = @exec_prefix@ bindir = @bindir@ libdir = @libdir@ datadir = @datadir@ mandir = @mandir@ includedir = @includedir@ DESTDIR = PKG_DIR = $(PACKAGE_NAME)$(PACKAGE_VERSION) pkgdatadir = $(datadir)/$(PKG_DIR) pkglibdir = $(libdir)/$(PKG_DIR) pkgincludedir = $(includedir)/$(PKG_DIR) top_builddir = . INSTALL = @INSTALL@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_VERSION = @PACKAGE_VERSION@ CC = @CC@ CFLAGS_DEFAULT = @CFLAGS_DEFAULT@ CFLAGS_WARNING = @CFLAGS_WARNING@ CLEANFILES = @CLEANFILES@ EXEEXT = @EXEEXT@ LDFLAGS_DEFAULT = @LDFLAGS_DEFAULT@ MAKE_LIB = @MAKE_LIB@ MAKE_SHARED_LIB = @MAKE_SHARED_LIB@ MAKE_STATIC_LIB = @MAKE_STATIC_LIB@ MAKE_STUB_LIB = @MAKE_STUB_LIB@ OBJEXT = @OBJEXT@ RANLIB = @RANLIB@ RANLIB_STUB = @RANLIB_STUB@ SHLIB_CFLAGS = @SHLIB_CFLAGS@ SHLIB_LD = @SHLIB_LD@ SHLIB_LD_LIBS = @SHLIB_LD_LIBS@ STLIB_LD = @STLIB_LD@ #TCL_DEFS = @TCL_DEFS@ TCL_BIN_DIR = @TCL_BIN_DIR@ TCL_SRC_DIR = @TCL_SRC_DIR@ TK_BIN_DIR = @TK_BIN_DIR@ TK_SRC_DIR = @TK_SRC_DIR@ # Not used, but retained for reference of what libs Tcl required #TCL_LIBS = @TCL_LIBS@ #======================================================================== # TCLLIBPATH seeds the auto_path in Tcl's init.tcl so we can test our # package without installing. The other environment variables allow us # to test against an uninstalled Tcl. Add special env vars that you # require for testing here (like TCLX_LIBRARY). #======================================================================== #EXTRA_PATH = $(top_builddir):$(TCL_BIN_DIR) EXTRA_PATH = $(top_builddir):$(TCL_BIN_DIR):$(TK_BIN_DIR) TCLLIBPATH = $(top_builddir) TCLSH_ENV = TCL_LIBRARY=`@CYGPATH@ $(TCL_SRC_DIR)/library` \ @LD_LIBRARY_PATH_VAR@="$(EXTRA_PATH):$(@LD_LIBRARY_PATH_VAR@)" \ PATH="$(EXTRA_PATH):$(PATH)" \ TCLLIBPATH="$(TCLLIBPATH)" # TK_LIBRARY=`@CYGPATH@ $(TK_SRC_DIR)/library` TCLSH_PROG = @TCLSH_PROG@ TCLSH = $(TCLSH_ENV) $(TCLSH_PROG) WISH_PROG = @WISH_PROG@ WISH = $(TCLSH_ENV) $(WISH_PROG) SHARED_BUILD = @SHARED_BUILD@ #INCLUDES = @PKG_INCLUDES@ @TCL_INCLUDES@ INCLUDES = @PKG_INCLUDES@ @TCL_INCLUDES@ @TK_INCLUDES@ @TK_XINCLUDES@ PKG_CFLAGS = @PKG_CFLAGS@ # TCL_DEFS is not strictly need here, but if you remove it, then you # must make sure that configure.in checks for the necessary components # that your library may use. TCL_DEFS can actually be a problem if # you do not compile with a similar machine setup as the Tcl core was # compiled with. #DEFS = $(TCL_DEFS) @DEFS@ $(PKG_CFLAGS) DEFS = @DEFS@ $(PKG_CFLAGS) CONFIG_CLEAN_FILES = Makefile CPPFLAGS = @CPPFLAGS@ LIBS = @PKG_LIBS@ @LIBS@ AR = @AR@ CFLAGS = @CFLAGS@ COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) #======================================================================== # Start of user-definable TARGETS section #======================================================================== #======================================================================== # TEA TARGETS. Please note that the "libraries:" target refers to platform # independent files, and the "binaries:" target inclues executable programs and # platform-dependent libraries. Modify these targets so that they install # the various pieces of your package. The make and install rules # for the BINARIES that you specified above have already been done. #======================================================================== all: binaries libraries doc #======================================================================== # The binaries target builds executable programs, Windows .dll's, unix # shared/static libraries, and any other platform-dependent files. # The list of targets to build for "binaries:" is specified at the top # of the Makefile, in the "BINARIES" variable. #======================================================================== binaries: $(BINARIES) pkgIndex.tcl HV3_VERSION = 0.1 HV3_LIB = hv3-$(HV3_VERSION).tm HV3_TCL_SOURCE = \ $(srcdir)/hv/hv3_util.tcl \ $(srcdir)/hv/hv3.tcl \ $(srcdir)/hv/hv3_encodings.tcl \ $(srcdir)/hv/hv3_form.tcl \ $(srcdir)/hv/hv3_request.tcl $(HV3_LIB): $(HV3_TCL_SOURCE) echo "package provide $(HV3_LIB)" > $@ cat $(HV3_TCL_SOURCE) >> $@ libraries: $(HV3_LIB) #======================================================================== # Your doc target should differentiate from doc builds (by the developer) # and doc installs (see install-doc), which just install the docs on the # end user machine when building from source. #======================================================================== doc: $(TCLSH) $(srcdir)/doc/macros.tcl -nroff $(srcdir)/doc/html.man>tkhtml.n install: all install-binaries install-libraries install-doc install-binaries: binaries install-lib-binaries install-bin-binaries #======================================================================== # This rule installs platform-independent files, such as header files. # The list=...; for p in $$list handles the empty list case x-platform. #======================================================================== install-libraries: libraries @mkdir -p $(DESTDIR)$(includedir) @echo "Installing header files in $(DESTDIR)$(includedir)" @list='$(PKG_HEADERS)'; for i in $$list; do \ echo "Installing $(srcdir)/$$i" ; \ $(INSTALL_DATA) $(srcdir)/$$i $(DESTDIR)$(includedir) ; \ done; echo "Installing $(HV3_LIB)" @$(INSTALL_DATA) $(HV3_LIB) $(DESTDIR)$(pkglibdir) #======================================================================== # Install documentation. Unix manpages should go in the $(mandir) # directory. #======================================================================== install-doc: doc @mkdir -p $(DESTDIR)$(mandir)/mann @echo "Installing documentation in $(DESTDIR)$(mandir)" @list='*.n'; for i in $$list; do \ echo "Installing $$i"; \ rm -f $(DESTDIR)$(mandir)/mann/`basename $$i`; \ $(INSTALL_DATA) $$i $(DESTDIR)$(mandir)/mann ; \ done test: binaries libraries $(WISH) `@CYGPATH@ $(srcdir)/tests/all.tcl` $(TESTFLAGS) # "inttest" is a custom target to run the interactive tests for the widget. inttest: binaries libraries $(TCLSH) `@CYGPATH@ $(srcdir)/tests/interactive.tcl` $(TESTFLAGS) shell: binaries libraries @$(TCLSH) $(SCRIPT) gdb: $(TCLSH_ENV) gdb $(TCLSH_PROG) $(SCRIPT) depend: #======================================================================== # $(PKG_LIB_FILE) should be listed as part of the BINARIES variable # mentioned above. That will ensure that this target is built when you # run "make binaries". # # The $(PKG_OBJECTS) objects are created and linked into the final # library. In most cases these object files will correspond to the # source files above. #======================================================================== $(PKG_LIB_FILE): $(PKG_OBJECTS) -rm -f $(PKG_LIB_FILE) ${MAKE_LIB} $(RANLIB) $(PKG_LIB_FILE) $(PKG_STUB_LIB_FILE): $(PKG_STUB_OBJECTS) -rm -f $(PKG_STUB_LIB_FILE) ${MAKE_STUB_LIB} $(RANLIB_STUB) $(PKG_STUB_LIB_FILE) #======================================================================== # We need to enumerate the list of .c to .o lines here. # # In the following lines, $(srcdir) refers to the toplevel directory # containing your extension. If your sources are in a subdirectory, # you will have to modify the paths to reflect this: # # sample.$(OBJEXT): $(srcdir)/generic/sample.c # $(COMPILE) -c `@CYGPATH@ $(srcdir)/generic/sample.c` -o $@ # # Setting the VPATH variable to a list of paths will cause the makefile # to look into these paths when resolving .c to .obj dependencies. # As necessary, add $(srcdir):$(srcdir)/compat:.... #======================================================================== VPATH = $(srcdir):$(srcdir)/src:$(srcdir)/unix:$(srcdir)/win:. HEADERS = html.h cssInt.h css.h cssprop.h htmltokens.h htmldefaultstyle.c HDR = $(GENHDR) $(SRCHDR) %.@OBJEXT@: %.c $(HEADERS) $(COMPILE) -c -I. -I$(srcdir)/src `@CYGPATH@ $<` -o $@ #======================================================================== # The special targets to generate C code from tcl and lemon files are # here: htmltokens.c: $(srcdir)/src/tokenlist.txt $(TCLSH) $? htmldefaultstyle.c: $(srcdir)/src/tkhtml.tcl $(srcdir)/src/html.css \ $(srcdir)/src/mkdefaultstyle.tcl $(TCLSH) $(srcdir)/src/mkdefaultstyle.tcl > htmldefaultstyle.c htmltokens.h: htmltokens.c cssprop.h: cssprop.tcl $(TCLSH) $? cssprop.c: cssprop.h #======================================================================== # Create the pkgIndex.tcl file. # It is usually easiest to let Tcl do this for you with pkg_mkIndex, but # you may find that you need to customize the package. If so, either # modify the -hand version, or create a pkgIndex.tcl.in file and have # the configure script output the pkgIndex.tcl by editing configure.in. #======================================================================== # pkgIndex.tcl: $(PKG_LIB_FILE) # ( echo pkg_mkIndex -load Tk . \; exit; ) | $(WISH) pkgIndex.tcl: echo 'package ifneeded $(PACKAGE_NAME) $(PACKAGE_VERSION) [list load [file join $$dir $(PKG_LIB_FILE)]]' > pkgIndex.tcl echo 'package ifneeded hv3 $(HV3_VERSION) [list source [file join $$dir $(HV3_LIB)]]' >> pkgIndex.tcl #======================================================================== # Distribution creation # You may need to tweak this target to make it work correctly. #======================================================================== #COMPRESS = tar cvf $(PKG_DIR).tar $(PKG_DIR); compress $(PKG_DIR).tar COMPRESS = gtar zcvf $(PKG_DIR).tar.gz $(PKG_DIR) DIST_ROOT = /tmp/dist DIST_DIR = $(DIST_ROOT)/$(PKG_DIR) dist-clean: rm -rf $(DIST_DIR) $(DIST_ROOT)/$(PKG_DIR).tar.* dist: dist-clean mkdir -p $(DIST_DIR) cp -p $(srcdir)/ChangeLog $(srcdir)/README* $(srcdir)/license* \ $(srcdir)/aclocal.m4 $(srcdir)/configure $(srcdir)/*.in \ $(DIST_DIR)/ chmod 664 $(DIST_DIR)/Makefile.in $(DIST_DIR)/aclocal.m4 chmod 775 $(DIST_DIR)/configure $(DIST_DIR)/configure.in for i in $(srcdir)/*.[ch]; do \ if [ -f $$i ]; then \ cp -p $$i $(DIST_DIR)/ ; \ fi; \ done; mkdir $(DIST_DIR)/tclconfig cp $(srcdir)/tclconfig/install-sh $(srcdir)/tclconfig/tcl.m4 \ $(DIST_DIR)/tclconfig/ chmod 664 $(DIST_DIR)/tclconfig/tcl.m4 chmod +x $(DIST_DIR)/tclconfig/install-sh list='demos doc src library mac tests unix win'; \ for p in $$list; do \ if test -d $(srcdir)/$$p ; then \ mkdir $(DIST_DIR)/$$p; \ cp -p $(srcdir)/$$p/*.* $(DIST_DIR)/$$p/; \ fi; \ done (cd $(DIST_ROOT); $(COMPRESS);) #======================================================================== # End of user-definable section #======================================================================== #======================================================================== # Don't modify the file to clean here. Instead, set the "CLEANFILES" # variable in configure.in #======================================================================== clean: -test -z "$(BINARIES)" || rm -f $(BINARIES) -rm -f *.$(OBJEXT) core *.core -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) distclean: clean -rm -f *.tab.c -rm -f $(CONFIG_CLEAN_FILES) -rm -f config.cache config.log config.status #======================================================================== # Install binary object libraries. On Windows this includes both .dll and # .lib files. Because the .lib files are not explicitly listed anywhere, # we need to deduce their existence from the .dll file of the same name. # Library files go into the lib directory. # In addition, this will generate the pkgIndex.tcl # file in the install location (assuming it can find a usable tclsh shell) # # You should not have to modify this target. #======================================================================== install-lib-binaries: binaries @mkdir -p $(DESTDIR)$(pkglibdir) @list='$(lib_BINARIES)'; for p in $$list; do \ if test -f $$p; then \ echo " $(INSTALL_PROGRAM) $$p $(DESTDIR)$(pkglibdir)/$$p"; \ $(INSTALL_PROGRAM) $$p $(DESTDIR)$(pkglibdir)/$$p; \ stub=`echo $$p|sed -e "s/.*\(stub\).*/\1/"`; \ if test "x$$stub" = "xstub"; then \ echo " $(RANLIB_STUB) $(DESTDIR)$(pkglibdir)/$$p"; \ $(RANLIB_STUB) $(DESTDIR)$(pkglibdir)/$$p; \ else \ echo " $(RANLIB) $(DESTDIR)$(pkglibdir)/$$p"; \ $(RANLIB) $(DESTDIR)$(pkglibdir)/$$p; \ fi; \ ext=`echo $$p|sed -e "s/.*\.//"`; \ if test "x$$ext" = "xdll"; then \ lib=`basename $$p|sed -e 's/.[^.]*$$//'`.lib; \ if test -f $$lib; then \ echo " $(INSTALL_DATA) $$lib $(DESTDIR)$(pkglibdir)/$$lib"; \ $(INSTALL_DATA) $$lib $(DESTDIR)$(pkglibdir)/$$lib; \ fi; \ fi; \ fi; \ done @list='$(PKG_TCL_SOURCES)'; for p in $$list; do \ if test -f $(srcdir)/$$p; then \ destp=`basename $$p`; \ echo " Install $$destp $(DESTDIR)$(pkglibdir)/$$destp"; \ $(INSTALL_DATA) $(srcdir)/$$p $(DESTDIR)$(pkglibdir)/$$destp; \ fi; \ done @if test "x$(SHARED_BUILD)" = "x1"; then \ echo " Install pkgIndex.tcl $(DESTDIR)$(pkglibdir)"; \ $(INSTALL_DATA) pkgIndex.tcl $(DESTDIR)$(pkglibdir); \ fi #======================================================================== # Install binary executables (e.g. .exe files and dependent .dll files) # This is for files that must go in the bin directory (located next to # wish and tclsh), like dependent .dll files on Windows. # # You should not have to modify this target, except to define bin_BINARIES # above if necessary. #======================================================================== install-bin-binaries: binaries @mkdir -p $(DESTDIR)$(bindir) @list='$(bin_BINARIES)'; for p in $$list; do \ if test -f $$p; then \ echo " $(INSTALL_PROGRAM) $$p $(DESTDIR)$(bindir)/$$p"; \ $(INSTALL_PROGRAM) $$p $(DESTDIR)$(bindir)/$$p; \ fi; \ done .SUFFIXES: .c .$(OBJEXT) Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status cd $(top_builddir) \ && CONFIG_FILES=$@ CONFIG_HEADERS= $(SHELL) ./config.status uninstall-binaries: list='$(lib_BINARIES)'; for p in $$list; do \ rm -f $(DESTDIR)$(pkglibdir)/$$p; \ done list='$(PKG_TCL_SOURCES)'; for p in $$list; do \ p=`basename $$p`; \ rm -f $(DESTDIR)$(pkglibdir)/$$p; \ done list='$(bin_BINARIES)'; for p in $$list; do \ rm -f $(DESTDIR)$(bindir)/$$p; \ done .PHONY: all binaries clean depend distclean doc install libraries test # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: tkHTML-4ee7aaa953d6cb59/README000064400000000000000000000006331151224263100147770ustar00nobodynobodyThis directory contains all source code files for the TkHtml widget. TkHtml renders HTML for Tcl/Tk 8.0 and later. COMPILE.txt Instructions on how to compile TkHtml. doc Other documentation about TkHtml. src All of the source code. tools Source code to tools that are used to build the widget but which do not become part of the widget. tkHTML-4ee7aaa953d6cb59/aclocal.m4000064400000000000000000000002231151224263100157520ustar00nobodynobody# # Include the TEA standard macro set # builtin(include,tclconfig/tcl.m4) # # Add here whatever m4 macros you want to define for your package # tkHTML-4ee7aaa953d6cb59/configure000075500000000000000000013003411151224263100160260ustar00nobodynobody#! /bin/sh # Guess values for system-dependent variables and create Makefiles. # Generated by GNU Autoconf 2.59 for Tkhtml 3.0. # # Copyright (C) 2003 Free Software Foundation, Inc. # This configure script is free software; the Free Software Foundation # gives unlimited permission to copy, distribute and modify it. ## --------------------- ## ## M4sh Initialization. ## ## --------------------- ## # 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+"$@"}'='"$@"' elif test -n "${BASH_VERSION+set}" && (set -o posix) >/dev/null 2>&1; then set -o posix fi DUALCASE=1; export DUALCASE # for MKS sh # Support unset when possible. if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then as_unset=unset else as_unset=false fi # Work around bugs in pre-3.0 UWIN ksh. $as_unset ENV MAIL MAILPATH PS1='$ ' PS2='> ' PS4='+ ' # NLS nuisances. for as_var in \ LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION \ LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \ LC_TELEPHONE LC_TIME do if (set +x; test -z "`(eval $as_var=C; export $as_var) 2>&1`"); then eval $as_var=C; export $as_var else $as_unset $as_var fi done # Required to use basename. if expr a : '\(a\)' >/dev/null 2>&1; then as_expr=expr else as_expr=false fi if (basename /) >/dev/null 2>&1 && test "X`basename / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi # Name of the executable. as_me=`$as_basename "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)$' \| \ . : '\(.\)' 2>/dev/null || echo X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/; q; } /^X\/\(\/\/\)$/{ s//\1/; q; } /^X\/\(\/\).*/{ s//\1/; q; } s/.*/./; q'` # PATH needs CR, and LINENO needs CR and PATH. # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then echo "#! /bin/sh" >conf$$.sh echo "exit 0" >>conf$$.sh chmod +x conf$$.sh if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then PATH_SEPARATOR=';' else PATH_SEPARATOR=: fi rm -f conf$$.sh fi as_lineno_1=$LINENO as_lineno_2=$LINENO as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null` test "x$as_lineno_1" != "x$as_lineno_2" && test "x$as_lineno_3" = "x$as_lineno_2" || { # Find who we are. Look in the path if we contain no path at all # relative or not. case $0 in *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break done ;; esac # We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then { echo "$as_me: error: cannot find myself; rerun with an absolute path" >&2 { (exit 1); exit 1; }; } fi case $CONFIG_SHELL in '') as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for as_base in sh bash ksh sh5; do case $as_dir in /*) if ("$as_dir/$as_base" -c ' as_lineno_1=$LINENO as_lineno_2=$LINENO as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null` test "x$as_lineno_1" != "x$as_lineno_2" && test "x$as_lineno_3" = "x$as_lineno_2" ') 2>/dev/null; then $as_unset BASH_ENV || test "${BASH_ENV+set}" != set || { BASH_ENV=; export BASH_ENV; } $as_unset ENV || test "${ENV+set}" != set || { ENV=; export ENV; } CONFIG_SHELL=$as_dir/$as_base export CONFIG_SHELL exec "$CONFIG_SHELL" "$0" ${1+"$@"} fi;; esac done done ;; esac # Create $as_me.lineno as a copy of $as_myself, but with $LINENO # uniformly replaced by the line number. The first 'sed' inserts a # line-number line before each line; the second 'sed' does the real # work. The second script uses 'N' to pair each line-number line # with the numbered line, and appends trailing '-' during # substitution so that $LINENO is not a special case at line end. # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the # second 'sed' script. Blame Lee E. McMahon for sed's syntax. :-) sed '=' <$as_myself | sed ' N s,$,-, : loop s,^\(['$as_cr_digits']*\)\(.*\)[$]LINENO\([^'$as_cr_alnum'_]\),\1\2\1\3, t loop s,-$,, s,^['$as_cr_digits']*\n,, ' >$as_me.lineno && chmod +x $as_me.lineno || { echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2 { (exit 1); exit 1; }; } # Don't try to exec as it changes $[0], causing all sort of problems # (the dirname of $[0] is not the place where we might find the # original and so on. Autoconf is especially sensible to this). . ./$as_me.lineno # Exit status is that of the last command. exit } case `echo "testing\c"; echo 1,2,3`,`echo -n testing; echo 1,2,3` in *c*,-n*) ECHO_N= ECHO_C=' ' ECHO_T=' ' ;; *c*,* ) ECHO_N=-n ECHO_C= ECHO_T= ;; *) ECHO_N= ECHO_C='\c' ECHO_T= ;; esac if expr a : '\(a\)' >/dev/null 2>&1; then as_expr=expr else as_expr=false fi rm -f conf$$ conf$$.exe conf$$.file echo >conf$$.file if ln -s conf$$.file conf$$ 2>/dev/null; then # We could just check for DJGPP; but this test a) works b) is more generic # and c) will remain valid once DJGPP supports symlinks (DJGPP 2.04). if test -f conf$$.exe; then # Don't use ln at all; we don't have any links as_ln_s='cp -p' else as_ln_s='ln -s' fi elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -p' fi rm -f conf$$ conf$$.exe conf$$.file if mkdir -p . 2>/dev/null; then as_mkdir_p=: else test -d ./-p && rmdir ./-p as_mkdir_p=false fi as_executable_p="test -f" # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" # IFS # We need space, tab and new line, in precisely that order. as_nl=' ' IFS=" $as_nl" # CDPATH. $as_unset CDPATH # Name of the host. # hostname on some systems (SVR3.2, Linux) returns a bogus exit status, # so uname gets run too. ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` exec 6>&1 # # Initializations. # ac_default_prefix=/usr/local ac_config_libobj_dir=. cross_compiling=no subdirs= MFLAGS= MAKEFLAGS= SHELL=${CONFIG_SHELL-/bin/sh} # Maximum number of lines to put in a shell here document. # This variable seems obsolete. It should probably be removed, and # only ac_max_sed_lines should be used. : ${ac_max_here_lines=38} # Identity of this package. PACKAGE_NAME='Tkhtml' PACKAGE_TARNAME='tkhtml' PACKAGE_VERSION='3.0' PACKAGE_STRING='Tkhtml 3.0' PACKAGE_BUGREPORT='' # Factoring default headers for most tests. ac_includes_default="\ #include #if HAVE_SYS_TYPES_H # include #endif #if HAVE_SYS_STAT_H # include #endif #if STDC_HEADERS # include # include #else # if HAVE_STDLIB_H # include # endif #endif #if HAVE_STRING_H # if !STDC_HEADERS && HAVE_MEMORY_H # include # endif # include #endif #if HAVE_STRINGS_H # include #endif #if HAVE_INTTYPES_H # include #else # if HAVE_STDINT_H # include # endif #endif #if HAVE_UNISTD_H # include #endif" ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS CYGPATH EXEEXT PKG_LIB_FILE PKG_STUB_LIB_FILE PKG_STUB_SOURCES PKG_STUB_OBJECTS PKG_TCL_SOURCES PKG_HEADERS PKG_INCLUDES PKG_LIBS PKG_CFLAGS TCL_VERSION TCL_BIN_DIR TCL_SRC_DIR TCL_LIB_FILE TCL_LIB_FLAG TCL_LIB_SPEC TCL_STUB_LIB_FILE TCL_STUB_LIB_FLAG TCL_STUB_LIB_SPEC TCL_LIBS TCL_DEFS TCL_EXTRA_CFLAGS TCL_LD_FLAGS TCL_SHLIB_LD_LIBS TK_VERSION TK_BIN_DIR TK_SRC_DIR TK_LIB_FILE TK_LIB_FLAG TK_LIB_SPEC TK_STUB_LIB_FILE TK_STUB_LIB_FLAG TK_STUB_LIB_SPEC TK_LIBS TK_XINCLUDES CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC OBJEXT CPP INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA SET_MAKE RANLIB ac_ct_RANLIB EGREP MATH_LIBS PKG_SOURCES PKG_OBJECTS CLEANFILES TCL_INCLUDES TK_INCLUDES TCL_THREADS SHARED_BUILD AR CELIB_DIR LIBOBJS DL_LIBS CFLAGS_DEBUG CFLAGS_OPTIMIZE CFLAGS_WARNING STLIB_LD SHLIB_LD SHLIB_LD_LIBS SHLIB_CFLAGS LD_LIBRARY_PATH_VAR TCL_DBGX CFLAGS_DEFAULT LDFLAGS_DEFAULT MAKE_LIB MAKE_SHARED_LIB MAKE_STATIC_LIB MAKE_STUB_LIB RANLIB_STUB TCLSH_PROG WISH_PROG LTLIBOBJS' ac_subst_files='' # Initialize some variables set by options. ac_init_help= ac_init_version=false # The variables have the same names as the options, with # dashes changed to underlines. cache_file=/dev/null exec_prefix=NONE no_create= no_recursion= prefix=NONE program_prefix=NONE program_suffix=NONE program_transform_name=s,x,x, silent= site= srcdir= verbose= x_includes=NONE x_libraries=NONE # Installation directory options. # These are left unexpanded so users can "make install exec_prefix=/foo" # and all the variables that are supposed to be based on exec_prefix # by default will actually change. # Use braces instead of parens because sh, perl, etc. also accept them. bindir='${exec_prefix}/bin' sbindir='${exec_prefix}/sbin' libexecdir='${exec_prefix}/libexec' datadir='${prefix}/share' sysconfdir='${prefix}/etc' sharedstatedir='${prefix}/com' localstatedir='${prefix}/var' libdir='${exec_prefix}/lib' includedir='${prefix}/include' oldincludedir='/usr/include' infodir='${prefix}/info' mandir='${prefix}/man' ac_prev= for ac_option do # If the previous option needs an argument, assign it. if test -n "$ac_prev"; then eval "$ac_prev=\$ac_option" ac_prev= continue fi ac_optarg=`expr "x$ac_option" : 'x[^=]*=\(.*\)'` # Accept the important Cygnus configure options, so we can diagnose typos. case $ac_option in -bindir | --bindir | --bindi | --bind | --bin | --bi) ac_prev=bindir ;; -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) bindir=$ac_optarg ;; -build | --build | --buil | --bui | --bu) ac_prev=build_alias ;; -build=* | --build=* | --buil=* | --bui=* | --bu=*) build_alias=$ac_optarg ;; -cache-file | --cache-file | --cache-fil | --cache-fi \ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) ac_prev=cache_file ;; -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) cache_file=$ac_optarg ;; --config-cache | -C) cache_file=config.cache ;; -datadir | --datadir | --datadi | --datad | --data | --dat | --da) ac_prev=datadir ;; -datadir=* | --datadir=* | --datadi=* | --datad=* | --data=* | --dat=* \ | --da=*) datadir=$ac_optarg ;; -disable-* | --disable-*) ac_feature=`expr "x$ac_option" : 'x-*disable-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_feature" : ".*[^-_$as_cr_alnum]" >/dev/null && { echo "$as_me: error: invalid feature name: $ac_feature" >&2 { (exit 1); exit 1; }; } ac_feature=`echo $ac_feature | sed 's/-/_/g'` eval "enable_$ac_feature=no" ;; -enable-* | --enable-*) ac_feature=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_feature" : ".*[^-_$as_cr_alnum]" >/dev/null && { echo "$as_me: error: invalid feature name: $ac_feature" >&2 { (exit 1); exit 1; }; } ac_feature=`echo $ac_feature | sed 's/-/_/g'` case $ac_option in *=*) ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"`;; *) ac_optarg=yes ;; esac eval "enable_$ac_feature='$ac_optarg'" ;; -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ | --exec | --exe | --ex) ac_prev=exec_prefix ;; -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ | --exec=* | --exe=* | --ex=*) exec_prefix=$ac_optarg ;; -gas | --gas | --ga | --g) # Obsolete; use --with-gas. with_gas=yes ;; -help | --help | --hel | --he | -h) ac_init_help=long ;; -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) ac_init_help=recursive ;; -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) ac_init_help=short ;; -host | --host | --hos | --ho) ac_prev=host_alias ;; -host=* | --host=* | --hos=* | --ho=*) host_alias=$ac_optarg ;; -includedir | --includedir | --includedi | --included | --include \ | --includ | --inclu | --incl | --inc) ac_prev=includedir ;; -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ | --includ=* | --inclu=* | --incl=* | --inc=*) includedir=$ac_optarg ;; -infodir | --infodir | --infodi | --infod | --info | --inf) ac_prev=infodir ;; -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) infodir=$ac_optarg ;; -libdir | --libdir | --libdi | --libd) ac_prev=libdir ;; -libdir=* | --libdir=* | --libdi=* | --libd=*) libdir=$ac_optarg ;; -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ | --libexe | --libex | --libe) ac_prev=libexecdir ;; -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ | --libexe=* | --libex=* | --libe=*) libexecdir=$ac_optarg ;; -localstatedir | --localstatedir | --localstatedi | --localstated \ | --localstate | --localstat | --localsta | --localst \ | --locals | --local | --loca | --loc | --lo) ac_prev=localstatedir ;; -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ | --localstate=* | --localstat=* | --localsta=* | --localst=* \ | --locals=* | --local=* | --loca=* | --loc=* | --lo=*) localstatedir=$ac_optarg ;; -mandir | --mandir | --mandi | --mand | --man | --ma | --m) ac_prev=mandir ;; -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) mandir=$ac_optarg ;; -nfp | --nfp | --nf) # Obsolete; use --without-fp. with_fp=no ;; -no-create | --no-create | --no-creat | --no-crea | --no-cre \ | --no-cr | --no-c | -n) no_create=yes ;; -no-recursion | --no-recursion | --no-recursio | --no-recursi \ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) no_recursion=yes ;; -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ | --oldin | --oldi | --old | --ol | --o) ac_prev=oldincludedir ;; -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) oldincludedir=$ac_optarg ;; -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) ac_prev=prefix ;; -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) prefix=$ac_optarg ;; -program-prefix | --program-prefix | --program-prefi | --program-pref \ | --program-pre | --program-pr | --program-p) ac_prev=program_prefix ;; -program-prefix=* | --program-prefix=* | --program-prefi=* \ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) program_prefix=$ac_optarg ;; -program-suffix | --program-suffix | --program-suffi | --program-suff \ | --program-suf | --program-su | --program-s) ac_prev=program_suffix ;; -program-suffix=* | --program-suffix=* | --program-suffi=* \ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) program_suffix=$ac_optarg ;; -program-transform-name | --program-transform-name \ | --program-transform-nam | --program-transform-na \ | --program-transform-n | --program-transform- \ | --program-transform | --program-transfor \ | --program-transfo | --program-transf \ | --program-trans | --program-tran \ | --progr-tra | --program-tr | --program-t) ac_prev=program_transform_name ;; -program-transform-name=* | --program-transform-name=* \ | --program-transform-nam=* | --program-transform-na=* \ | --program-transform-n=* | --program-transform-=* \ | --program-transform=* | --program-transfor=* \ | --program-transfo=* | --program-transf=* \ | --program-trans=* | --program-tran=* \ | --progr-tra=* | --program-tr=* | --program-t=*) program_transform_name=$ac_optarg ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) silent=yes ;; -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) ac_prev=sbindir ;; -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ | --sbi=* | --sb=*) sbindir=$ac_optarg ;; -sharedstatedir | --sharedstatedir | --sharedstatedi \ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ | --sharedst | --shareds | --shared | --share | --shar \ | --sha | --sh) ac_prev=sharedstatedir ;; -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ | --sha=* | --sh=*) sharedstatedir=$ac_optarg ;; -site | --site | --sit) ac_prev=site ;; -site=* | --site=* | --sit=*) site=$ac_optarg ;; -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) ac_prev=srcdir ;; -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) srcdir=$ac_optarg ;; -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ | --syscon | --sysco | --sysc | --sys | --sy) ac_prev=sysconfdir ;; -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) sysconfdir=$ac_optarg ;; -target | --target | --targe | --targ | --tar | --ta | --t) ac_prev=target_alias ;; -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) target_alias=$ac_optarg ;; -v | -verbose | --verbose | --verbos | --verbo | --verb) verbose=yes ;; -version | --version | --versio | --versi | --vers | -V) ac_init_version=: ;; -with-* | --with-*) ac_package=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_package" : ".*[^-_$as_cr_alnum]" >/dev/null && { echo "$as_me: error: invalid package name: $ac_package" >&2 { (exit 1); exit 1; }; } ac_package=`echo $ac_package| sed 's/-/_/g'` case $ac_option in *=*) ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"`;; *) ac_optarg=yes ;; esac eval "with_$ac_package='$ac_optarg'" ;; -without-* | --without-*) ac_package=`expr "x$ac_option" : 'x-*without-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_package" : ".*[^-_$as_cr_alnum]" >/dev/null && { echo "$as_me: error: invalid package name: $ac_package" >&2 { (exit 1); exit 1; }; } ac_package=`echo $ac_package | sed 's/-/_/g'` eval "with_$ac_package=no" ;; --x) # Obsolete; use --with-x. with_x=yes ;; -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ | --x-incl | --x-inc | --x-in | --x-i) ac_prev=x_includes ;; -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) x_includes=$ac_optarg ;; -x-libraries | --x-libraries | --x-librarie | --x-librari \ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) ac_prev=x_libraries ;; -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) x_libraries=$ac_optarg ;; -*) { echo "$as_me: error: unrecognized option: $ac_option Try \`$0 --help' for more information." >&2 { (exit 1); exit 1; }; } ;; *=*) ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` # Reject names that are not valid shell variable names. expr "x$ac_envvar" : ".*[^_$as_cr_alnum]" >/dev/null && { echo "$as_me: error: invalid variable name: $ac_envvar" >&2 { (exit 1); exit 1; }; } ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` eval "$ac_envvar='$ac_optarg'" export $ac_envvar ;; *) # FIXME: should be removed in autoconf 3.0. echo "$as_me: WARNING: you should use --build, --host, --target" >&2 expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && echo "$as_me: WARNING: invalid host type: $ac_option" >&2 : ${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option} ;; esac done if test -n "$ac_prev"; then ac_option=--`echo $ac_prev | sed 's/_/-/g'` { echo "$as_me: error: missing argument to $ac_option" >&2 { (exit 1); exit 1; }; } fi # Be sure to have absolute paths. for ac_var in exec_prefix prefix do eval ac_val=$`echo $ac_var` case $ac_val in [\\/$]* | ?:[\\/]* | NONE | '' ) ;; *) { echo "$as_me: error: expected an absolute directory name for --$ac_var: $ac_val" >&2 { (exit 1); exit 1; }; };; esac done # Be sure to have absolute paths. for ac_var in bindir sbindir libexecdir datadir sysconfdir sharedstatedir \ localstatedir libdir includedir oldincludedir infodir mandir do eval ac_val=$`echo $ac_var` case $ac_val in [\\/$]* | ?:[\\/]* ) ;; *) { echo "$as_me: error: expected an absolute directory name for --$ac_var: $ac_val" >&2 { (exit 1); exit 1; }; };; esac done # There might be people who depend on the old broken behavior: `$host' # used to hold the argument of --host etc. # FIXME: To remove some day. build=$build_alias host=$host_alias target=$target_alias # FIXME: To remove some day. if test "x$host_alias" != x; then if test "x$build_alias" = x; then cross_compiling=maybe echo "$as_me: WARNING: If you wanted to set the --build type, don't use --host. If a cross compiler is detected then cross compile mode will be used." >&2 elif test "x$build_alias" != "x$host_alias"; then cross_compiling=yes fi fi ac_tool_prefix= test -n "$host_alias" && ac_tool_prefix=$host_alias- test "$silent" = yes && exec 6>/dev/null # Find the source files, if location was not specified. if test -z "$srcdir"; then ac_srcdir_defaulted=yes # Try the directory containing this script, then its parent. ac_confdir=`(dirname "$0") 2>/dev/null || $as_expr X"$0" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$0" : 'X\(//\)[^/]' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| \ . : '\(.\)' 2>/dev/null || echo X"$0" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } /^X\(\/\/\)[^/].*/{ s//\1/; q; } /^X\(\/\/\)$/{ s//\1/; q; } /^X\(\/\).*/{ s//\1/; q; } s/.*/./; q'` srcdir=$ac_confdir if test ! -r $srcdir/$ac_unique_file; then srcdir=.. fi else ac_srcdir_defaulted=no fi if test ! -r $srcdir/$ac_unique_file; then if test "$ac_srcdir_defaulted" = yes; then { echo "$as_me: error: cannot find sources ($ac_unique_file) in $ac_confdir or .." >&2 { (exit 1); exit 1; }; } else { echo "$as_me: error: cannot find sources ($ac_unique_file) in $srcdir" >&2 { (exit 1); exit 1; }; } fi fi (cd $srcdir && test -r ./$ac_unique_file) 2>/dev/null || { echo "$as_me: error: sources are in $srcdir, but \`cd $srcdir' does not work" >&2 { (exit 1); exit 1; }; } srcdir=`echo "$srcdir" | sed 's%\([^\\/]\)[\\/]*$%\1%'` ac_env_build_alias_set=${build_alias+set} ac_env_build_alias_value=$build_alias ac_cv_env_build_alias_set=${build_alias+set} ac_cv_env_build_alias_value=$build_alias ac_env_host_alias_set=${host_alias+set} ac_env_host_alias_value=$host_alias ac_cv_env_host_alias_set=${host_alias+set} ac_cv_env_host_alias_value=$host_alias ac_env_target_alias_set=${target_alias+set} ac_env_target_alias_value=$target_alias ac_cv_env_target_alias_set=${target_alias+set} ac_cv_env_target_alias_value=$target_alias ac_env_CC_set=${CC+set} ac_env_CC_value=$CC ac_cv_env_CC_set=${CC+set} ac_cv_env_CC_value=$CC ac_env_CFLAGS_set=${CFLAGS+set} ac_env_CFLAGS_value=$CFLAGS ac_cv_env_CFLAGS_set=${CFLAGS+set} ac_cv_env_CFLAGS_value=$CFLAGS ac_env_LDFLAGS_set=${LDFLAGS+set} ac_env_LDFLAGS_value=$LDFLAGS ac_cv_env_LDFLAGS_set=${LDFLAGS+set} ac_cv_env_LDFLAGS_value=$LDFLAGS ac_env_CPPFLAGS_set=${CPPFLAGS+set} ac_env_CPPFLAGS_value=$CPPFLAGS ac_cv_env_CPPFLAGS_set=${CPPFLAGS+set} ac_cv_env_CPPFLAGS_value=$CPPFLAGS ac_env_CPP_set=${CPP+set} ac_env_CPP_value=$CPP ac_cv_env_CPP_set=${CPP+set} ac_cv_env_CPP_value=$CPP # # Report the --help message. # if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF \`configure' configures Tkhtml 3.0 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... To assign environment variables (e.g., CC, CFLAGS...), specify them as VAR=VALUE. See below for descriptions of some of the useful variables. Defaults for the options are specified in brackets. Configuration: -h, --help display this help and exit --help=short display options specific to this package --help=recursive display the short help of all the included packages -V, --version display version information and exit -q, --quiet, --silent do not print \`checking...' messages --cache-file=FILE cache test results in FILE [disabled] -C, --config-cache alias for \`--cache-file=config.cache' -n, --no-create do not create output files --srcdir=DIR find the sources in DIR [configure dir or \`..'] _ACEOF cat <<_ACEOF Installation directories: --prefix=PREFIX install architecture-independent files in PREFIX [$ac_default_prefix] --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX [PREFIX] By default, \`make install' will install all the files in \`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify an installation prefix other than \`$ac_default_prefix' using \`--prefix', for instance \`--prefix=\$HOME'. For better control, use the options below. Fine tuning of the installation directories: --bindir=DIR user executables [EPREFIX/bin] --sbindir=DIR system admin executables [EPREFIX/sbin] --libexecdir=DIR program executables [EPREFIX/libexec] --datadir=DIR read-only architecture-independent data [PREFIX/share] --sysconfdir=DIR read-only single-machine data [PREFIX/etc] --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] --localstatedir=DIR modifiable single-machine data [PREFIX/var] --libdir=DIR object code libraries [EPREFIX/lib] --includedir=DIR C header files [PREFIX/include] --oldincludedir=DIR C header files for non-gcc [/usr/include] --infodir=DIR info documentation [PREFIX/info] --mandir=DIR man documentation [PREFIX/man] _ACEOF cat <<\_ACEOF X features: --x-includes=DIR X include files are in DIR --x-libraries=DIR X library files are in DIR _ACEOF fi if test -n "$ac_init_help"; then case $ac_init_help in short | recursive ) echo "Configuration of Tkhtml 3.0:";; esac cat <<\_ACEOF Optional Features: --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) --enable-FEATURE[=ARG] include FEATURE [ARG=yes] --enable-threads build with threads --enable-shared build and link with shared libraries (default: on) --enable-64bit enable 64bit support (default: off) --enable-64bit-vis enable 64bit Sparc VIS support (default: off) --enable-wince enable Win/CE support (where applicable) --disable-load disallow dynamic loading and "load" command (default: enabled) --enable-symbols build with debugging symbols (default: off) Optional Packages: --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) --with-tcl directory containing tcl configuration (tclConfig.sh) --with-tk directory containing tk configuration (tkConfig.sh) --with-tclinclude directory containing the public Tcl header files --with-tkinclude directory containing the public Tk header files. --with-x use the X Window System --with-celib=DIR use Windows/CE support library from DIR Some influential environment variables: CC C compiler command CFLAGS C compiler flags LDFLAGS linker flags, e.g. -L if you have libraries in a nonstandard directory CPPFLAGS C/C++ preprocessor flags, e.g. -I if you have headers in a nonstandard directory CPP C preprocessor Use these variables to override the choices made by `configure' or to help it to find libraries and programs with nonstandard names/locations. _ACEOF fi if test "$ac_init_help" = "recursive"; then # If there are subdirs, report their specific --help. ac_popdir=`pwd` for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue test -d $ac_dir || continue ac_builddir=. if test "$ac_dir" != .; then ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'` # A "../" for each directory in $ac_dir_suffix. ac_top_builddir=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,../,g'` else ac_dir_suffix= ac_top_builddir= fi case $srcdir in .) # No --srcdir option. We are building in place. ac_srcdir=. if test -z "$ac_top_builddir"; then ac_top_srcdir=. else ac_top_srcdir=`echo $ac_top_builddir | sed 's,/$,,'` fi ;; [\\/]* | ?:[\\/]* ) # Absolute path. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ;; *) # Relative path. ac_srcdir=$ac_top_builddir$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_builddir$srcdir ;; esac # Do not use `cd foo && pwd` to compute absolute paths, because # the directories may not exist. case `pwd` in .) ac_abs_builddir="$ac_dir";; *) case "$ac_dir" in .) ac_abs_builddir=`pwd`;; [\\/]* | ?:[\\/]* ) ac_abs_builddir="$ac_dir";; *) ac_abs_builddir=`pwd`/"$ac_dir";; esac;; esac case $ac_abs_builddir in .) ac_abs_top_builddir=${ac_top_builddir}.;; *) case ${ac_top_builddir}. in .) ac_abs_top_builddir=$ac_abs_builddir;; [\\/]* | ?:[\\/]* ) ac_abs_top_builddir=${ac_top_builddir}.;; *) ac_abs_top_builddir=$ac_abs_builddir/${ac_top_builddir}.;; esac;; esac case $ac_abs_builddir in .) ac_abs_srcdir=$ac_srcdir;; *) case $ac_srcdir in .) ac_abs_srcdir=$ac_abs_builddir;; [\\/]* | ?:[\\/]* ) ac_abs_srcdir=$ac_srcdir;; *) ac_abs_srcdir=$ac_abs_builddir/$ac_srcdir;; esac;; esac case $ac_abs_builddir in .) ac_abs_top_srcdir=$ac_top_srcdir;; *) case $ac_top_srcdir in .) ac_abs_top_srcdir=$ac_abs_builddir;; [\\/]* | ?:[\\/]* ) ac_abs_top_srcdir=$ac_top_srcdir;; *) ac_abs_top_srcdir=$ac_abs_builddir/$ac_top_srcdir;; esac;; esac cd $ac_dir # Check for guested configure; otherwise get Cygnus style configure. if test -f $ac_srcdir/configure.gnu; then echo $SHELL $ac_srcdir/configure.gnu --help=recursive elif test -f $ac_srcdir/configure; then echo $SHELL $ac_srcdir/configure --help=recursive elif test -f $ac_srcdir/configure.ac || test -f $ac_srcdir/configure.in; then echo $ac_configure --help else echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 fi cd $ac_popdir done fi test -n "$ac_init_help" && exit 0 if $ac_init_version; then cat <<\_ACEOF Tkhtml configure 3.0 generated by GNU Autoconf 2.59 Copyright (C) 2003 Free Software Foundation, Inc. This configure script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it. _ACEOF exit 0 fi exec 5>config.log cat >&5 <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. It was created by Tkhtml $as_me 3.0, which was generated by GNU Autoconf 2.59. Invocation command line was $ $0 $@ _ACEOF { cat <<_ASUNAME ## --------- ## ## Platform. ## ## --------- ## hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` uname -m = `(uname -m) 2>/dev/null || echo unknown` uname -r = `(uname -r) 2>/dev/null || echo unknown` uname -s = `(uname -s) 2>/dev/null || echo unknown` uname -v = `(uname -v) 2>/dev/null || echo unknown` /usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` /bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` /bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` /usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` hostinfo = `(hostinfo) 2>/dev/null || echo unknown` /bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` /bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` _ASUNAME as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. echo "PATH: $as_dir" done } >&5 cat >&5 <<_ACEOF ## ----------- ## ## Core tests. ## ## ----------- ## _ACEOF # Keep a trace of the command line. # Strip out --no-create and --no-recursion so they do not pile up. # Strip out --silent because we don't want to record it for future runs. # Also quote any args containing shell meta-characters. # Make two passes to allow for proper duplicate-argument suppression. ac_configure_args= ac_configure_args0= ac_configure_args1= ac_sep= ac_must_keep_next=false for ac_pass in 1 2 do for ac_arg do case $ac_arg in -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) continue ;; *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?\"\']*) ac_arg=`echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; esac case $ac_pass in 1) ac_configure_args0="$ac_configure_args0 '$ac_arg'" ;; 2) ac_configure_args1="$ac_configure_args1 '$ac_arg'" if test $ac_must_keep_next = true; then ac_must_keep_next=false # Got value, back to normal. else case $ac_arg in *=* | --config-cache | -C | -disable-* | --disable-* \ | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ | -with-* | --with-* | -without-* | --without-* | --x) case "$ac_configure_args0 " in "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; esac ;; -* ) ac_must_keep_next=true ;; esac fi ac_configure_args="$ac_configure_args$ac_sep'$ac_arg'" # Get rid of the leading space. ac_sep=" " ;; esac done done $as_unset ac_configure_args0 || test "${ac_configure_args0+set}" != set || { ac_configure_args0=; export ac_configure_args0; } $as_unset ac_configure_args1 || test "${ac_configure_args1+set}" != set || { ac_configure_args1=; export ac_configure_args1; } # When interrupted or exit'd, cleanup temporary files, and complete # config.log. We remove comments because anyway the quotes in there # would cause problems or look ugly. # WARNING: Be sure not to use single quotes in there, as some shells, # such as our DU 5.0 friend, will then `close' the trap. trap 'exit_status=$? # Save into config.log some information that might help in debugging. { echo cat <<\_ASBOX ## ---------------- ## ## Cache variables. ## ## ---------------- ## _ASBOX echo # The following way of writing the cache mishandles newlines in values, { (set) 2>&1 | case `(ac_space='"'"' '"'"'; set | grep ac_space) 2>&1` in *ac_space=\ *) sed -n \ "s/'"'"'/'"'"'\\\\'"'"''"'"'/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='"'"'\\2'"'"'/p" ;; *) sed -n \ "s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1=\\2/p" ;; esac; } echo cat <<\_ASBOX ## ----------------- ## ## Output variables. ## ## ----------------- ## _ASBOX echo for ac_var in $ac_subst_vars do eval ac_val=$`echo $ac_var` echo "$ac_var='"'"'$ac_val'"'"'" done | sort echo if test -n "$ac_subst_files"; then cat <<\_ASBOX ## ------------- ## ## Output files. ## ## ------------- ## _ASBOX echo for ac_var in $ac_subst_files do eval ac_val=$`echo $ac_var` echo "$ac_var='"'"'$ac_val'"'"'" done | sort echo fi if test -s confdefs.h; then cat <<\_ASBOX ## ----------- ## ## confdefs.h. ## ## ----------- ## _ASBOX echo sed "/^$/d" confdefs.h | sort echo fi test "$ac_signal" != 0 && echo "$as_me: caught signal $ac_signal" echo "$as_me: exit $exit_status" } >&5 rm -f core *.core && rm -rf conftest* confdefs* conf$$* $ac_clean_files && exit $exit_status ' 0 for ac_signal in 1 2 13 15; do trap 'ac_signal='$ac_signal'; { (exit 1); exit 1; }' $ac_signal done ac_signal=0 # confdefs.h avoids OS command line length limits that DEFS can exceed. rm -rf conftest* confdefs.h # AIX cpp loses on an empty file, so make sure it contains at least a newline. echo >confdefs.h # Predefined preprocessor variables. cat >>confdefs.h <<_ACEOF #define PACKAGE_NAME "$PACKAGE_NAME" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_TARNAME "$PACKAGE_TARNAME" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_VERSION "$PACKAGE_VERSION" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_STRING "$PACKAGE_STRING" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" _ACEOF # Let the site file select an alternate cache file if it wants to. # Prefer explicitly selected file to automatically selected ones. if test -z "$CONFIG_SITE"; then if test "x$prefix" != xNONE; then CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site" else CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site" fi fi for ac_site_file in $CONFIG_SITE; do if test -r "$ac_site_file"; then { echo "$as_me:$LINENO: loading site script $ac_site_file" >&5 echo "$as_me: loading site script $ac_site_file" >&6;} sed 's/^/| /' "$ac_site_file" >&5 . "$ac_site_file" fi done if test -r "$cache_file"; then # Some versions of bash will fail to source /dev/null (special # files actually), so we avoid doing that. if test -f "$cache_file"; then { echo "$as_me:$LINENO: loading cache $cache_file" >&5 echo "$as_me: loading cache $cache_file" >&6;} case $cache_file in [\\/]* | ?:[\\/]* ) . $cache_file;; *) . ./$cache_file;; esac fi else { echo "$as_me:$LINENO: creating cache $cache_file" >&5 echo "$as_me: creating cache $cache_file" >&6;} >$cache_file fi # Check that the precious variables saved in the cache have kept the same # value. ac_cache_corrupted=false for ac_var in `(set) 2>&1 | sed -n 's/^ac_env_\([a-zA-Z_0-9]*\)_set=.*/\1/p'`; do eval ac_old_set=\$ac_cv_env_${ac_var}_set eval ac_new_set=\$ac_env_${ac_var}_set eval ac_old_val="\$ac_cv_env_${ac_var}_value" eval ac_new_val="\$ac_env_${ac_var}_value" case $ac_old_set,$ac_new_set in set,) { echo "$as_me:$LINENO: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} ac_cache_corrupted=: ;; ,set) { echo "$as_me:$LINENO: error: \`$ac_var' was not set in the previous run" >&5 echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} ac_cache_corrupted=: ;; ,);; *) if test "x$ac_old_val" != "x$ac_new_val"; then { echo "$as_me:$LINENO: error: \`$ac_var' has changed since the previous run:" >&5 echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} { echo "$as_me:$LINENO: former value: $ac_old_val" >&5 echo "$as_me: former value: $ac_old_val" >&2;} { echo "$as_me:$LINENO: current value: $ac_new_val" >&5 echo "$as_me: current value: $ac_new_val" >&2;} ac_cache_corrupted=: fi;; esac # Pass precious variables to config.status. if test "$ac_new_set" = set; then case $ac_new_val in *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?\"\']*) ac_arg=$ac_var=`echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; *) ac_arg=$ac_var=$ac_new_val ;; esac case " $ac_configure_args " in *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. *) ac_configure_args="$ac_configure_args '$ac_arg'" ;; esac fi done if $ac_cache_corrupted; then { echo "$as_me:$LINENO: error: changes in the environment can compromise the build" >&5 echo "$as_me: error: changes in the environment can compromise the build" >&2;} { { echo "$as_me:$LINENO: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&5 echo "$as_me: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&2;} { (exit 1); exit 1; }; } fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu #-------------------------------------------------------------------- # Call TEA_INIT as the first TEA_ macro to set up initial vars. # This will define a ${TEA_PLATFORM} variable == "unix" or "windows" # as well as PKG_LIB_FILE and PKG_STUB_LIB_FILE. #-------------------------------------------------------------------- # TEA extensions pass this us the version of TEA they think they # are compatible with. TEA_VERSION="3.5" echo "$as_me:$LINENO: checking for correct TEA configuration" >&5 echo $ECHO_N "checking for correct TEA configuration... $ECHO_C" >&6 if test x"${PACKAGE_NAME}" = x ; then { { echo "$as_me:$LINENO: error: The PACKAGE_NAME variable must be defined by your TEA configure.in" >&5 echo "$as_me: error: The PACKAGE_NAME variable must be defined by your TEA configure.in" >&2;} { (exit 1); exit 1; }; } fi if test x"3.5" = x ; then { { echo "$as_me:$LINENO: error: TEA version not specified." >&5 echo "$as_me: error: TEA version not specified." >&2;} { (exit 1); exit 1; }; } elif test "3.5" != "${TEA_VERSION}" ; then echo "$as_me:$LINENO: result: warning: requested TEA version \"3.5\", have \"${TEA_VERSION}\"" >&5 echo "${ECHO_T}warning: requested TEA version \"3.5\", have \"${TEA_VERSION}\"" >&6 else echo "$as_me:$LINENO: result: ok (TEA ${TEA_VERSION})" >&5 echo "${ECHO_T}ok (TEA ${TEA_VERSION})" >&6 fi case "`uname -s`" in *win32*|*WIN32*|*CYGWIN_NT*|*CYGWIN_9*|*CYGWIN_ME*|*MINGW32_*) # Extract the first word of "cygpath", so it can be a program name with args. set dummy cygpath; ac_word=$2 echo "$as_me:$LINENO: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 if test "${ac_cv_prog_CYGPATH+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else if test -n "$CYGPATH"; then ac_cv_prog_CYGPATH="$CYGPATH" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CYGPATH="cygpath -w" echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done test -z "$ac_cv_prog_CYGPATH" && ac_cv_prog_CYGPATH="echo" fi fi CYGPATH=$ac_cv_prog_CYGPATH if test -n "$CYGPATH"; then echo "$as_me:$LINENO: result: $CYGPATH" >&5 echo "${ECHO_T}$CYGPATH" >&6 else echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6 fi EXEEXT=".exe" TEA_PLATFORM="windows" ;; *) CYGPATH=echo EXEEXT="" TEA_PLATFORM="unix" ;; esac # Check if exec_prefix is set. If not use fall back to prefix. # Note when adjusted, so that TEA_PREFIX can correct for this. # This is needed for recursive configures, since autoconf propagates # $prefix, but not $exec_prefix (doh!). if test x$exec_prefix = xNONE ; then exec_prefix_default=yes exec_prefix=$prefix fi # This package name must be replaced statically for AC_SUBST to work # Substitute STUB_LIB_FILE in case package creates a stub library too. # We AC_SUBST these here to ensure they are subst'ed, # in case the user doesn't call TEA_ADD_... ac_aux_dir= for ac_dir in tclconfig $srcdir/tclconfig; do if test -f $ac_dir/install-sh; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/install-sh -c" break elif test -f $ac_dir/install.sh; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/install.sh -c" break elif test -f $ac_dir/shtool; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/shtool install -c" break fi done if test -z "$ac_aux_dir"; then { { echo "$as_me:$LINENO: error: cannot find install-sh or install.sh in tclconfig $srcdir/tclconfig" >&5 echo "$as_me: error: cannot find install-sh or install.sh in tclconfig $srcdir/tclconfig" >&2;} { (exit 1); exit 1; }; } fi ac_config_guess="$SHELL $ac_aux_dir/config.guess" ac_config_sub="$SHELL $ac_aux_dir/config.sub" ac_configure="$SHELL $ac_aux_dir/configure" # This should be Cygnus configure. #-------------------------------------------------------------------- # Load the tclConfig.sh file #-------------------------------------------------------------------- # # Ok, lets find the tcl configuration # First, look for one uninstalled. # the alternative search directory is invoked by --with-tcl # if test x"${no_tcl}" = x ; then # we reset no_tcl in case something fails here no_tcl=true # Check whether --with-tcl or --without-tcl was given. if test "${with_tcl+set}" = set; then withval="$with_tcl" with_tclconfig=${withval} fi; echo "$as_me:$LINENO: checking for Tcl configuration" >&5 echo $ECHO_N "checking for Tcl configuration... $ECHO_C" >&6 if test "${ac_cv_c_tclconfig+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else # First check to see if --with-tcl was specified. if test x"${with_tclconfig}" != x ; then case ${with_tclconfig} in */tclConfig.sh ) if test -f ${with_tclconfig}; then { echo "$as_me:$LINENO: WARNING: --with-tcl argument should refer to directory containing tclConfig.sh, not to tclConfig.sh itself" >&5 echo "$as_me: WARNING: --with-tcl argument should refer to directory containing tclConfig.sh, not to tclConfig.sh itself" >&2;} with_tclconfig=`echo ${with_tclconfig} | sed 's!/tclConfig\.sh$!!'` fi ;; esac if test -f "${with_tclconfig}/tclConfig.sh" ; then ac_cv_c_tclconfig=`(cd ${with_tclconfig}; pwd)` else { { echo "$as_me:$LINENO: error: ${with_tclconfig} directory doesn't contain tclConfig.sh" >&5 echo "$as_me: error: ${with_tclconfig} directory doesn't contain tclConfig.sh" >&2;} { (exit 1); exit 1; }; } fi fi # then check for a private Tcl installation if test x"${ac_cv_c_tclconfig}" = x ; then for i in \ ../tcl \ `ls -dr ../tcl[8-9].[0-9].[0-9]* 2>/dev/null` \ `ls -dr ../tcl[8-9].[0-9] 2>/dev/null` \ `ls -dr ../tcl[8-9].[0-9]* 2>/dev/null` \ ../../tcl \ `ls -dr ../../tcl[8-9].[0-9].[0-9]* 2>/dev/null` \ `ls -dr ../../tcl[8-9].[0-9] 2>/dev/null` \ `ls -dr ../../tcl[8-9].[0-9]* 2>/dev/null` \ ../../../tcl \ `ls -dr ../../../tcl[8-9].[0-9].[0-9]* 2>/dev/null` \ `ls -dr ../../../tcl[8-9].[0-9] 2>/dev/null` \ `ls -dr ../../../tcl[8-9].[0-9]* 2>/dev/null` ; do if test -f "$i/unix/tclConfig.sh" ; then ac_cv_c_tclconfig=`(cd $i/unix; pwd)` break fi done fi # on Darwin, check in Framework installation locations if test "`uname -s`" = "Darwin" -a x"${ac_cv_c_tclconfig}" = x ; then for i in `ls -d ~/Library/Frameworks 2>/dev/null` \ `ls -d /Library/Frameworks 2>/dev/null` \ `ls -d /Network/Library/Frameworks 2>/dev/null` \ `ls -d /System/Library/Frameworks 2>/dev/null` \ ; do if test -f "$i/Tcl.framework/tclConfig.sh" ; then ac_cv_c_tclconfig=`(cd $i/Tcl.framework; pwd)` break fi done fi # on Windows, check in common installation locations if test "${TEA_PLATFORM}" = "windows" \ -a x"${ac_cv_c_tclconfig}" = x ; then for i in `ls -d C:/Tcl/lib 2>/dev/null` \ `ls -d C:/Progra~1/Tcl/lib 2>/dev/null` \ ; do if test -f "$i/tclConfig.sh" ; then ac_cv_c_tclconfig=`(cd $i; pwd)` break fi done fi # check in a few common install locations if test x"${ac_cv_c_tclconfig}" = x ; then for i in `ls -d ${libdir} 2>/dev/null` \ `ls -d ${exec_prefix}/lib 2>/dev/null` \ `ls -d ${prefix}/lib 2>/dev/null` \ `ls -d /usr/local/lib 2>/dev/null` \ `ls -d /usr/contrib/lib 2>/dev/null` \ `ls -d /usr/lib 2>/dev/null` \ ; do if test -f "$i/tclConfig.sh" ; then ac_cv_c_tclconfig=`(cd $i; pwd)` break fi done fi # check in a few other private locations if test x"${ac_cv_c_tclconfig}" = x ; then for i in \ ${srcdir}/../tcl \ `ls -dr ${srcdir}/../tcl[8-9].[0-9].[0-9]* 2>/dev/null` \ `ls -dr ${srcdir}/../tcl[8-9].[0-9] 2>/dev/null` \ `ls -dr ${srcdir}/../tcl[8-9].[0-9]* 2>/dev/null` ; do if test -f "$i/unix/tclConfig.sh" ; then ac_cv_c_tclconfig=`(cd $i/unix; pwd)` break fi done fi fi if test x"${ac_cv_c_tclconfig}" = x ; then TCL_BIN_DIR="# no Tcl configs found" { echo "$as_me:$LINENO: WARNING: Can't find Tcl configuration definitions" >&5 echo "$as_me: WARNING: Can't find Tcl configuration definitions" >&2;} exit 0 else no_tcl= TCL_BIN_DIR=${ac_cv_c_tclconfig} echo "$as_me:$LINENO: result: found ${TCL_BIN_DIR}/tclConfig.sh" >&5 echo "${ECHO_T}found ${TCL_BIN_DIR}/tclConfig.sh" >&6 fi fi echo "$as_me:$LINENO: checking for existence of ${TCL_BIN_DIR}/tclConfig.sh" >&5 echo $ECHO_N "checking for existence of ${TCL_BIN_DIR}/tclConfig.sh... $ECHO_C" >&6 if test -f "${TCL_BIN_DIR}/tclConfig.sh" ; then echo "$as_me:$LINENO: result: loading" >&5 echo "${ECHO_T}loading" >&6 . ${TCL_BIN_DIR}/tclConfig.sh else echo "$as_me:$LINENO: result: could not find ${TCL_BIN_DIR}/tclConfig.sh" >&5 echo "${ECHO_T}could not find ${TCL_BIN_DIR}/tclConfig.sh" >&6 fi # eval is required to do the TCL_DBGX substitution eval "TCL_LIB_FILE=\"${TCL_LIB_FILE}\"" eval "TCL_STUB_LIB_FILE=\"${TCL_STUB_LIB_FILE}\"" # If the TCL_BIN_DIR is the build directory (not the install directory), # then set the common variable name to the value of the build variables. # For example, the variable TCL_LIB_SPEC will be set to the value # of TCL_BUILD_LIB_SPEC. An extension should make use of TCL_LIB_SPEC # instead of TCL_BUILD_LIB_SPEC since it will work with both an # installed and uninstalled version of Tcl. if test -f ${TCL_BIN_DIR}/Makefile ; then TCL_LIB_SPEC=${TCL_BUILD_LIB_SPEC} TCL_STUB_LIB_SPEC=${TCL_BUILD_STUB_LIB_SPEC} TCL_STUB_LIB_PATH=${TCL_BUILD_STUB_LIB_PATH} elif test "`uname -s`" = "Darwin"; then # If Tcl was built as a framework, attempt to use the libraries # from the framework at the given location so that linking works # against Tcl.framework installed in an arbitary location. case ${TCL_DEFS} in *TCL_FRAMEWORK*) if test -f ${TCL_BIN_DIR}/${TCL_LIB_FILE}; then for i in "`cd ${TCL_BIN_DIR}; pwd`" \ "`cd ${TCL_BIN_DIR}/../..; pwd`"; do if test "`basename "$i"`" = "${TCL_LIB_FILE}.framework"; then TCL_LIB_SPEC="-F`dirname "$i"` -framework ${TCL_LIB_FILE}" break fi done fi if test -f ${TCL_BIN_DIR}/${TCL_STUB_LIB_FILE}; then TCL_STUB_LIB_SPEC="-L${TCL_BIN_DIR} ${TCL_STUB_LIB_FLAG}" TCL_STUB_LIB_PATH="${TCL_BIN_DIR}/${TCL_STUB_LIB_FILE}" fi ;; esac fi # eval is required to do the TCL_DBGX substitution eval "TCL_LIB_FLAG=\"${TCL_LIB_FLAG}\"" eval "TCL_LIB_SPEC=\"${TCL_LIB_SPEC}\"" eval "TCL_STUB_LIB_FLAG=\"${TCL_STUB_LIB_FLAG}\"" eval "TCL_STUB_LIB_SPEC=\"${TCL_STUB_LIB_SPEC}\"" #-------------------------------------------------------------------- # Load the tkConfig.sh file if necessary (Tk extension) #-------------------------------------------------------------------- # # Ok, lets find the tk configuration # First, look for one uninstalled. # the alternative search directory is invoked by --with-tk # if test x"${no_tk}" = x ; then # we reset no_tk in case something fails here no_tk=true # Check whether --with-tk or --without-tk was given. if test "${with_tk+set}" = set; then withval="$with_tk" with_tkconfig=${withval} fi; echo "$as_me:$LINENO: checking for Tk configuration" >&5 echo $ECHO_N "checking for Tk configuration... $ECHO_C" >&6 if test "${ac_cv_c_tkconfig+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else # First check to see if --with-tkconfig was specified. if test x"${with_tkconfig}" != x ; then case ${with_tkconfig} in */tkConfig.sh ) if test -f ${with_tkconfig}; then { echo "$as_me:$LINENO: WARNING: --with-tk argument should refer to directory containing tkConfig.sh, not to tkConfig.sh itself" >&5 echo "$as_me: WARNING: --with-tk argument should refer to directory containing tkConfig.sh, not to tkConfig.sh itself" >&2;} with_tkconfig=`echo ${with_tkconfig} | sed 's!/tkConfig\.sh$!!'` fi ;; esac if test -f "${with_tkconfig}/tkConfig.sh" ; then ac_cv_c_tkconfig=`(cd ${with_tkconfig}; pwd)` else { { echo "$as_me:$LINENO: error: ${with_tkconfig} directory doesn't contain tkConfig.sh" >&5 echo "$as_me: error: ${with_tkconfig} directory doesn't contain tkConfig.sh" >&2;} { (exit 1); exit 1; }; } fi fi # then check for a private Tk library if test x"${ac_cv_c_tkconfig}" = x ; then for i in \ ../tk \ `ls -dr ../tk[8-9].[0-9].[0-9]* 2>/dev/null` \ `ls -dr ../tk[8-9].[0-9] 2>/dev/null` \ `ls -dr ../tk[8-9].[0-9]* 2>/dev/null` \ ../../tk \ `ls -dr ../../tk[8-9].[0-9].[0-9]* 2>/dev/null` \ `ls -dr ../../tk[8-9].[0-9] 2>/dev/null` \ `ls -dr ../../tk[8-9].[0-9]* 2>/dev/null` \ ../../../tk \ `ls -dr ../../../tk[8-9].[0-9].[0-9]* 2>/dev/null` \ `ls -dr ../../../tk[8-9].[0-9] 2>/dev/null` \ `ls -dr ../../../tk[8-9].[0-9]* 2>/dev/null` ; do if test -f "$i/unix/tkConfig.sh" ; then ac_cv_c_tkconfig=`(cd $i/unix; pwd)` break fi done fi # on Darwin, check in Framework installation locations if test "`uname -s`" = "Darwin" -a x"${ac_cv_c_tkconfig}" = x ; then for i in `ls -d ~/Library/Frameworks 2>/dev/null` \ `ls -d /Library/Frameworks 2>/dev/null` \ `ls -d /Network/Library/Frameworks 2>/dev/null` \ `ls -d /System/Library/Frameworks 2>/dev/null` \ ; do if test -f "$i/Tk.framework/tkConfig.sh" ; then ac_cv_c_tkconfig=`(cd $i/Tk.framework; pwd)` break fi done fi # check in a few common install locations if test x"${ac_cv_c_tkconfig}" = x ; then for i in `ls -d ${libdir} 2>/dev/null` \ `ls -d ${exec_prefix}/lib 2>/dev/null` \ `ls -d ${prefix}/lib 2>/dev/null` \ `ls -d /usr/local/lib 2>/dev/null` \ `ls -d /usr/contrib/lib 2>/dev/null` \ `ls -d /usr/lib 2>/dev/null` \ ; do if test -f "$i/tkConfig.sh" ; then ac_cv_c_tkconfig=`(cd $i; pwd)` break fi done fi # on Windows, check in common installation locations if test "${TEA_PLATFORM}" = "windows" \ -a x"${ac_cv_c_tclconfig}" = x ; then for i in `ls -d C:/Tcl/lib 2>/dev/null` \ `ls -d C:/Progra~1/Tcl/lib 2>/dev/null` \ ; do if test -f "$i/tclConfig.sh" ; then ac_cv_c_tclconfig=`(cd $i; pwd)` break fi done fi # check in a few other private locations if test x"${ac_cv_c_tkconfig}" = x ; then for i in \ ${srcdir}/../tk \ `ls -dr ${srcdir}/../tk[8-9].[0-9].[0-9]* 2>/dev/null` \ `ls -dr ${srcdir}/../tk[8-9].[0-9] 2>/dev/null` \ `ls -dr ${srcdir}/../tk[8-9].[0-9]* 2>/dev/null` ; do if test -f "$i/unix/tkConfig.sh" ; then ac_cv_c_tkconfig=`(cd $i/unix; pwd)` break fi done fi fi if test x"${ac_cv_c_tkconfig}" = x ; then TK_BIN_DIR="# no Tk configs found" { echo "$as_me:$LINENO: WARNING: Can't find Tk configuration definitions" >&5 echo "$as_me: WARNING: Can't find Tk configuration definitions" >&2;} exit 0 else no_tk= TK_BIN_DIR=${ac_cv_c_tkconfig} echo "$as_me:$LINENO: result: found ${TK_BIN_DIR}/tkConfig.sh" >&5 echo "${ECHO_T}found ${TK_BIN_DIR}/tkConfig.sh" >&6 fi fi echo "$as_me:$LINENO: checking for existence of ${TK_BIN_DIR}/tkConfig.sh" >&5 echo $ECHO_N "checking for existence of ${TK_BIN_DIR}/tkConfig.sh... $ECHO_C" >&6 if test -f "${TK_BIN_DIR}/tkConfig.sh" ; then echo "$as_me:$LINENO: result: loading" >&5 echo "${ECHO_T}loading" >&6 . ${TK_BIN_DIR}/tkConfig.sh else echo "$as_me:$LINENO: result: could not find ${TK_BIN_DIR}/tkConfig.sh" >&5 echo "${ECHO_T}could not find ${TK_BIN_DIR}/tkConfig.sh" >&6 fi # eval is required to do the TK_DBGX substitution eval "TK_LIB_FILE=\"${TK_LIB_FILE}\"" eval "TK_STUB_LIB_FILE=\"${TK_STUB_LIB_FILE}\"" # If the TK_BIN_DIR is the build directory (not the install directory), # then set the common variable name to the value of the build variables. # For example, the variable TK_LIB_SPEC will be set to the value # of TK_BUILD_LIB_SPEC. An extension should make use of TK_LIB_SPEC # instead of TK_BUILD_LIB_SPEC since it will work with both an # installed and uninstalled version of Tcl. if test -f ${TK_BIN_DIR}/Makefile ; then TK_LIB_SPEC=${TK_BUILD_LIB_SPEC} TK_STUB_LIB_SPEC=${TK_BUILD_STUB_LIB_SPEC} TK_STUB_LIB_PATH=${TK_BUILD_STUB_LIB_PATH} elif test "`uname -s`" = "Darwin"; then # If Tk was built as a framework, attempt to use the libraries # from the framework at the given location so that linking works # against Tk.framework installed in an arbitary location. case ${TK_DEFS} in *TK_FRAMEWORK*) if test -f ${TK_BIN_DIR}/${TK_LIB_FILE}; then for i in "`cd ${TK_BIN_DIR}; pwd`" \ "`cd ${TK_BIN_DIR}/../..; pwd`"; do if test "`basename "$i"`" = "${TK_LIB_FILE}.framework"; then TK_LIB_SPEC="-F`dirname "$i"` -framework ${TK_LIB_FILE}" break fi done fi if test -f ${TK_BIN_DIR}/${TK_STUB_LIB_FILE}; then TK_STUB_LIB_SPEC="-L${TK_BIN_DIR} ${TK_STUB_LIB_FLAG}" TK_STUB_LIB_PATH="${TK_BIN_DIR}/${TK_STUB_LIB_FILE}" fi ;; esac fi # eval is required to do the TK_DBGX substitution eval "TK_LIB_FLAG=\"${TK_LIB_FLAG}\"" eval "TK_LIB_SPEC=\"${TK_LIB_SPEC}\"" eval "TK_STUB_LIB_FLAG=\"${TK_STUB_LIB_FLAG}\"" eval "TK_STUB_LIB_SPEC=\"${TK_STUB_LIB_SPEC}\"" # Ensure windowingsystem is defined if test "${TEA_PLATFORM}" = "unix" ; then case ${TK_DEFS} in *MAC_OSX_TK*) cat >>confdefs.h <<\_ACEOF #define MAC_OSX_TK 1 _ACEOF TEA_WINDOWINGSYSTEM="aqua" ;; *) TEA_WINDOWINGSYSTEM="x11" ;; esac elif test "${TEA_PLATFORM}" = "windows" ; then TEA_WINDOWINGSYSTEM="win32" fi #----------------------------------------------------------------------- # Handle the --prefix=... option by defaulting to what Tcl gave. # Must be called after TEA_LOAD_TCLCONFIG and before TEA_SETUP_COMPILER. #----------------------------------------------------------------------- if test "${prefix}" = "NONE"; then prefix_default=yes if test x"${TCL_PREFIX}" != x; then { echo "$as_me:$LINENO: --prefix defaulting to TCL_PREFIX ${TCL_PREFIX}" >&5 echo "$as_me: --prefix defaulting to TCL_PREFIX ${TCL_PREFIX}" >&6;} prefix=${TCL_PREFIX} else { echo "$as_me:$LINENO: --prefix defaulting to /usr/local" >&5 echo "$as_me: --prefix defaulting to /usr/local" >&6;} prefix=/usr/local fi fi if test "${exec_prefix}" = "NONE" -a x"${prefix_default}" = x"yes" \ -o x"${exec_prefix_default}" = x"yes" ; then if test x"${TCL_EXEC_PREFIX}" != x; then { echo "$as_me:$LINENO: --exec-prefix defaulting to TCL_EXEC_PREFIX ${TCL_EXEC_PREFIX}" >&5 echo "$as_me: --exec-prefix defaulting to TCL_EXEC_PREFIX ${TCL_EXEC_PREFIX}" >&6;} exec_prefix=${TCL_EXEC_PREFIX} else { echo "$as_me:$LINENO: --exec-prefix defaulting to ${prefix}" >&5 echo "$as_me: --exec-prefix defaulting to ${prefix}" >&6;} exec_prefix=$prefix fi fi #----------------------------------------------------------------------- # Standard compiler checks. # This sets up CC by using the CC env var, or looks for gcc otherwise. # This also calls AC_PROG_CC, AC_PROG_INSTALL and a few others to create # the basic setup necessary to compile executables. #----------------------------------------------------------------------- # Don't put any macros that use the compiler (e.g. AC_TRY_COMPILE) # in this macro, they need to go into TEA_SETUP_COMPILER instead. # If the user did not set CFLAGS, set it now to keep # the AC_PROG_CC macro from adding "-g -O2". if test "${CFLAGS+set}" != "set" ; then CFLAGS="" fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. set dummy ${ac_tool_prefix}gcc; ac_word=$2 echo "$as_me:$LINENO: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 if test "${ac_cv_prog_CC+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}gcc" echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then echo "$as_me:$LINENO: result: $CC" >&5 echo "${ECHO_T}$CC" >&6 else echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6 fi fi if test -z "$ac_cv_prog_CC"; then ac_ct_CC=$CC # Extract the first word of "gcc", so it can be a program name with args. set dummy gcc; ac_word=$2 echo "$as_me:$LINENO: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 if test "${ac_cv_prog_ac_ct_CC+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="gcc" echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then echo "$as_me:$LINENO: result: $ac_ct_CC" >&5 echo "${ECHO_T}$ac_ct_CC" >&6 else echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6 fi CC=$ac_ct_CC else CC="$ac_cv_prog_CC" fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. set dummy ${ac_tool_prefix}cc; ac_word=$2 echo "$as_me:$LINENO: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 if test "${ac_cv_prog_CC+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}cc" echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then echo "$as_me:$LINENO: result: $CC" >&5 echo "${ECHO_T}$CC" >&6 else echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6 fi fi if test -z "$ac_cv_prog_CC"; then ac_ct_CC=$CC # Extract the first word of "cc", so it can be a program name with args. set dummy cc; ac_word=$2 echo "$as_me:$LINENO: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 if test "${ac_cv_prog_ac_ct_CC+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="cc" echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then echo "$as_me:$LINENO: result: $ac_ct_CC" >&5 echo "${ECHO_T}$ac_ct_CC" >&6 else echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6 fi CC=$ac_ct_CC else CC="$ac_cv_prog_CC" fi fi if test -z "$CC"; then # Extract the first word of "cc", so it can be a program name with args. set dummy cc; ac_word=$2 echo "$as_me:$LINENO: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 if test "${ac_cv_prog_CC+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else ac_prog_rejected=no as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then ac_prog_rejected=yes continue fi ac_cv_prog_CC="cc" echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done if test $ac_prog_rejected = yes; then # We found a bogon in the path, so make sure we never use it. set dummy $ac_cv_prog_CC shift if test $# != 0; then # We chose a different compiler from the bogus one. # However, it has the same basename, so the bogon will be chosen # first if we set CC to just the basename; use the full file name. shift ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" fi fi fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then echo "$as_me:$LINENO: result: $CC" >&5 echo "${ECHO_T}$CC" >&6 else echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6 fi fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then for ac_prog in cl do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 echo "$as_me:$LINENO: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 if test "${ac_cv_prog_CC+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="$ac_tool_prefix$ac_prog" echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then echo "$as_me:$LINENO: result: $CC" >&5 echo "${ECHO_T}$CC" >&6 else echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6 fi test -n "$CC" && break done fi if test -z "$CC"; then ac_ct_CC=$CC for ac_prog in cl do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 echo "$as_me:$LINENO: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 if test "${ac_cv_prog_ac_ct_CC+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="$ac_prog" echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then echo "$as_me:$LINENO: result: $ac_ct_CC" >&5 echo "${ECHO_T}$ac_ct_CC" >&6 else echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6 fi test -n "$ac_ct_CC" && break done CC=$ac_ct_CC fi fi test -z "$CC" && { { echo "$as_me:$LINENO: error: no acceptable C compiler found in \$PATH See \`config.log' for more details." >&5 echo "$as_me: error: no acceptable C compiler found in \$PATH See \`config.log' for more details." >&2;} { (exit 1); exit 1; }; } # Provide some information about the compiler. echo "$as_me:$LINENO:" \ "checking for C compiler version" >&5 ac_compiler=`set X $ac_compile; echo $2` { (eval echo "$as_me:$LINENO: \"$ac_compiler --version &5\"") >&5 (eval $ac_compiler --version &5) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } { (eval echo "$as_me:$LINENO: \"$ac_compiler -v &5\"") >&5 (eval $ac_compiler -v &5) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } { (eval echo "$as_me:$LINENO: \"$ac_compiler -V &5\"") >&5 (eval $ac_compiler -V &5) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ int main () { ; return 0; } _ACEOF ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files a.out a.exe b.out" # Try to create an executable without -o first, disregard a.out. # It will help us diagnose broken compilers, and finding out an intuition # of exeext. echo "$as_me:$LINENO: checking for C compiler default output file name" >&5 echo $ECHO_N "checking for C compiler default output file name... $ECHO_C" >&6 ac_link_default=`echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` if { (eval echo "$as_me:$LINENO: \"$ac_link_default\"") >&5 (eval $ac_link_default) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; then # Find the output, starting from the most likely. This scheme is # not robust to junk in `.', hence go to wildcards (a.*) only as a last # resort. # Be careful to initialize this variable, since it used to be cached. # Otherwise an old cache value of `no' led to `EXEEXT = no' in a Makefile. ac_cv_exeext= # b.out is created by i960 compilers. for ac_file in a_out.exe a.exe conftest.exe a.out conftest a.* conftest.* b.out do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.o | *.obj ) ;; conftest.$ac_ext ) # This is the source file. ;; [ab].out ) # We found the default executable, but exeext='' is most # certainly right. break;; *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` # FIXME: I believe we export ac_cv_exeext for Libtool, # but it would be cool to find out if it's true. Does anybody # maintain Libtool? --akim. export ac_cv_exeext break;; * ) break;; esac done else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { echo "$as_me:$LINENO: error: C compiler cannot create executables See \`config.log' for more details." >&5 echo "$as_me: error: C compiler cannot create executables See \`config.log' for more details." >&2;} { (exit 77); exit 77; }; } fi ac_exeext=$ac_cv_exeext echo "$as_me:$LINENO: result: $ac_file" >&5 echo "${ECHO_T}$ac_file" >&6 # Check the compiler produces executables we can run. If not, either # the compiler is broken, or we cross compile. echo "$as_me:$LINENO: checking whether the C compiler works" >&5 echo $ECHO_N "checking whether the C compiler works... $ECHO_C" >&6 # FIXME: These cross compiler hacks should be removed for Autoconf 3.0 # If not cross compiling, check that we can run a simple program. if test "$cross_compiling" != yes; then if { ac_try='./$ac_file' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then cross_compiling=no else if test "$cross_compiling" = maybe; then cross_compiling=yes else { { echo "$as_me:$LINENO: error: cannot run C compiled programs. If you meant to cross compile, use \`--host'. See \`config.log' for more details." >&5 echo "$as_me: error: cannot run C compiled programs. If you meant to cross compile, use \`--host'. See \`config.log' for more details." >&2;} { (exit 1); exit 1; }; } fi fi fi echo "$as_me:$LINENO: result: yes" >&5 echo "${ECHO_T}yes" >&6 rm -f a.out a.exe conftest$ac_cv_exeext b.out ac_clean_files=$ac_clean_files_save # Check the compiler produces executables we can run. If not, either # the compiler is broken, or we cross compile. echo "$as_me:$LINENO: checking whether we are cross compiling" >&5 echo $ECHO_N "checking whether we are cross compiling... $ECHO_C" >&6 echo "$as_me:$LINENO: result: $cross_compiling" >&5 echo "${ECHO_T}$cross_compiling" >&6 echo "$as_me:$LINENO: checking for suffix of executables" >&5 echo $ECHO_N "checking for suffix of executables... $ECHO_C" >&6 if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; then # If both `conftest.exe' and `conftest' are `present' (well, observable) # catch `conftest.exe'. For instance with Cygwin, `ls conftest' will # work properly (i.e., refer to `conftest.exe'), while it won't with # `rm'. for ac_file in conftest.exe conftest conftest.*; do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.o | *.obj ) ;; *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` export ac_cv_exeext break;; * ) break;; esac done else { { echo "$as_me:$LINENO: error: cannot compute suffix of executables: cannot compile and link See \`config.log' for more details." >&5 echo "$as_me: error: cannot compute suffix of executables: cannot compile and link See \`config.log' for more details." >&2;} { (exit 1); exit 1; }; } fi rm -f conftest$ac_cv_exeext echo "$as_me:$LINENO: result: $ac_cv_exeext" >&5 echo "${ECHO_T}$ac_cv_exeext" >&6 rm -f conftest.$ac_ext EXEEXT=$ac_cv_exeext ac_exeext=$EXEEXT echo "$as_me:$LINENO: checking for suffix of object files" >&5 echo $ECHO_N "checking for suffix of object files... $ECHO_C" >&6 if test "${ac_cv_objext+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ int main () { ; return 0; } _ACEOF rm -f conftest.o conftest.obj if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; then for ac_file in `(ls conftest.o conftest.obj; ls conftest.*) 2>/dev/null`; do case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg ) ;; *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` break;; esac done else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { echo "$as_me:$LINENO: error: cannot compute suffix of object files: cannot compile See \`config.log' for more details." >&5 echo "$as_me: error: cannot compute suffix of object files: cannot compile See \`config.log' for more details." >&2;} { (exit 1); exit 1; }; } fi rm -f conftest.$ac_cv_objext conftest.$ac_ext fi echo "$as_me:$LINENO: result: $ac_cv_objext" >&5 echo "${ECHO_T}$ac_cv_objext" >&6 OBJEXT=$ac_cv_objext ac_objext=$OBJEXT echo "$as_me:$LINENO: checking whether we are using the GNU C compiler" >&5 echo $ECHO_N "checking whether we are using the GNU C compiler... $ECHO_C" >&6 if test "${ac_cv_c_compiler_gnu+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ int main () { #ifndef __GNUC__ choke me #endif ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_compiler_gnu=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_compiler_gnu=no fi rm -f conftest.err conftest.$ac_objext conftest.$ac_ext ac_cv_c_compiler_gnu=$ac_compiler_gnu fi echo "$as_me:$LINENO: result: $ac_cv_c_compiler_gnu" >&5 echo "${ECHO_T}$ac_cv_c_compiler_gnu" >&6 GCC=`test $ac_compiler_gnu = yes && echo yes` ac_test_CFLAGS=${CFLAGS+set} ac_save_CFLAGS=$CFLAGS CFLAGS="-g" echo "$as_me:$LINENO: checking whether $CC accepts -g" >&5 echo $ECHO_N "checking whether $CC accepts -g... $ECHO_C" >&6 if test "${ac_cv_prog_cc_g+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ int main () { ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_prog_cc_g=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_prog_cc_g=no fi rm -f conftest.err conftest.$ac_objext conftest.$ac_ext fi echo "$as_me:$LINENO: result: $ac_cv_prog_cc_g" >&5 echo "${ECHO_T}$ac_cv_prog_cc_g" >&6 if test "$ac_test_CFLAGS" = set; then CFLAGS=$ac_save_CFLAGS elif test $ac_cv_prog_cc_g = yes; then if test "$GCC" = yes; then CFLAGS="-g -O2" else CFLAGS="-g" fi else if test "$GCC" = yes; then CFLAGS="-O2" else CFLAGS= fi fi echo "$as_me:$LINENO: checking for $CC option to accept ANSI C" >&5 echo $ECHO_N "checking for $CC option to accept ANSI C... $ECHO_C" >&6 if test "${ac_cv_prog_cc_stdc+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else ac_cv_prog_cc_stdc=no ac_save_CC=$CC cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include #include #include #include /* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ struct buf { int x; }; FILE * (*rcsopen) (struct buf *, struct stat *, int); static char *e (p, i) char **p; int i; { return p[i]; } static char *f (char * (*g) (char **, int), char **p, ...) { char *s; va_list v; va_start (v,p); s = g (p, va_arg (v,int)); va_end (v); return s; } /* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has function prototypes and stuff, but not '\xHH' hex character constants. These don't provoke an error unfortunately, instead are silently treated as 'x'. The following induces an error, until -std1 is added to get proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an array size at least. It's necessary to write '\x00'==0 to get something that's true only with -std1. */ int osf4_cc_array ['\x00' == 0 ? 1 : -1]; int test (int i, double x); struct s1 {int (*f) (int a);}; struct s2 {int (*f) (double a);}; int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); int argc; char **argv; int main () { return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; ; return 0; } _ACEOF # Don't try gcc -ansi; that turns off useful extensions and # breaks some systems' header files. # AIX -qlanglvl=ansi # Ultrix and OSF/1 -std1 # HP-UX 10.20 and later -Ae # HP-UX older versions -Aa -D_HPUX_SOURCE # SVR4 -Xc -D__EXTENSIONS__ for ac_arg in "" -qlanglvl=ansi -std1 -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" do CC="$ac_save_CC $ac_arg" rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_prog_cc_stdc=$ac_arg break else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 fi rm -f conftest.err conftest.$ac_objext done rm -f conftest.$ac_ext conftest.$ac_objext CC=$ac_save_CC fi case "x$ac_cv_prog_cc_stdc" in x|xno) echo "$as_me:$LINENO: result: none needed" >&5 echo "${ECHO_T}none needed" >&6 ;; *) echo "$as_me:$LINENO: result: $ac_cv_prog_cc_stdc" >&5 echo "${ECHO_T}$ac_cv_prog_cc_stdc" >&6 CC="$CC $ac_cv_prog_cc_stdc" ;; esac # Some people use a C++ compiler to compile C. Since we use `exit', # in C++ we need to declare it. In case someone uses the same compiler # for both compiling C and C++ we need to have the C++ compiler decide # the declaration of exit, since it's the most demanding environment. cat >conftest.$ac_ext <<_ACEOF #ifndef __cplusplus choke me #endif _ACEOF rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then for ac_declaration in \ '' \ 'extern "C" void std::exit (int) throw (); using std::exit;' \ 'extern "C" void std::exit (int); using std::exit;' \ 'extern "C" void exit (int) throw ();' \ 'extern "C" void exit (int);' \ 'void exit (int);' do cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_declaration #include int main () { exit (42); ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then : else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 continue fi rm -f conftest.err conftest.$ac_objext conftest.$ac_ext cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_declaration int main () { exit (42); ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then break else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 fi rm -f conftest.err conftest.$ac_objext conftest.$ac_ext done rm -f conftest* if test -n "$ac_declaration"; then echo '#ifdef __cplusplus' >>confdefs.h echo $ac_declaration >>confdefs.h echo '#endif' >>confdefs.h fi else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 fi rm -f conftest.err conftest.$ac_objext conftest.$ac_ext ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu echo "$as_me:$LINENO: checking how to run the C preprocessor" >&5 echo $ECHO_N "checking how to run the C preprocessor... $ECHO_C" >&6 # On Suns, sometimes $CPP names a directory. if test -n "$CPP" && test -d "$CPP"; then CPP= fi if test -z "$CPP"; then if test "${ac_cv_prog_CPP+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else # Double quotes because CPP needs to be expanded for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp" do ac_preproc_ok=false for ac_c_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. # Prefer to if __STDC__ is defined, since # exists even on freestanding compilers. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #ifdef __STDC__ # include #else # include #endif Syntax error _ACEOF if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } >/dev/null; then if test -s conftest.err; then ac_cpp_err=$ac_c_preproc_warn_flag ac_cpp_err=$ac_cpp_err$ac_c_werror_flag else ac_cpp_err= fi else ac_cpp_err=yes fi if test -z "$ac_cpp_err"; then : else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 # Broken: fails on valid input. continue fi rm -f conftest.err conftest.$ac_ext # OK, works on sane cases. Now check whether non-existent headers # can be detected and how. cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include _ACEOF if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } >/dev/null; then if test -s conftest.err; then ac_cpp_err=$ac_c_preproc_warn_flag ac_cpp_err=$ac_cpp_err$ac_c_werror_flag else ac_cpp_err= fi else ac_cpp_err=yes fi if test -z "$ac_cpp_err"; then # Broken: success on invalid input. continue else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 # Passes both tests. ac_preproc_ok=: break fi rm -f conftest.err conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.err conftest.$ac_ext if $ac_preproc_ok; then break fi done ac_cv_prog_CPP=$CPP fi CPP=$ac_cv_prog_CPP else ac_cv_prog_CPP=$CPP fi echo "$as_me:$LINENO: result: $CPP" >&5 echo "${ECHO_T}$CPP" >&6 ac_preproc_ok=false for ac_c_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. # Prefer to if __STDC__ is defined, since # exists even on freestanding compilers. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #ifdef __STDC__ # include #else # include #endif Syntax error _ACEOF if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } >/dev/null; then if test -s conftest.err; then ac_cpp_err=$ac_c_preproc_warn_flag ac_cpp_err=$ac_cpp_err$ac_c_werror_flag else ac_cpp_err= fi else ac_cpp_err=yes fi if test -z "$ac_cpp_err"; then : else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 # Broken: fails on valid input. continue fi rm -f conftest.err conftest.$ac_ext # OK, works on sane cases. Now check whether non-existent headers # can be detected and how. cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include _ACEOF if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } >/dev/null; then if test -s conftest.err; then ac_cpp_err=$ac_c_preproc_warn_flag ac_cpp_err=$ac_cpp_err$ac_c_werror_flag else ac_cpp_err= fi else ac_cpp_err=yes fi if test -z "$ac_cpp_err"; then # Broken: success on invalid input. continue else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 # Passes both tests. ac_preproc_ok=: break fi rm -f conftest.err conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.err conftest.$ac_ext if $ac_preproc_ok; then : else { { echo "$as_me:$LINENO: error: C preprocessor \"$CPP\" fails sanity check See \`config.log' for more details." >&5 echo "$as_me: error: C preprocessor \"$CPP\" fails sanity check See \`config.log' for more details." >&2;} { (exit 1); exit 1; }; } fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu # Find a good install program. We prefer a C program (faster), # so one script is as good as another. But avoid the broken or # incompatible versions: # SysV /etc/install, /usr/sbin/install # SunOS /usr/etc/install # IRIX /sbin/install # AIX /bin/install # AmigaOS /C/install, which installs bootblocks on floppy discs # AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag # AFS /usr/afsws/bin/install, which mishandles nonexistent args # SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" # OS/2's system install, which has a completely different semantic # ./install, which can be erroneously created by make from ./install.sh. echo "$as_me:$LINENO: checking for a BSD-compatible install" >&5 echo $ECHO_N "checking for a BSD-compatible install... $ECHO_C" >&6 if test -z "$INSTALL"; then if test "${ac_cv_path_install+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. # Account for people who put trailing slashes in PATH elements. case $as_dir/ in ./ | .// | /cC/* | \ /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \ ?:\\/os2\\/install\\/* | ?:\\/OS2\\/INSTALL\\/* | \ /usr/ucb/* ) ;; *) # OSF1 and SCO ODT 3.0 have their own names for install. # Don't use installbsd from OSF since it installs stuff as root # by default. for ac_prog in ginstall scoinst install; do for ac_exec_ext in '' $ac_executable_extensions; do if $as_executable_p "$as_dir/$ac_prog$ac_exec_ext"; then if test $ac_prog = install && grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then # AIX install. It has an incompatible calling convention. : elif test $ac_prog = install && grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then # program-specific install script used by HP pwplus--don't use. : else ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c" break 3 fi fi done done ;; esac done fi if test "${ac_cv_path_install+set}" = set; then INSTALL=$ac_cv_path_install else # As a last resort, use the slow shell script. We don't cache a # path for INSTALL within a source directory, because that will # break other packages using the cache if that directory is # removed, or if the path is relative. INSTALL=$ac_install_sh fi fi echo "$as_me:$LINENO: result: $INSTALL" >&5 echo "${ECHO_T}$INSTALL" >&6 # Use test -z because SunOS4 sh mishandles braces in ${var-val}. # It thinks the first close brace ends the variable substitution. test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}' test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' #-------------------------------------------------------------------- # Checks to see if the make program sets the $MAKE variable. #-------------------------------------------------------------------- echo "$as_me:$LINENO: checking whether ${MAKE-make} sets \$(MAKE)" >&5 echo $ECHO_N "checking whether ${MAKE-make} sets \$(MAKE)... $ECHO_C" >&6 set dummy ${MAKE-make}; ac_make=`echo "$2" | sed 'y,:./+-,___p_,'` if eval "test \"\${ac_cv_prog_make_${ac_make}_set+set}\" = set"; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.make <<\_ACEOF all: @echo 'ac_maketemp="$(MAKE)"' _ACEOF # GNU make sometimes prints "make[1]: Entering...", which would confuse us. eval `${MAKE-make} -f conftest.make 2>/dev/null | grep temp=` if test -n "$ac_maketemp"; then eval ac_cv_prog_make_${ac_make}_set=yes else eval ac_cv_prog_make_${ac_make}_set=no fi rm -f conftest.make fi if eval "test \"`echo '$ac_cv_prog_make_'${ac_make}_set`\" = yes"; then echo "$as_me:$LINENO: result: yes" >&5 echo "${ECHO_T}yes" >&6 SET_MAKE= else echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6 SET_MAKE="MAKE=${MAKE-make}" fi #-------------------------------------------------------------------- # Find ranlib #-------------------------------------------------------------------- if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args. set dummy ${ac_tool_prefix}ranlib; ac_word=$2 echo "$as_me:$LINENO: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 if test "${ac_cv_prog_RANLIB+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else if test -n "$RANLIB"; then ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib" echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done fi fi RANLIB=$ac_cv_prog_RANLIB if test -n "$RANLIB"; then echo "$as_me:$LINENO: result: $RANLIB" >&5 echo "${ECHO_T}$RANLIB" >&6 else echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6 fi fi if test -z "$ac_cv_prog_RANLIB"; then ac_ct_RANLIB=$RANLIB # Extract the first word of "ranlib", so it can be a program name with args. set dummy ranlib; ac_word=$2 echo "$as_me:$LINENO: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 if test "${ac_cv_prog_ac_ct_RANLIB+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else if test -n "$ac_ct_RANLIB"; then ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_RANLIB="ranlib" echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done test -z "$ac_cv_prog_ac_ct_RANLIB" && ac_cv_prog_ac_ct_RANLIB=":" fi fi ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB if test -n "$ac_ct_RANLIB"; then echo "$as_me:$LINENO: result: $ac_ct_RANLIB" >&5 echo "${ECHO_T}$ac_ct_RANLIB" >&6 else echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6 fi RANLIB=$ac_ct_RANLIB else RANLIB="$ac_cv_prog_RANLIB" fi #-------------------------------------------------------------------- # Determines the correct binary file extension (.o, .obj, .exe etc.) #-------------------------------------------------------------------- echo "$as_me:$LINENO: checking for egrep" >&5 echo $ECHO_N "checking for egrep... $ECHO_C" >&6 if test "${ac_cv_prog_egrep+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else if echo a | (grep -E '(a|b)') >/dev/null 2>&1 then ac_cv_prog_egrep='grep -E' else ac_cv_prog_egrep='egrep' fi fi echo "$as_me:$LINENO: result: $ac_cv_prog_egrep" >&5 echo "${ECHO_T}$ac_cv_prog_egrep" >&6 EGREP=$ac_cv_prog_egrep echo "$as_me:$LINENO: checking for ANSI C header files" >&5 echo $ECHO_N "checking for ANSI C header files... $ECHO_C" >&6 if test "${ac_cv_header_stdc+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include #include #include #include int main () { ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_header_stdc=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_header_stdc=no fi rm -f conftest.err conftest.$ac_objext conftest.$ac_ext if test $ac_cv_header_stdc = yes; then # SunOS 4.x string.h does not declare mem*, contrary to ANSI. cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "memchr" >/dev/null 2>&1; then : else ac_cv_header_stdc=no fi rm -f conftest* fi if test $ac_cv_header_stdc = yes; then # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "free" >/dev/null 2>&1; then : else ac_cv_header_stdc=no fi rm -f conftest* fi if test $ac_cv_header_stdc = yes; then # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. if test "$cross_compiling" = yes; then : else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include #if ((' ' & 0x0FF) == 0x020) # define ISLOWER(c) ('a' <= (c) && (c) <= 'z') # define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) #else # define ISLOWER(c) \ (('a' <= (c) && (c) <= 'i') \ || ('j' <= (c) && (c) <= 'r') \ || ('s' <= (c) && (c) <= 'z')) # define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) #endif #define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) int main () { int i; for (i = 0; i < 256; i++) if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) exit(2); exit (0); } _ACEOF rm -f conftest$ac_exeext if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='./conftest$ac_exeext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then : else echo "$as_me: program exited with status $ac_status" >&5 echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ( exit $ac_status ) ac_cv_header_stdc=no fi rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext fi fi fi echo "$as_me:$LINENO: result: $ac_cv_header_stdc" >&5 echo "${ECHO_T}$ac_cv_header_stdc" >&6 if test $ac_cv_header_stdc = yes; then cat >>confdefs.h <<\_ACEOF #define STDC_HEADERS 1 _ACEOF fi # On IRIX 5.3, sys/types and inttypes.h are conflicting. for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \ inttypes.h stdint.h unistd.h do as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` echo "$as_me:$LINENO: checking for $ac_header" >&5 echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 if eval "test \"\${$as_ac_Header+set}\" = set"; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_includes_default #include <$ac_header> _ACEOF rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then eval "$as_ac_Header=yes" else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 eval "$as_ac_Header=no" fi rm -f conftest.err conftest.$ac_objext conftest.$ac_ext fi echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 if test `eval echo '${'$as_ac_Header'}'` = yes; then cat >>confdefs.h <<_ACEOF #define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF fi done # Any macros that use the compiler (e.g. AC_TRY_COMPILE) have to go here. #------------------------------------------------------------------------ # If we're using GCC, see if the compiler understands -pipe. If so, use it. # It makes compiling go faster. (This is only a performance feature.) #------------------------------------------------------------------------ if test -z "$no_pipe" -a -n "$GCC"; then echo "$as_me:$LINENO: checking if the compiler understands -pipe" >&5 echo $ECHO_N "checking if the compiler understands -pipe... $ECHO_C" >&6 OLDCC="$CC" CC="$CC -pipe" cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ int main () { ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then echo "$as_me:$LINENO: result: yes" >&5 echo "${ECHO_T}yes" >&6 else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 CC="$OLDCC" echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6 fi rm -f conftest.err conftest.$ac_objext conftest.$ac_ext fi #-------------------------------------------------------------------- # Common compiler flag setup #-------------------------------------------------------------------- echo "$as_me:$LINENO: checking whether byte ordering is bigendian" >&5 echo $ECHO_N "checking whether byte ordering is bigendian... $ECHO_C" >&6 if test "${ac_cv_c_bigendian+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else # See if sys/param.h defines the BYTE_ORDER macro. cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include #include int main () { #if !BYTE_ORDER || !BIG_ENDIAN || !LITTLE_ENDIAN bogus endian macros #endif ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then # It does; now see whether it defined to BIG_ENDIAN or not. cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include #include int main () { #if BYTE_ORDER != BIG_ENDIAN not big endian #endif ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_c_bigendian=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_c_bigendian=no fi rm -f conftest.err conftest.$ac_objext conftest.$ac_ext else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 # It does not; compile a test program. if test "$cross_compiling" = yes; then # try to guess the endianness by grepping values into an object file ac_cv_c_bigendian=unknown cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ short ascii_mm[] = { 0x4249, 0x4765, 0x6E44, 0x6961, 0x6E53, 0x7953, 0 }; short ascii_ii[] = { 0x694C, 0x5454, 0x656C, 0x6E45, 0x6944, 0x6E61, 0 }; void _ascii () { char *s = (char *) ascii_mm; s = (char *) ascii_ii; } short ebcdic_ii[] = { 0x89D3, 0xE3E3, 0x8593, 0x95C5, 0x89C4, 0x9581, 0 }; short ebcdic_mm[] = { 0xC2C9, 0xC785, 0x95C4, 0x8981, 0x95E2, 0xA8E2, 0 }; void _ebcdic () { char *s = (char *) ebcdic_mm; s = (char *) ebcdic_ii; } int main () { _ascii (); _ebcdic (); ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then if grep BIGenDianSyS conftest.$ac_objext >/dev/null ; then ac_cv_c_bigendian=yes fi if grep LiTTleEnDian conftest.$ac_objext >/dev/null ; then if test "$ac_cv_c_bigendian" = unknown; then ac_cv_c_bigendian=no else # finding both strings is unlikely to happen, but who knows? ac_cv_c_bigendian=unknown fi fi else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 fi rm -f conftest.err conftest.$ac_objext conftest.$ac_ext else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ int main () { /* Are we little or big endian? From Harbison&Steele. */ union { long l; char c[sizeof (long)]; } u; u.l = 1; exit (u.c[sizeof (long) - 1] == 1); } _ACEOF rm -f conftest$ac_exeext if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='./conftest$ac_exeext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_c_bigendian=no else echo "$as_me: program exited with status $ac_status" >&5 echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ( exit $ac_status ) ac_cv_c_bigendian=yes fi rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext fi fi rm -f conftest.err conftest.$ac_objext conftest.$ac_ext fi echo "$as_me:$LINENO: result: $ac_cv_c_bigendian" >&5 echo "${ECHO_T}$ac_cv_c_bigendian" >&6 case $ac_cv_c_bigendian in yes) cat >>confdefs.h <<\_ACEOF #define WORDS_BIGENDIAN 1 _ACEOF ;; no) ;; *) { { echo "$as_me:$LINENO: error: unknown endianness presetting ac_cv_c_bigendian=no (or yes) will help" >&5 echo "$as_me: error: unknown endianness presetting ac_cv_c_bigendian=no (or yes) will help" >&2;} { (exit 1); exit 1; }; } ;; esac if test "${TEA_PLATFORM}" = "unix" ; then #-------------------------------------------------------------------- # On a few very rare systems, all of the libm.a stuff is # already in libc.a. Set compiler flags accordingly. # Also, Linux requires the "ieee" library for math to work # right (and it must appear before "-lm"). #-------------------------------------------------------------------- echo "$as_me:$LINENO: checking for sin" >&5 echo $ECHO_N "checking for sin... $ECHO_C" >&6 if test "${ac_cv_func_sin+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ /* Define sin to an innocuous variant, in case declares sin. For example, HP-UX 11i declares gettimeofday. */ #define sin innocuous_sin /* System header to define __stub macros and hopefully few prototypes, which can conflict with char sin (); below. Prefer to if __STDC__ is defined, since exists even on freestanding compilers. */ #ifdef __STDC__ # include #else # include #endif #undef sin /* Override any gcc2 internal prototype to avoid an error. */ #ifdef __cplusplus extern "C" { #endif /* We use char because int might match the return type of a gcc2 builtin and then its argument prototype would still apply. */ char sin (); /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ #if defined (__stub_sin) || defined (__stub___sin) choke me #else char (*f) () = sin; #endif #ifdef __cplusplus } #endif int main () { return f != sin; ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest$ac_exeext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_func_sin=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_func_sin=no fi rm -f conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi echo "$as_me:$LINENO: result: $ac_cv_func_sin" >&5 echo "${ECHO_T}$ac_cv_func_sin" >&6 if test $ac_cv_func_sin = yes; then MATH_LIBS="" else MATH_LIBS="-lm" fi echo "$as_me:$LINENO: checking for main in -lieee" >&5 echo $ECHO_N "checking for main in -lieee... $ECHO_C" >&6 if test "${ac_cv_lib_ieee_main+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lieee $LIBS" cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ int main () { main (); ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest$ac_exeext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_lib_ieee_main=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_lib_ieee_main=no fi rm -f conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi echo "$as_me:$LINENO: result: $ac_cv_lib_ieee_main" >&5 echo "${ECHO_T}$ac_cv_lib_ieee_main" >&6 if test $ac_cv_lib_ieee_main = yes; then MATH_LIBS="-lieee $MATH_LIBS" fi #-------------------------------------------------------------------- # Interactive UNIX requires -linet instead of -lsocket, plus it # needs net/errno.h to define the socket-related error codes. #-------------------------------------------------------------------- echo "$as_me:$LINENO: checking for main in -linet" >&5 echo $ECHO_N "checking for main in -linet... $ECHO_C" >&6 if test "${ac_cv_lib_inet_main+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-linet $LIBS" cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ int main () { main (); ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest$ac_exeext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_lib_inet_main=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_lib_inet_main=no fi rm -f conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi echo "$as_me:$LINENO: result: $ac_cv_lib_inet_main" >&5 echo "${ECHO_T}$ac_cv_lib_inet_main" >&6 if test $ac_cv_lib_inet_main = yes; then LIBS="$LIBS -linet" fi if test "${ac_cv_header_net_errno_h+set}" = set; then echo "$as_me:$LINENO: checking for net/errno.h" >&5 echo $ECHO_N "checking for net/errno.h... $ECHO_C" >&6 if test "${ac_cv_header_net_errno_h+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 fi echo "$as_me:$LINENO: result: $ac_cv_header_net_errno_h" >&5 echo "${ECHO_T}$ac_cv_header_net_errno_h" >&6 else # Is the header compilable? echo "$as_me:$LINENO: checking net/errno.h usability" >&5 echo $ECHO_N "checking net/errno.h usability... $ECHO_C" >&6 cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_includes_default #include _ACEOF rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_header_compiler=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_header_compiler=no fi rm -f conftest.err conftest.$ac_objext conftest.$ac_ext echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 echo "${ECHO_T}$ac_header_compiler" >&6 # Is the header present? echo "$as_me:$LINENO: checking net/errno.h presence" >&5 echo $ECHO_N "checking net/errno.h presence... $ECHO_C" >&6 cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include _ACEOF if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } >/dev/null; then if test -s conftest.err; then ac_cpp_err=$ac_c_preproc_warn_flag ac_cpp_err=$ac_cpp_err$ac_c_werror_flag else ac_cpp_err= fi else ac_cpp_err=yes fi if test -z "$ac_cpp_err"; then ac_header_preproc=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_header_preproc=no fi rm -f conftest.err conftest.$ac_ext echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 echo "${ECHO_T}$ac_header_preproc" >&6 # So? What about this header? case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in yes:no: ) { echo "$as_me:$LINENO: WARNING: net/errno.h: accepted by the compiler, rejected by the preprocessor!" >&5 echo "$as_me: WARNING: net/errno.h: accepted by the compiler, rejected by the preprocessor!" >&2;} { echo "$as_me:$LINENO: WARNING: net/errno.h: proceeding with the compiler's result" >&5 echo "$as_me: WARNING: net/errno.h: proceeding with the compiler's result" >&2;} ac_header_preproc=yes ;; no:yes:* ) { echo "$as_me:$LINENO: WARNING: net/errno.h: present but cannot be compiled" >&5 echo "$as_me: WARNING: net/errno.h: present but cannot be compiled" >&2;} { echo "$as_me:$LINENO: WARNING: net/errno.h: check for missing prerequisite headers?" >&5 echo "$as_me: WARNING: net/errno.h: check for missing prerequisite headers?" >&2;} { echo "$as_me:$LINENO: WARNING: net/errno.h: see the Autoconf documentation" >&5 echo "$as_me: WARNING: net/errno.h: see the Autoconf documentation" >&2;} { echo "$as_me:$LINENO: WARNING: net/errno.h: section \"Present But Cannot Be Compiled\"" >&5 echo "$as_me: WARNING: net/errno.h: section \"Present But Cannot Be Compiled\"" >&2;} { echo "$as_me:$LINENO: WARNING: net/errno.h: proceeding with the preprocessor's result" >&5 echo "$as_me: WARNING: net/errno.h: proceeding with the preprocessor's result" >&2;} { echo "$as_me:$LINENO: WARNING: net/errno.h: in the future, the compiler will take precedence" >&5 echo "$as_me: WARNING: net/errno.h: in the future, the compiler will take precedence" >&2;} ( cat <<\_ASBOX ## --------------------------------- ## ## Report this to the Tkhtml lists. ## ## --------------------------------- ## _ASBOX ) | sed "s/^/$as_me: WARNING: /" >&2 ;; esac echo "$as_me:$LINENO: checking for net/errno.h" >&5 echo $ECHO_N "checking for net/errno.h... $ECHO_C" >&6 if test "${ac_cv_header_net_errno_h+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else ac_cv_header_net_errno_h=$ac_header_preproc fi echo "$as_me:$LINENO: result: $ac_cv_header_net_errno_h" >&5 echo "${ECHO_T}$ac_cv_header_net_errno_h" >&6 fi if test $ac_cv_header_net_errno_h = yes; then cat >>confdefs.h <<\_ACEOF #define HAVE_NET_ERRNO_H 1 _ACEOF fi #-------------------------------------------------------------------- # Check for the existence of the -lsocket and -lnsl libraries. # The order here is important, so that they end up in the right # order in the command line generated by make. Here are some # special considerations: # 1. Use "connect" and "accept" to check for -lsocket, and # "gethostbyname" to check for -lnsl. # 2. Use each function name only once: can't redo a check because # autoconf caches the results of the last check and won't redo it. # 3. Use -lnsl and -lsocket only if they supply procedures that # aren't already present in the normal libraries. This is because # IRIX 5.2 has libraries, but they aren't needed and they're # bogus: they goof up name resolution if used. # 4. On some SVR4 systems, can't use -lsocket without -lnsl too. # To get around this problem, check for both libraries together # if -lsocket doesn't work by itself. #-------------------------------------------------------------------- tcl_checkBoth=0 echo "$as_me:$LINENO: checking for connect" >&5 echo $ECHO_N "checking for connect... $ECHO_C" >&6 if test "${ac_cv_func_connect+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ /* Define connect to an innocuous variant, in case declares connect. For example, HP-UX 11i declares gettimeofday. */ #define connect innocuous_connect /* System header to define __stub macros and hopefully few prototypes, which can conflict with char connect (); below. Prefer to if __STDC__ is defined, since exists even on freestanding compilers. */ #ifdef __STDC__ # include #else # include #endif #undef connect /* Override any gcc2 internal prototype to avoid an error. */ #ifdef __cplusplus extern "C" { #endif /* We use char because int might match the return type of a gcc2 builtin and then its argument prototype would still apply. */ char connect (); /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ #if defined (__stub_connect) || defined (__stub___connect) choke me #else char (*f) () = connect; #endif #ifdef __cplusplus } #endif int main () { return f != connect; ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest$ac_exeext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_func_connect=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_func_connect=no fi rm -f conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi echo "$as_me:$LINENO: result: $ac_cv_func_connect" >&5 echo "${ECHO_T}$ac_cv_func_connect" >&6 if test $ac_cv_func_connect = yes; then tcl_checkSocket=0 else tcl_checkSocket=1 fi if test "$tcl_checkSocket" = 1; then echo "$as_me:$LINENO: checking for setsockopt" >&5 echo $ECHO_N "checking for setsockopt... $ECHO_C" >&6 if test "${ac_cv_func_setsockopt+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ /* Define setsockopt to an innocuous variant, in case declares setsockopt. For example, HP-UX 11i declares gettimeofday. */ #define setsockopt innocuous_setsockopt /* System header to define __stub macros and hopefully few prototypes, which can conflict with char setsockopt (); below. Prefer to if __STDC__ is defined, since exists even on freestanding compilers. */ #ifdef __STDC__ # include #else # include #endif #undef setsockopt /* Override any gcc2 internal prototype to avoid an error. */ #ifdef __cplusplus extern "C" { #endif /* We use char because int might match the return type of a gcc2 builtin and then its argument prototype would still apply. */ char setsockopt (); /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ #if defined (__stub_setsockopt) || defined (__stub___setsockopt) choke me #else char (*f) () = setsockopt; #endif #ifdef __cplusplus } #endif int main () { return f != setsockopt; ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest$ac_exeext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_func_setsockopt=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_func_setsockopt=no fi rm -f conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi echo "$as_me:$LINENO: result: $ac_cv_func_setsockopt" >&5 echo "${ECHO_T}$ac_cv_func_setsockopt" >&6 if test $ac_cv_func_setsockopt = yes; then : else echo "$as_me:$LINENO: checking for setsockopt in -lsocket" >&5 echo $ECHO_N "checking for setsockopt in -lsocket... $ECHO_C" >&6 if test "${ac_cv_lib_socket_setsockopt+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lsocket $LIBS" cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ /* Override any gcc2 internal prototype to avoid an error. */ #ifdef __cplusplus extern "C" #endif /* We use char because int might match the return type of a gcc2 builtin and then its argument prototype would still apply. */ char setsockopt (); int main () { setsockopt (); ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest$ac_exeext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_lib_socket_setsockopt=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_lib_socket_setsockopt=no fi rm -f conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi echo "$as_me:$LINENO: result: $ac_cv_lib_socket_setsockopt" >&5 echo "${ECHO_T}$ac_cv_lib_socket_setsockopt" >&6 if test $ac_cv_lib_socket_setsockopt = yes; then LIBS="$LIBS -lsocket" else tcl_checkBoth=1 fi fi fi if test "$tcl_checkBoth" = 1; then tk_oldLibs=$LIBS LIBS="$LIBS -lsocket -lnsl" echo "$as_me:$LINENO: checking for accept" >&5 echo $ECHO_N "checking for accept... $ECHO_C" >&6 if test "${ac_cv_func_accept+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ /* Define accept to an innocuous variant, in case declares accept. For example, HP-UX 11i declares gettimeofday. */ #define accept innocuous_accept /* System header to define __stub macros and hopefully few prototypes, which can conflict with char accept (); below. Prefer to if __STDC__ is defined, since exists even on freestanding compilers. */ #ifdef __STDC__ # include #else # include #endif #undef accept /* Override any gcc2 internal prototype to avoid an error. */ #ifdef __cplusplus extern "C" { #endif /* We use char because int might match the return type of a gcc2 builtin and then its argument prototype would still apply. */ char accept (); /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ #if defined (__stub_accept) || defined (__stub___accept) choke me #else char (*f) () = accept; #endif #ifdef __cplusplus } #endif int main () { return f != accept; ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest$ac_exeext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_func_accept=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_func_accept=no fi rm -f conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi echo "$as_me:$LINENO: result: $ac_cv_func_accept" >&5 echo "${ECHO_T}$ac_cv_func_accept" >&6 if test $ac_cv_func_accept = yes; then tcl_checkNsl=0 else LIBS=$tk_oldLibs fi fi echo "$as_me:$LINENO: checking for gethostbyname" >&5 echo $ECHO_N "checking for gethostbyname... $ECHO_C" >&6 if test "${ac_cv_func_gethostbyname+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ /* Define gethostbyname to an innocuous variant, in case declares gethostbyname. For example, HP-UX 11i declares gettimeofday. */ #define gethostbyname innocuous_gethostbyname /* System header to define __stub macros and hopefully few prototypes, which can conflict with char gethostbyname (); below. Prefer to if __STDC__ is defined, since exists even on freestanding compilers. */ #ifdef __STDC__ # include #else # include #endif #undef gethostbyname /* Override any gcc2 internal prototype to avoid an error. */ #ifdef __cplusplus extern "C" { #endif /* We use char because int might match the return type of a gcc2 builtin and then its argument prototype would still apply. */ char gethostbyname (); /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ #if defined (__stub_gethostbyname) || defined (__stub___gethostbyname) choke me #else char (*f) () = gethostbyname; #endif #ifdef __cplusplus } #endif int main () { return f != gethostbyname; ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest$ac_exeext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_func_gethostbyname=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_func_gethostbyname=no fi rm -f conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi echo "$as_me:$LINENO: result: $ac_cv_func_gethostbyname" >&5 echo "${ECHO_T}$ac_cv_func_gethostbyname" >&6 if test $ac_cv_func_gethostbyname = yes; then : else echo "$as_me:$LINENO: checking for gethostbyname in -lnsl" >&5 echo $ECHO_N "checking for gethostbyname in -lnsl... $ECHO_C" >&6 if test "${ac_cv_lib_nsl_gethostbyname+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lnsl $LIBS" cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ /* Override any gcc2 internal prototype to avoid an error. */ #ifdef __cplusplus extern "C" #endif /* We use char because int might match the return type of a gcc2 builtin and then its argument prototype would still apply. */ char gethostbyname (); int main () { gethostbyname (); ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest$ac_exeext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_lib_nsl_gethostbyname=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_lib_nsl_gethostbyname=no fi rm -f conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi echo "$as_me:$LINENO: result: $ac_cv_lib_nsl_gethostbyname" >&5 echo "${ECHO_T}$ac_cv_lib_nsl_gethostbyname" >&6 if test $ac_cv_lib_nsl_gethostbyname = yes; then LIBS="$LIBS -lnsl" fi fi # Don't perform the eval of the libraries here because DL_LIBS # won't be set until we call TEA_CONFIG_CFLAGS TCL_LIBS='${DL_LIBS} ${LIBS} ${MATH_LIBS}' echo "$as_me:$LINENO: checking dirent.h" >&5 echo $ECHO_N "checking dirent.h... $ECHO_C" >&6 if test "${tcl_cv_dirent_h+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include #include int main () { #ifndef _POSIX_SOURCE # ifdef __Lynx__ /* * Generate compilation error to make the test fail: Lynx headers * are only valid if really in the POSIX environment. */ missing_procedure(); # endif #endif DIR *d; struct dirent *entryPtr; char *p; d = opendir("foobar"); entryPtr = readdir(d); p = entryPtr->d_name; closedir(d); ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest$ac_exeext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then tcl_cv_dirent_h=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 tcl_cv_dirent_h=no fi rm -f conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi echo "$as_me:$LINENO: result: $tcl_cv_dirent_h" >&5 echo "${ECHO_T}$tcl_cv_dirent_h" >&6 if test $tcl_cv_dirent_h = no; then cat >>confdefs.h <<\_ACEOF #define NO_DIRENT_H 1 _ACEOF fi if test "${ac_cv_header_errno_h+set}" = set; then echo "$as_me:$LINENO: checking for errno.h" >&5 echo $ECHO_N "checking for errno.h... $ECHO_C" >&6 if test "${ac_cv_header_errno_h+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 fi echo "$as_me:$LINENO: result: $ac_cv_header_errno_h" >&5 echo "${ECHO_T}$ac_cv_header_errno_h" >&6 else # Is the header compilable? echo "$as_me:$LINENO: checking errno.h usability" >&5 echo $ECHO_N "checking errno.h usability... $ECHO_C" >&6 cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_includes_default #include _ACEOF rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_header_compiler=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_header_compiler=no fi rm -f conftest.err conftest.$ac_objext conftest.$ac_ext echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 echo "${ECHO_T}$ac_header_compiler" >&6 # Is the header present? echo "$as_me:$LINENO: checking errno.h presence" >&5 echo $ECHO_N "checking errno.h presence... $ECHO_C" >&6 cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include _ACEOF if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } >/dev/null; then if test -s conftest.err; then ac_cpp_err=$ac_c_preproc_warn_flag ac_cpp_err=$ac_cpp_err$ac_c_werror_flag else ac_cpp_err= fi else ac_cpp_err=yes fi if test -z "$ac_cpp_err"; then ac_header_preproc=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_header_preproc=no fi rm -f conftest.err conftest.$ac_ext echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 echo "${ECHO_T}$ac_header_preproc" >&6 # So? What about this header? case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in yes:no: ) { echo "$as_me:$LINENO: WARNING: errno.h: accepted by the compiler, rejected by the preprocessor!" >&5 echo "$as_me: WARNING: errno.h: accepted by the compiler, rejected by the preprocessor!" >&2;} { echo "$as_me:$LINENO: WARNING: errno.h: proceeding with the compiler's result" >&5 echo "$as_me: WARNING: errno.h: proceeding with the compiler's result" >&2;} ac_header_preproc=yes ;; no:yes:* ) { echo "$as_me:$LINENO: WARNING: errno.h: present but cannot be compiled" >&5 echo "$as_me: WARNING: errno.h: present but cannot be compiled" >&2;} { echo "$as_me:$LINENO: WARNING: errno.h: check for missing prerequisite headers?" >&5 echo "$as_me: WARNING: errno.h: check for missing prerequisite headers?" >&2;} { echo "$as_me:$LINENO: WARNING: errno.h: see the Autoconf documentation" >&5 echo "$as_me: WARNING: errno.h: see the Autoconf documentation" >&2;} { echo "$as_me:$LINENO: WARNING: errno.h: section \"Present But Cannot Be Compiled\"" >&5 echo "$as_me: WARNING: errno.h: section \"Present But Cannot Be Compiled\"" >&2;} { echo "$as_me:$LINENO: WARNING: errno.h: proceeding with the preprocessor's result" >&5 echo "$as_me: WARNING: errno.h: proceeding with the preprocessor's result" >&2;} { echo "$as_me:$LINENO: WARNING: errno.h: in the future, the compiler will take precedence" >&5 echo "$as_me: WARNING: errno.h: in the future, the compiler will take precedence" >&2;} ( cat <<\_ASBOX ## --------------------------------- ## ## Report this to the Tkhtml lists. ## ## --------------------------------- ## _ASBOX ) | sed "s/^/$as_me: WARNING: /" >&2 ;; esac echo "$as_me:$LINENO: checking for errno.h" >&5 echo $ECHO_N "checking for errno.h... $ECHO_C" >&6 if test "${ac_cv_header_errno_h+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else ac_cv_header_errno_h=$ac_header_preproc fi echo "$as_me:$LINENO: result: $ac_cv_header_errno_h" >&5 echo "${ECHO_T}$ac_cv_header_errno_h" >&6 fi if test $ac_cv_header_errno_h = yes; then : else cat >>confdefs.h <<\_ACEOF #define NO_ERRNO_H 1 _ACEOF fi if test "${ac_cv_header_float_h+set}" = set; then echo "$as_me:$LINENO: checking for float.h" >&5 echo $ECHO_N "checking for float.h... $ECHO_C" >&6 if test "${ac_cv_header_float_h+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 fi echo "$as_me:$LINENO: result: $ac_cv_header_float_h" >&5 echo "${ECHO_T}$ac_cv_header_float_h" >&6 else # Is the header compilable? echo "$as_me:$LINENO: checking float.h usability" >&5 echo $ECHO_N "checking float.h usability... $ECHO_C" >&6 cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_includes_default #include _ACEOF rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_header_compiler=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_header_compiler=no fi rm -f conftest.err conftest.$ac_objext conftest.$ac_ext echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 echo "${ECHO_T}$ac_header_compiler" >&6 # Is the header present? echo "$as_me:$LINENO: checking float.h presence" >&5 echo $ECHO_N "checking float.h presence... $ECHO_C" >&6 cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include _ACEOF if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } >/dev/null; then if test -s conftest.err; then ac_cpp_err=$ac_c_preproc_warn_flag ac_cpp_err=$ac_cpp_err$ac_c_werror_flag else ac_cpp_err= fi else ac_cpp_err=yes fi if test -z "$ac_cpp_err"; then ac_header_preproc=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_header_preproc=no fi rm -f conftest.err conftest.$ac_ext echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 echo "${ECHO_T}$ac_header_preproc" >&6 # So? What about this header? case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in yes:no: ) { echo "$as_me:$LINENO: WARNING: float.h: accepted by the compiler, rejected by the preprocessor!" >&5 echo "$as_me: WARNING: float.h: accepted by the compiler, rejected by the preprocessor!" >&2;} { echo "$as_me:$LINENO: WARNING: float.h: proceeding with the compiler's result" >&5 echo "$as_me: WARNING: float.h: proceeding with the compiler's result" >&2;} ac_header_preproc=yes ;; no:yes:* ) { echo "$as_me:$LINENO: WARNING: float.h: present but cannot be compiled" >&5 echo "$as_me: WARNING: float.h: present but cannot be compiled" >&2;} { echo "$as_me:$LINENO: WARNING: float.h: check for missing prerequisite headers?" >&5 echo "$as_me: WARNING: float.h: check for missing prerequisite headers?" >&2;} { echo "$as_me:$LINENO: WARNING: float.h: see the Autoconf documentation" >&5 echo "$as_me: WARNING: float.h: see the Autoconf documentation" >&2;} { echo "$as_me:$LINENO: WARNING: float.h: section \"Present But Cannot Be Compiled\"" >&5 echo "$as_me: WARNING: float.h: section \"Present But Cannot Be Compiled\"" >&2;} { echo "$as_me:$LINENO: WARNING: float.h: proceeding with the preprocessor's result" >&5 echo "$as_me: WARNING: float.h: proceeding with the preprocessor's result" >&2;} { echo "$as_me:$LINENO: WARNING: float.h: in the future, the compiler will take precedence" >&5 echo "$as_me: WARNING: float.h: in the future, the compiler will take precedence" >&2;} ( cat <<\_ASBOX ## --------------------------------- ## ## Report this to the Tkhtml lists. ## ## --------------------------------- ## _ASBOX ) | sed "s/^/$as_me: WARNING: /" >&2 ;; esac echo "$as_me:$LINENO: checking for float.h" >&5 echo $ECHO_N "checking for float.h... $ECHO_C" >&6 if test "${ac_cv_header_float_h+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else ac_cv_header_float_h=$ac_header_preproc fi echo "$as_me:$LINENO: result: $ac_cv_header_float_h" >&5 echo "${ECHO_T}$ac_cv_header_float_h" >&6 fi if test $ac_cv_header_float_h = yes; then : else cat >>confdefs.h <<\_ACEOF #define NO_FLOAT_H 1 _ACEOF fi if test "${ac_cv_header_values_h+set}" = set; then echo "$as_me:$LINENO: checking for values.h" >&5 echo $ECHO_N "checking for values.h... $ECHO_C" >&6 if test "${ac_cv_header_values_h+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 fi echo "$as_me:$LINENO: result: $ac_cv_header_values_h" >&5 echo "${ECHO_T}$ac_cv_header_values_h" >&6 else # Is the header compilable? echo "$as_me:$LINENO: checking values.h usability" >&5 echo $ECHO_N "checking values.h usability... $ECHO_C" >&6 cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_includes_default #include _ACEOF rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_header_compiler=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_header_compiler=no fi rm -f conftest.err conftest.$ac_objext conftest.$ac_ext echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 echo "${ECHO_T}$ac_header_compiler" >&6 # Is the header present? echo "$as_me:$LINENO: checking values.h presence" >&5 echo $ECHO_N "checking values.h presence... $ECHO_C" >&6 cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include _ACEOF if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } >/dev/null; then if test -s conftest.err; then ac_cpp_err=$ac_c_preproc_warn_flag ac_cpp_err=$ac_cpp_err$ac_c_werror_flag else ac_cpp_err= fi else ac_cpp_err=yes fi if test -z "$ac_cpp_err"; then ac_header_preproc=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_header_preproc=no fi rm -f conftest.err conftest.$ac_ext echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 echo "${ECHO_T}$ac_header_preproc" >&6 # So? What about this header? case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in yes:no: ) { echo "$as_me:$LINENO: WARNING: values.h: accepted by the compiler, rejected by the preprocessor!" >&5 echo "$as_me: WARNING: values.h: accepted by the compiler, rejected by the preprocessor!" >&2;} { echo "$as_me:$LINENO: WARNING: values.h: proceeding with the compiler's result" >&5 echo "$as_me: WARNING: values.h: proceeding with the compiler's result" >&2;} ac_header_preproc=yes ;; no:yes:* ) { echo "$as_me:$LINENO: WARNING: values.h: present but cannot be compiled" >&5 echo "$as_me: WARNING: values.h: present but cannot be compiled" >&2;} { echo "$as_me:$LINENO: WARNING: values.h: check for missing prerequisite headers?" >&5 echo "$as_me: WARNING: values.h: check for missing prerequisite headers?" >&2;} { echo "$as_me:$LINENO: WARNING: values.h: see the Autoconf documentation" >&5 echo "$as_me: WARNING: values.h: see the Autoconf documentation" >&2;} { echo "$as_me:$LINENO: WARNING: values.h: section \"Present But Cannot Be Compiled\"" >&5 echo "$as_me: WARNING: values.h: section \"Present But Cannot Be Compiled\"" >&2;} { echo "$as_me:$LINENO: WARNING: values.h: proceeding with the preprocessor's result" >&5 echo "$as_me: WARNING: values.h: proceeding with the preprocessor's result" >&2;} { echo "$as_me:$LINENO: WARNING: values.h: in the future, the compiler will take precedence" >&5 echo "$as_me: WARNING: values.h: in the future, the compiler will take precedence" >&2;} ( cat <<\_ASBOX ## --------------------------------- ## ## Report this to the Tkhtml lists. ## ## --------------------------------- ## _ASBOX ) | sed "s/^/$as_me: WARNING: /" >&2 ;; esac echo "$as_me:$LINENO: checking for values.h" >&5 echo $ECHO_N "checking for values.h... $ECHO_C" >&6 if test "${ac_cv_header_values_h+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else ac_cv_header_values_h=$ac_header_preproc fi echo "$as_me:$LINENO: result: $ac_cv_header_values_h" >&5 echo "${ECHO_T}$ac_cv_header_values_h" >&6 fi if test $ac_cv_header_values_h = yes; then : else cat >>confdefs.h <<\_ACEOF #define NO_VALUES_H 1 _ACEOF fi if test "${ac_cv_header_limits_h+set}" = set; then echo "$as_me:$LINENO: checking for limits.h" >&5 echo $ECHO_N "checking for limits.h... $ECHO_C" >&6 if test "${ac_cv_header_limits_h+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 fi echo "$as_me:$LINENO: result: $ac_cv_header_limits_h" >&5 echo "${ECHO_T}$ac_cv_header_limits_h" >&6 else # Is the header compilable? echo "$as_me:$LINENO: checking limits.h usability" >&5 echo $ECHO_N "checking limits.h usability... $ECHO_C" >&6 cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_includes_default #include _ACEOF rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_header_compiler=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_header_compiler=no fi rm -f conftest.err conftest.$ac_objext conftest.$ac_ext echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 echo "${ECHO_T}$ac_header_compiler" >&6 # Is the header present? echo "$as_me:$LINENO: checking limits.h presence" >&5 echo $ECHO_N "checking limits.h presence... $ECHO_C" >&6 cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include _ACEOF if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } >/dev/null; then if test -s conftest.err; then ac_cpp_err=$ac_c_preproc_warn_flag ac_cpp_err=$ac_cpp_err$ac_c_werror_flag else ac_cpp_err= fi else ac_cpp_err=yes fi if test -z "$ac_cpp_err"; then ac_header_preproc=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_header_preproc=no fi rm -f conftest.err conftest.$ac_ext echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 echo "${ECHO_T}$ac_header_preproc" >&6 # So? What about this header? case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in yes:no: ) { echo "$as_me:$LINENO: WARNING: limits.h: accepted by the compiler, rejected by the preprocessor!" >&5 echo "$as_me: WARNING: limits.h: accepted by the compiler, rejected by the preprocessor!" >&2;} { echo "$as_me:$LINENO: WARNING: limits.h: proceeding with the compiler's result" >&5 echo "$as_me: WARNING: limits.h: proceeding with the compiler's result" >&2;} ac_header_preproc=yes ;; no:yes:* ) { echo "$as_me:$LINENO: WARNING: limits.h: present but cannot be compiled" >&5 echo "$as_me: WARNING: limits.h: present but cannot be compiled" >&2;} { echo "$as_me:$LINENO: WARNING: limits.h: check for missing prerequisite headers?" >&5 echo "$as_me: WARNING: limits.h: check for missing prerequisite headers?" >&2;} { echo "$as_me:$LINENO: WARNING: limits.h: see the Autoconf documentation" >&5 echo "$as_me: WARNING: limits.h: see the Autoconf documentation" >&2;} { echo "$as_me:$LINENO: WARNING: limits.h: section \"Present But Cannot Be Compiled\"" >&5 echo "$as_me: WARNING: limits.h: section \"Present But Cannot Be Compiled\"" >&2;} { echo "$as_me:$LINENO: WARNING: limits.h: proceeding with the preprocessor's result" >&5 echo "$as_me: WARNING: limits.h: proceeding with the preprocessor's result" >&2;} { echo "$as_me:$LINENO: WARNING: limits.h: in the future, the compiler will take precedence" >&5 echo "$as_me: WARNING: limits.h: in the future, the compiler will take precedence" >&2;} ( cat <<\_ASBOX ## --------------------------------- ## ## Report this to the Tkhtml lists. ## ## --------------------------------- ## _ASBOX ) | sed "s/^/$as_me: WARNING: /" >&2 ;; esac echo "$as_me:$LINENO: checking for limits.h" >&5 echo $ECHO_N "checking for limits.h... $ECHO_C" >&6 if test "${ac_cv_header_limits_h+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else ac_cv_header_limits_h=$ac_header_preproc fi echo "$as_me:$LINENO: result: $ac_cv_header_limits_h" >&5 echo "${ECHO_T}$ac_cv_header_limits_h" >&6 fi if test $ac_cv_header_limits_h = yes; then cat >>confdefs.h <<\_ACEOF #define HAVE_LIMITS_H 1 _ACEOF else cat >>confdefs.h <<\_ACEOF #define NO_LIMITS_H 1 _ACEOF fi if test "${ac_cv_header_stdlib_h+set}" = set; then echo "$as_me:$LINENO: checking for stdlib.h" >&5 echo $ECHO_N "checking for stdlib.h... $ECHO_C" >&6 if test "${ac_cv_header_stdlib_h+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 fi echo "$as_me:$LINENO: result: $ac_cv_header_stdlib_h" >&5 echo "${ECHO_T}$ac_cv_header_stdlib_h" >&6 else # Is the header compilable? echo "$as_me:$LINENO: checking stdlib.h usability" >&5 echo $ECHO_N "checking stdlib.h usability... $ECHO_C" >&6 cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_includes_default #include _ACEOF rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_header_compiler=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_header_compiler=no fi rm -f conftest.err conftest.$ac_objext conftest.$ac_ext echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 echo "${ECHO_T}$ac_header_compiler" >&6 # Is the header present? echo "$as_me:$LINENO: checking stdlib.h presence" >&5 echo $ECHO_N "checking stdlib.h presence... $ECHO_C" >&6 cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include _ACEOF if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } >/dev/null; then if test -s conftest.err; then ac_cpp_err=$ac_c_preproc_warn_flag ac_cpp_err=$ac_cpp_err$ac_c_werror_flag else ac_cpp_err= fi else ac_cpp_err=yes fi if test -z "$ac_cpp_err"; then ac_header_preproc=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_header_preproc=no fi rm -f conftest.err conftest.$ac_ext echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 echo "${ECHO_T}$ac_header_preproc" >&6 # So? What about this header? case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in yes:no: ) { echo "$as_me:$LINENO: WARNING: stdlib.h: accepted by the compiler, rejected by the preprocessor!" >&5 echo "$as_me: WARNING: stdlib.h: accepted by the compiler, rejected by the preprocessor!" >&2;} { echo "$as_me:$LINENO: WARNING: stdlib.h: proceeding with the compiler's result" >&5 echo "$as_me: WARNING: stdlib.h: proceeding with the compiler's result" >&2;} ac_header_preproc=yes ;; no:yes:* ) { echo "$as_me:$LINENO: WARNING: stdlib.h: present but cannot be compiled" >&5 echo "$as_me: WARNING: stdlib.h: present but cannot be compiled" >&2;} { echo "$as_me:$LINENO: WARNING: stdlib.h: check for missing prerequisite headers?" >&5 echo "$as_me: WARNING: stdlib.h: check for missing prerequisite headers?" >&2;} { echo "$as_me:$LINENO: WARNING: stdlib.h: see the Autoconf documentation" >&5 echo "$as_me: WARNING: stdlib.h: see the Autoconf documentation" >&2;} { echo "$as_me:$LINENO: WARNING: stdlib.h: section \"Present But Cannot Be Compiled\"" >&5 echo "$as_me: WARNING: stdlib.h: section \"Present But Cannot Be Compiled\"" >&2;} { echo "$as_me:$LINENO: WARNING: stdlib.h: proceeding with the preprocessor's result" >&5 echo "$as_me: WARNING: stdlib.h: proceeding with the preprocessor's result" >&2;} { echo "$as_me:$LINENO: WARNING: stdlib.h: in the future, the compiler will take precedence" >&5 echo "$as_me: WARNING: stdlib.h: in the future, the compiler will take precedence" >&2;} ( cat <<\_ASBOX ## --------------------------------- ## ## Report this to the Tkhtml lists. ## ## --------------------------------- ## _ASBOX ) | sed "s/^/$as_me: WARNING: /" >&2 ;; esac echo "$as_me:$LINENO: checking for stdlib.h" >&5 echo $ECHO_N "checking for stdlib.h... $ECHO_C" >&6 if test "${ac_cv_header_stdlib_h+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else ac_cv_header_stdlib_h=$ac_header_preproc fi echo "$as_me:$LINENO: result: $ac_cv_header_stdlib_h" >&5 echo "${ECHO_T}$ac_cv_header_stdlib_h" >&6 fi if test $ac_cv_header_stdlib_h = yes; then tcl_ok=1 else tcl_ok=0 fi cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "strtol" >/dev/null 2>&1; then : else tcl_ok=0 fi rm -f conftest* cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "strtoul" >/dev/null 2>&1; then : else tcl_ok=0 fi rm -f conftest* cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "strtod" >/dev/null 2>&1; then : else tcl_ok=0 fi rm -f conftest* if test $tcl_ok = 0; then cat >>confdefs.h <<\_ACEOF #define NO_STDLIB_H 1 _ACEOF fi if test "${ac_cv_header_string_h+set}" = set; then echo "$as_me:$LINENO: checking for string.h" >&5 echo $ECHO_N "checking for string.h... $ECHO_C" >&6 if test "${ac_cv_header_string_h+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 fi echo "$as_me:$LINENO: result: $ac_cv_header_string_h" >&5 echo "${ECHO_T}$ac_cv_header_string_h" >&6 else # Is the header compilable? echo "$as_me:$LINENO: checking string.h usability" >&5 echo $ECHO_N "checking string.h usability... $ECHO_C" >&6 cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_includes_default #include _ACEOF rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_header_compiler=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_header_compiler=no fi rm -f conftest.err conftest.$ac_objext conftest.$ac_ext echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 echo "${ECHO_T}$ac_header_compiler" >&6 # Is the header present? echo "$as_me:$LINENO: checking string.h presence" >&5 echo $ECHO_N "checking string.h presence... $ECHO_C" >&6 cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include _ACEOF if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } >/dev/null; then if test -s conftest.err; then ac_cpp_err=$ac_c_preproc_warn_flag ac_cpp_err=$ac_cpp_err$ac_c_werror_flag else ac_cpp_err= fi else ac_cpp_err=yes fi if test -z "$ac_cpp_err"; then ac_header_preproc=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_header_preproc=no fi rm -f conftest.err conftest.$ac_ext echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 echo "${ECHO_T}$ac_header_preproc" >&6 # So? What about this header? case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in yes:no: ) { echo "$as_me:$LINENO: WARNING: string.h: accepted by the compiler, rejected by the preprocessor!" >&5 echo "$as_me: WARNING: string.h: accepted by the compiler, rejected by the preprocessor!" >&2;} { echo "$as_me:$LINENO: WARNING: string.h: proceeding with the compiler's result" >&5 echo "$as_me: WARNING: string.h: proceeding with the compiler's result" >&2;} ac_header_preproc=yes ;; no:yes:* ) { echo "$as_me:$LINENO: WARNING: string.h: present but cannot be compiled" >&5 echo "$as_me: WARNING: string.h: present but cannot be compiled" >&2;} { echo "$as_me:$LINENO: WARNING: string.h: check for missing prerequisite headers?" >&5 echo "$as_me: WARNING: string.h: check for missing prerequisite headers?" >&2;} { echo "$as_me:$LINENO: WARNING: string.h: see the Autoconf documentation" >&5 echo "$as_me: WARNING: string.h: see the Autoconf documentation" >&2;} { echo "$as_me:$LINENO: WARNING: string.h: section \"Present But Cannot Be Compiled\"" >&5 echo "$as_me: WARNING: string.h: section \"Present But Cannot Be Compiled\"" >&2;} { echo "$as_me:$LINENO: WARNING: string.h: proceeding with the preprocessor's result" >&5 echo "$as_me: WARNING: string.h: proceeding with the preprocessor's result" >&2;} { echo "$as_me:$LINENO: WARNING: string.h: in the future, the compiler will take precedence" >&5 echo "$as_me: WARNING: string.h: in the future, the compiler will take precedence" >&2;} ( cat <<\_ASBOX ## --------------------------------- ## ## Report this to the Tkhtml lists. ## ## --------------------------------- ## _ASBOX ) | sed "s/^/$as_me: WARNING: /" >&2 ;; esac echo "$as_me:$LINENO: checking for string.h" >&5 echo $ECHO_N "checking for string.h... $ECHO_C" >&6 if test "${ac_cv_header_string_h+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else ac_cv_header_string_h=$ac_header_preproc fi echo "$as_me:$LINENO: result: $ac_cv_header_string_h" >&5 echo "${ECHO_T}$ac_cv_header_string_h" >&6 fi if test $ac_cv_header_string_h = yes; then tcl_ok=1 else tcl_ok=0 fi cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "strstr" >/dev/null 2>&1; then : else tcl_ok=0 fi rm -f conftest* cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "strerror" >/dev/null 2>&1; then : else tcl_ok=0 fi rm -f conftest* # See also memmove check below for a place where NO_STRING_H can be # set and why. if test $tcl_ok = 0; then cat >>confdefs.h <<\_ACEOF #define NO_STRING_H 1 _ACEOF fi if test "${ac_cv_header_sys_wait_h+set}" = set; then echo "$as_me:$LINENO: checking for sys/wait.h" >&5 echo $ECHO_N "checking for sys/wait.h... $ECHO_C" >&6 if test "${ac_cv_header_sys_wait_h+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 fi echo "$as_me:$LINENO: result: $ac_cv_header_sys_wait_h" >&5 echo "${ECHO_T}$ac_cv_header_sys_wait_h" >&6 else # Is the header compilable? echo "$as_me:$LINENO: checking sys/wait.h usability" >&5 echo $ECHO_N "checking sys/wait.h usability... $ECHO_C" >&6 cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_includes_default #include _ACEOF rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_header_compiler=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_header_compiler=no fi rm -f conftest.err conftest.$ac_objext conftest.$ac_ext echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 echo "${ECHO_T}$ac_header_compiler" >&6 # Is the header present? echo "$as_me:$LINENO: checking sys/wait.h presence" >&5 echo $ECHO_N "checking sys/wait.h presence... $ECHO_C" >&6 cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include _ACEOF if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } >/dev/null; then if test -s conftest.err; then ac_cpp_err=$ac_c_preproc_warn_flag ac_cpp_err=$ac_cpp_err$ac_c_werror_flag else ac_cpp_err= fi else ac_cpp_err=yes fi if test -z "$ac_cpp_err"; then ac_header_preproc=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_header_preproc=no fi rm -f conftest.err conftest.$ac_ext echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 echo "${ECHO_T}$ac_header_preproc" >&6 # So? What about this header? case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in yes:no: ) { echo "$as_me:$LINENO: WARNING: sys/wait.h: accepted by the compiler, rejected by the preprocessor!" >&5 echo "$as_me: WARNING: sys/wait.h: accepted by the compiler, rejected by the preprocessor!" >&2;} { echo "$as_me:$LINENO: WARNING: sys/wait.h: proceeding with the compiler's result" >&5 echo "$as_me: WARNING: sys/wait.h: proceeding with the compiler's result" >&2;} ac_header_preproc=yes ;; no:yes:* ) { echo "$as_me:$LINENO: WARNING: sys/wait.h: present but cannot be compiled" >&5 echo "$as_me: WARNING: sys/wait.h: present but cannot be compiled" >&2;} { echo "$as_me:$LINENO: WARNING: sys/wait.h: check for missing prerequisite headers?" >&5 echo "$as_me: WARNING: sys/wait.h: check for missing prerequisite headers?" >&2;} { echo "$as_me:$LINENO: WARNING: sys/wait.h: see the Autoconf documentation" >&5 echo "$as_me: WARNING: sys/wait.h: see the Autoconf documentation" >&2;} { echo "$as_me:$LINENO: WARNING: sys/wait.h: section \"Present But Cannot Be Compiled\"" >&5 echo "$as_me: WARNING: sys/wait.h: section \"Present But Cannot Be Compiled\"" >&2;} { echo "$as_me:$LINENO: WARNING: sys/wait.h: proceeding with the preprocessor's result" >&5 echo "$as_me: WARNING: sys/wait.h: proceeding with the preprocessor's result" >&2;} { echo "$as_me:$LINENO: WARNING: sys/wait.h: in the future, the compiler will take precedence" >&5 echo "$as_me: WARNING: sys/wait.h: in the future, the compiler will take precedence" >&2;} ( cat <<\_ASBOX ## --------------------------------- ## ## Report this to the Tkhtml lists. ## ## --------------------------------- ## _ASBOX ) | sed "s/^/$as_me: WARNING: /" >&2 ;; esac echo "$as_me:$LINENO: checking for sys/wait.h" >&5 echo $ECHO_N "checking for sys/wait.h... $ECHO_C" >&6 if test "${ac_cv_header_sys_wait_h+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else ac_cv_header_sys_wait_h=$ac_header_preproc fi echo "$as_me:$LINENO: result: $ac_cv_header_sys_wait_h" >&5 echo "${ECHO_T}$ac_cv_header_sys_wait_h" >&6 fi if test $ac_cv_header_sys_wait_h = yes; then : else cat >>confdefs.h <<\_ACEOF #define NO_SYS_WAIT_H 1 _ACEOF fi if test "${ac_cv_header_dlfcn_h+set}" = set; then echo "$as_me:$LINENO: checking for dlfcn.h" >&5 echo $ECHO_N "checking for dlfcn.h... $ECHO_C" >&6 if test "${ac_cv_header_dlfcn_h+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 fi echo "$as_me:$LINENO: result: $ac_cv_header_dlfcn_h" >&5 echo "${ECHO_T}$ac_cv_header_dlfcn_h" >&6 else # Is the header compilable? echo "$as_me:$LINENO: checking dlfcn.h usability" >&5 echo $ECHO_N "checking dlfcn.h usability... $ECHO_C" >&6 cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_includes_default #include _ACEOF rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_header_compiler=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_header_compiler=no fi rm -f conftest.err conftest.$ac_objext conftest.$ac_ext echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 echo "${ECHO_T}$ac_header_compiler" >&6 # Is the header present? echo "$as_me:$LINENO: checking dlfcn.h presence" >&5 echo $ECHO_N "checking dlfcn.h presence... $ECHO_C" >&6 cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include _ACEOF if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } >/dev/null; then if test -s conftest.err; then ac_cpp_err=$ac_c_preproc_warn_flag ac_cpp_err=$ac_cpp_err$ac_c_werror_flag else ac_cpp_err= fi else ac_cpp_err=yes fi if test -z "$ac_cpp_err"; then ac_header_preproc=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_header_preproc=no fi rm -f conftest.err conftest.$ac_ext echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 echo "${ECHO_T}$ac_header_preproc" >&6 # So? What about this header? case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in yes:no: ) { echo "$as_me:$LINENO: WARNING: dlfcn.h: accepted by the compiler, rejected by the preprocessor!" >&5 echo "$as_me: WARNING: dlfcn.h: accepted by the compiler, rejected by the preprocessor!" >&2;} { echo "$as_me:$LINENO: WARNING: dlfcn.h: proceeding with the compiler's result" >&5 echo "$as_me: WARNING: dlfcn.h: proceeding with the compiler's result" >&2;} ac_header_preproc=yes ;; no:yes:* ) { echo "$as_me:$LINENO: WARNING: dlfcn.h: present but cannot be compiled" >&5 echo "$as_me: WARNING: dlfcn.h: present but cannot be compiled" >&2;} { echo "$as_me:$LINENO: WARNING: dlfcn.h: check for missing prerequisite headers?" >&5 echo "$as_me: WARNING: dlfcn.h: check for missing prerequisite headers?" >&2;} { echo "$as_me:$LINENO: WARNING: dlfcn.h: see the Autoconf documentation" >&5 echo "$as_me: WARNING: dlfcn.h: see the Autoconf documentation" >&2;} { echo "$as_me:$LINENO: WARNING: dlfcn.h: section \"Present But Cannot Be Compiled\"" >&5 echo "$as_me: WARNING: dlfcn.h: section \"Present But Cannot Be Compiled\"" >&2;} { echo "$as_me:$LINENO: WARNING: dlfcn.h: proceeding with the preprocessor's result" >&5 echo "$as_me: WARNING: dlfcn.h: proceeding with the preprocessor's result" >&2;} { echo "$as_me:$LINENO: WARNING: dlfcn.h: in the future, the compiler will take precedence" >&5 echo "$as_me: WARNING: dlfcn.h: in the future, the compiler will take precedence" >&2;} ( cat <<\_ASBOX ## --------------------------------- ## ## Report this to the Tkhtml lists. ## ## --------------------------------- ## _ASBOX ) | sed "s/^/$as_me: WARNING: /" >&2 ;; esac echo "$as_me:$LINENO: checking for dlfcn.h" >&5 echo $ECHO_N "checking for dlfcn.h... $ECHO_C" >&6 if test "${ac_cv_header_dlfcn_h+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else ac_cv_header_dlfcn_h=$ac_header_preproc fi echo "$as_me:$LINENO: result: $ac_cv_header_dlfcn_h" >&5 echo "${ECHO_T}$ac_cv_header_dlfcn_h" >&6 fi if test $ac_cv_header_dlfcn_h = yes; then : else cat >>confdefs.h <<\_ACEOF #define NO_DLFCN_H 1 _ACEOF fi # OS/390 lacks sys/param.h (and doesn't need it, by chance). for ac_header in sys/param.h do as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` if eval "test \"\${$as_ac_Header+set}\" = set"; then echo "$as_me:$LINENO: checking for $ac_header" >&5 echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 if eval "test \"\${$as_ac_Header+set}\" = set"; then echo $ECHO_N "(cached) $ECHO_C" >&6 fi echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 else # Is the header compilable? echo "$as_me:$LINENO: checking $ac_header usability" >&5 echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6 cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_includes_default #include <$ac_header> _ACEOF rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_header_compiler=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_header_compiler=no fi rm -f conftest.err conftest.$ac_objext conftest.$ac_ext echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 echo "${ECHO_T}$ac_header_compiler" >&6 # Is the header present? echo "$as_me:$LINENO: checking $ac_header presence" >&5 echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6 cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include <$ac_header> _ACEOF if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } >/dev/null; then if test -s conftest.err; then ac_cpp_err=$ac_c_preproc_warn_flag ac_cpp_err=$ac_cpp_err$ac_c_werror_flag else ac_cpp_err= fi else ac_cpp_err=yes fi if test -z "$ac_cpp_err"; then ac_header_preproc=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_header_preproc=no fi rm -f conftest.err conftest.$ac_ext echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 echo "${ECHO_T}$ac_header_preproc" >&6 # So? What about this header? case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in yes:no: ) { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5 echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;} { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5 echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;} ac_header_preproc=yes ;; no:yes:* ) { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5 echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;} { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5 echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;} { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5 echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;} { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5 echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;} { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5 echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5 echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;} ( cat <<\_ASBOX ## --------------------------------- ## ## Report this to the Tkhtml lists. ## ## --------------------------------- ## _ASBOX ) | sed "s/^/$as_me: WARNING: /" >&2 ;; esac echo "$as_me:$LINENO: checking for $ac_header" >&5 echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 if eval "test \"\${$as_ac_Header+set}\" = set"; then echo $ECHO_N "(cached) $ECHO_C" >&6 else eval "$as_ac_Header=\$ac_header_preproc" fi echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 fi if test `eval echo '${'$as_ac_Header'}'` = yes; then cat >>confdefs.h <<_ACEOF #define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF fi done # Let the user call this, because if it triggers, they will # need a compat/strtod.c that is correct. Users can also # use Tcl_GetDouble(FromObj) instead. #TEA_BUGGY_STRTOD fi #----------------------------------------------------------------------- # __CHANGE__ # Specify the C source files to compile in TEA_ADD_SOURCES, # public headers that need to be installed in TEA_ADD_HEADERS, # stub library C source files to compile in TEA_ADD_STUB_SOURCES, # and runtime Tcl library files in TEA_ADD_TCL_SOURCES. # This defines PKG(_STUB)_SOURCES, PKG(_STUB)_OBJECTS, PKG_HEADERS # and PKG_TCL_SOURCES. #----------------------------------------------------------------------- vars="css.c" for i in $vars; do case $i in \$*) # allow $-var names PKG_SOURCES="$PKG_SOURCES $i" PKG_OBJECTS="$PKG_OBJECTS $i" ;; *) # check for existence - allows for generic/win/unix VPATH if test ! -f "${srcdir}/$i" -a ! -f "${srcdir}/src/$i" \ -a ! -f "${srcdir}/win/$i" -a ! -f "${srcdir}/unix/$i" \ ; then { { echo "$as_me:$LINENO: error: could not find source file '$i'" >&5 echo "$as_me: error: could not find source file '$i'" >&2;} { (exit 1); exit 1; }; } fi PKG_SOURCES="$PKG_SOURCES $i" # this assumes it is in a VPATH dir i=`basename $i` # handle user calling this before or after TEA_SETUP_COMPILER if test x"${OBJEXT}" != x ; then j="`echo $i | sed -e 's/\.[^.]*$//'`.${OBJEXT}" else j="`echo $i | sed -e 's/\.[^.]*$//'`.\${OBJEXT}" fi PKG_OBJECTS="$PKG_OBJECTS $j" ;; esac done vars="cssdynamic.c" for i in $vars; do case $i in \$*) # allow $-var names PKG_SOURCES="$PKG_SOURCES $i" PKG_OBJECTS="$PKG_OBJECTS $i" ;; *) # check for existence - allows for generic/win/unix VPATH if test ! -f "${srcdir}/$i" -a ! -f "${srcdir}/src/$i" \ -a ! -f "${srcdir}/win/$i" -a ! -f "${srcdir}/unix/$i" \ ; then { { echo "$as_me:$LINENO: error: could not find source file '$i'" >&5 echo "$as_me: error: could not find source file '$i'" >&2;} { (exit 1); exit 1; }; } fi PKG_SOURCES="$PKG_SOURCES $i" # this assumes it is in a VPATH dir i=`basename $i` # handle user calling this before or after TEA_SETUP_COMPILER if test x"${OBJEXT}" != x ; then j="`echo $i | sed -e 's/\.[^.]*$//'`.${OBJEXT}" else j="`echo $i | sed -e 's/\.[^.]*$//'`.\${OBJEXT}" fi PKG_OBJECTS="$PKG_OBJECTS $j" ;; esac done vars="cssparser.c" for i in $vars; do case $i in \$*) # allow $-var names PKG_SOURCES="$PKG_SOURCES $i" PKG_OBJECTS="$PKG_OBJECTS $i" ;; *) # check for existence - allows for generic/win/unix VPATH if test ! -f "${srcdir}/$i" -a ! -f "${srcdir}/src/$i" \ -a ! -f "${srcdir}/win/$i" -a ! -f "${srcdir}/unix/$i" \ ; then { { echo "$as_me:$LINENO: error: could not find source file '$i'" >&5 echo "$as_me: error: could not find source file '$i'" >&2;} { (exit 1); exit 1; }; } fi PKG_SOURCES="$PKG_SOURCES $i" # this assumes it is in a VPATH dir i=`basename $i` # handle user calling this before or after TEA_SETUP_COMPILER if test x"${OBJEXT}" != x ; then j="`echo $i | sed -e 's/\.[^.]*$//'`.${OBJEXT}" else j="`echo $i | sed -e 's/\.[^.]*$//'`.\${OBJEXT}" fi PKG_OBJECTS="$PKG_OBJECTS $j" ;; esac done vars="csssearch.c" for i in $vars; do case $i in \$*) # allow $-var names PKG_SOURCES="$PKG_SOURCES $i" PKG_OBJECTS="$PKG_OBJECTS $i" ;; *) # check for existence - allows for generic/win/unix VPATH if test ! -f "${srcdir}/$i" -a ! -f "${srcdir}/src/$i" \ -a ! -f "${srcdir}/win/$i" -a ! -f "${srcdir}/unix/$i" \ ; then { { echo "$as_me:$LINENO: error: could not find source file '$i'" >&5 echo "$as_me: error: could not find source file '$i'" >&2;} { (exit 1); exit 1; }; } fi PKG_SOURCES="$PKG_SOURCES $i" # this assumes it is in a VPATH dir i=`basename $i` # handle user calling this before or after TEA_SETUP_COMPILER if test x"${OBJEXT}" != x ; then j="`echo $i | sed -e 's/\.[^.]*$//'`.${OBJEXT}" else j="`echo $i | sed -e 's/\.[^.]*$//'`.\${OBJEXT}" fi PKG_OBJECTS="$PKG_OBJECTS $j" ;; esac done vars="htmldraw.c" for i in $vars; do case $i in \$*) # allow $-var names PKG_SOURCES="$PKG_SOURCES $i" PKG_OBJECTS="$PKG_OBJECTS $i" ;; *) # check for existence - allows for generic/win/unix VPATH if test ! -f "${srcdir}/$i" -a ! -f "${srcdir}/src/$i" \ -a ! -f "${srcdir}/win/$i" -a ! -f "${srcdir}/unix/$i" \ ; then { { echo "$as_me:$LINENO: error: could not find source file '$i'" >&5 echo "$as_me: error: could not find source file '$i'" >&2;} { (exit 1); exit 1; }; } fi PKG_SOURCES="$PKG_SOURCES $i" # this assumes it is in a VPATH dir i=`basename $i` # handle user calling this before or after TEA_SETUP_COMPILER if test x"${OBJEXT}" != x ; then j="`echo $i | sed -e 's/\.[^.]*$//'`.${OBJEXT}" else j="`echo $i | sed -e 's/\.[^.]*$//'`.\${OBJEXT}" fi PKG_OBJECTS="$PKG_OBJECTS $j" ;; esac done vars="htmlfloat.c" for i in $vars; do case $i in \$*) # allow $-var names PKG_SOURCES="$PKG_SOURCES $i" PKG_OBJECTS="$PKG_OBJECTS $i" ;; *) # check for existence - allows for generic/win/unix VPATH if test ! -f "${srcdir}/$i" -a ! -f "${srcdir}/src/$i" \ -a ! -f "${srcdir}/win/$i" -a ! -f "${srcdir}/unix/$i" \ ; then { { echo "$as_me:$LINENO: error: could not find source file '$i'" >&5 echo "$as_me: error: could not find source file '$i'" >&2;} { (exit 1); exit 1; }; } fi PKG_SOURCES="$PKG_SOURCES $i" # this assumes it is in a VPATH dir i=`basename $i` # handle user calling this before or after TEA_SETUP_COMPILER if test x"${OBJEXT}" != x ; then j="`echo $i | sed -e 's/\.[^.]*$//'`.${OBJEXT}" else j="`echo $i | sed -e 's/\.[^.]*$//'`.\${OBJEXT}" fi PKG_OBJECTS="$PKG_OBJECTS $j" ;; esac done vars="htmlhash.c" for i in $vars; do case $i in \$*) # allow $-var names PKG_SOURCES="$PKG_SOURCES $i" PKG_OBJECTS="$PKG_OBJECTS $i" ;; *) # check for existence - allows for generic/win/unix VPATH if test ! -f "${srcdir}/$i" -a ! -f "${srcdir}/src/$i" \ -a ! -f "${srcdir}/win/$i" -a ! -f "${srcdir}/unix/$i" \ ; then { { echo "$as_me:$LINENO: error: could not find source file '$i'" >&5 echo "$as_me: error: could not find source file '$i'" >&2;} { (exit 1); exit 1; }; } fi PKG_SOURCES="$PKG_SOURCES $i" # this assumes it is in a VPATH dir i=`basename $i` # handle user calling this before or after TEA_SETUP_COMPILER if test x"${OBJEXT}" != x ; then j="`echo $i | sed -e 's/\.[^.]*$//'`.${OBJEXT}" else j="`echo $i | sed -e 's/\.[^.]*$//'`.\${OBJEXT}" fi PKG_OBJECTS="$PKG_OBJECTS $j" ;; esac done vars="htmlimage.c" for i in $vars; do case $i in \$*) # allow $-var names PKG_SOURCES="$PKG_SOURCES $i" PKG_OBJECTS="$PKG_OBJECTS $i" ;; *) # check for existence - allows for generic/win/unix VPATH if test ! -f "${srcdir}/$i" -a ! -f "${srcdir}/src/$i" \ -a ! -f "${srcdir}/win/$i" -a ! -f "${srcdir}/unix/$i" \ ; then { { echo "$as_me:$LINENO: error: could not find source file '$i'" >&5 echo "$as_me: error: could not find source file '$i'" >&2;} { (exit 1); exit 1; }; } fi PKG_SOURCES="$PKG_SOURCES $i" # this assumes it is in a VPATH dir i=`basename $i` # handle user calling this before or after TEA_SETUP_COMPILER if test x"${OBJEXT}" != x ; then j="`echo $i | sed -e 's/\.[^.]*$//'`.${OBJEXT}" else j="`echo $i | sed -e 's/\.[^.]*$//'`.\${OBJEXT}" fi PKG_OBJECTS="$PKG_OBJECTS $j" ;; esac done vars="htmlinline.c" for i in $vars; do case $i in \$*) # allow $-var names PKG_SOURCES="$PKG_SOURCES $i" PKG_OBJECTS="$PKG_OBJECTS $i" ;; *) # check for existence - allows for generic/win/unix VPATH if test ! -f "${srcdir}/$i" -a ! -f "${srcdir}/src/$i" \ -a ! -f "${srcdir}/win/$i" -a ! -f "${srcdir}/unix/$i" \ ; then { { echo "$as_me:$LINENO: error: could not find source file '$i'" >&5 echo "$as_me: error: could not find source file '$i'" >&2;} { (exit 1); exit 1; }; } fi PKG_SOURCES="$PKG_SOURCES $i" # this assumes it is in a VPATH dir i=`basename $i` # handle user calling this before or after TEA_SETUP_COMPILER if test x"${OBJEXT}" != x ; then j="`echo $i | sed -e 's/\.[^.]*$//'`.${OBJEXT}" else j="`echo $i | sed -e 's/\.[^.]*$//'`.\${OBJEXT}" fi PKG_OBJECTS="$PKG_OBJECTS $j" ;; esac done vars="htmllayout.c" for i in $vars; do case $i in \$*) # allow $-var names PKG_SOURCES="$PKG_SOURCES $i" PKG_OBJECTS="$PKG_OBJECTS $i" ;; *) # check for existence - allows for generic/win/unix VPATH if test ! -f "${srcdir}/$i" -a ! -f "${srcdir}/src/$i" \ -a ! -f "${srcdir}/win/$i" -a ! -f "${srcdir}/unix/$i" \ ; then { { echo "$as_me:$LINENO: error: could not find source file '$i'" >&5 echo "$as_me: error: could not find source file '$i'" >&2;} { (exit 1); exit 1; }; } fi PKG_SOURCES="$PKG_SOURCES $i" # this assumes it is in a VPATH dir i=`basename $i` # handle user calling this before or after TEA_SETUP_COMPILER if test x"${OBJEXT}" != x ; then j="`echo $i | sed -e 's/\.[^.]*$//'`.${OBJEXT}" else j="`echo $i | sed -e 's/\.[^.]*$//'`.\${OBJEXT}" fi PKG_OBJECTS="$PKG_OBJECTS $j" ;; esac done vars="htmlparse.c" for i in $vars; do case $i in \$*) # allow $-var names PKG_SOURCES="$PKG_SOURCES $i" PKG_OBJECTS="$PKG_OBJECTS $i" ;; *) # check for existence - allows for generic/win/unix VPATH if test ! -f "${srcdir}/$i" -a ! -f "${srcdir}/src/$i" \ -a ! -f "${srcdir}/win/$i" -a ! -f "${srcdir}/unix/$i" \ ; then { { echo "$as_me:$LINENO: error: could not find source file '$i'" >&5 echo "$as_me: error: could not find source file '$i'" >&2;} { (exit 1); exit 1; }; } fi PKG_SOURCES="$PKG_SOURCES $i" # this assumes it is in a VPATH dir i=`basename $i` # handle user calling this before or after TEA_SETUP_COMPILER if test x"${OBJEXT}" != x ; then j="`echo $i | sed -e 's/\.[^.]*$//'`.${OBJEXT}" else j="`echo $i | sed -e 's/\.[^.]*$//'`.\${OBJEXT}" fi PKG_OBJECTS="$PKG_OBJECTS $j" ;; esac done vars="htmlprop.c" for i in $vars; do case $i in \$*) # allow $-var names PKG_SOURCES="$PKG_SOURCES $i" PKG_OBJECTS="$PKG_OBJECTS $i" ;; *) # check for existence - allows for generic/win/unix VPATH if test ! -f "${srcdir}/$i" -a ! -f "${srcdir}/src/$i" \ -a ! -f "${srcdir}/win/$i" -a ! -f "${srcdir}/unix/$i" \ ; then { { echo "$as_me:$LINENO: error: could not find source file '$i'" >&5 echo "$as_me: error: could not find source file '$i'" >&2;} { (exit 1); exit 1; }; } fi PKG_SOURCES="$PKG_SOURCES $i" # this assumes it is in a VPATH dir i=`basename $i` # handle user calling this before or after TEA_SETUP_COMPILER if test x"${OBJEXT}" != x ; then j="`echo $i | sed -e 's/\.[^.]*$//'`.${OBJEXT}" else j="`echo $i | sed -e 's/\.[^.]*$//'`.\${OBJEXT}" fi PKG_OBJECTS="$PKG_OBJECTS $j" ;; esac done vars="htmlstyle.c" for i in $vars; do case $i in \$*) # allow $-var names PKG_SOURCES="$PKG_SOURCES $i" PKG_OBJECTS="$PKG_OBJECTS $i" ;; *) # check for existence - allows for generic/win/unix VPATH if test ! -f "${srcdir}/$i" -a ! -f "${srcdir}/src/$i" \ -a ! -f "${srcdir}/win/$i" -a ! -f "${srcdir}/unix/$i" \ ; then { { echo "$as_me:$LINENO: error: could not find source file '$i'" >&5 echo "$as_me: error: could not find source file '$i'" >&2;} { (exit 1); exit 1; }; } fi PKG_SOURCES="$PKG_SOURCES $i" # this assumes it is in a VPATH dir i=`basename $i` # handle user calling this before or after TEA_SETUP_COMPILER if test x"${OBJEXT}" != x ; then j="`echo $i | sed -e 's/\.[^.]*$//'`.${OBJEXT}" else j="`echo $i | sed -e 's/\.[^.]*$//'`.\${OBJEXT}" fi PKG_OBJECTS="$PKG_OBJECTS $j" ;; esac done vars="htmltagdb.c" for i in $vars; do case $i in \$*) # allow $-var names PKG_SOURCES="$PKG_SOURCES $i" PKG_OBJECTS="$PKG_OBJECTS $i" ;; *) # check for existence - allows for generic/win/unix VPATH if test ! -f "${srcdir}/$i" -a ! -f "${srcdir}/src/$i" \ -a ! -f "${srcdir}/win/$i" -a ! -f "${srcdir}/unix/$i" \ ; then { { echo "$as_me:$LINENO: error: could not find source file '$i'" >&5 echo "$as_me: error: could not find source file '$i'" >&2;} { (exit 1); exit 1; }; } fi PKG_SOURCES="$PKG_SOURCES $i" # this assumes it is in a VPATH dir i=`basename $i` # handle user calling this before or after TEA_SETUP_COMPILER if test x"${OBJEXT}" != x ; then j="`echo $i | sed -e 's/\.[^.]*$//'`.${OBJEXT}" else j="`echo $i | sed -e 's/\.[^.]*$//'`.\${OBJEXT}" fi PKG_OBJECTS="$PKG_OBJECTS $j" ;; esac done vars="htmltable.c" for i in $vars; do case $i in \$*) # allow $-var names PKG_SOURCES="$PKG_SOURCES $i" PKG_OBJECTS="$PKG_OBJECTS $i" ;; *) # check for existence - allows for generic/win/unix VPATH if test ! -f "${srcdir}/$i" -a ! -f "${srcdir}/src/$i" \ -a ! -f "${srcdir}/win/$i" -a ! -f "${srcdir}/unix/$i" \ ; then { { echo "$as_me:$LINENO: error: could not find source file '$i'" >&5 echo "$as_me: error: could not find source file '$i'" >&2;} { (exit 1); exit 1; }; } fi PKG_SOURCES="$PKG_SOURCES $i" # this assumes it is in a VPATH dir i=`basename $i` # handle user calling this before or after TEA_SETUP_COMPILER if test x"${OBJEXT}" != x ; then j="`echo $i | sed -e 's/\.[^.]*$//'`.${OBJEXT}" else j="`echo $i | sed -e 's/\.[^.]*$//'`.\${OBJEXT}" fi PKG_OBJECTS="$PKG_OBJECTS $j" ;; esac done vars="htmltcl.c" for i in $vars; do case $i in \$*) # allow $-var names PKG_SOURCES="$PKG_SOURCES $i" PKG_OBJECTS="$PKG_OBJECTS $i" ;; *) # check for existence - allows for generic/win/unix VPATH if test ! -f "${srcdir}/$i" -a ! -f "${srcdir}/src/$i" \ -a ! -f "${srcdir}/win/$i" -a ! -f "${srcdir}/unix/$i" \ ; then { { echo "$as_me:$LINENO: error: could not find source file '$i'" >&5 echo "$as_me: error: could not find source file '$i'" >&2;} { (exit 1); exit 1; }; } fi PKG_SOURCES="$PKG_SOURCES $i" # this assumes it is in a VPATH dir i=`basename $i` # handle user calling this before or after TEA_SETUP_COMPILER if test x"${OBJEXT}" != x ; then j="`echo $i | sed -e 's/\.[^.]*$//'`.${OBJEXT}" else j="`echo $i | sed -e 's/\.[^.]*$//'`.\${OBJEXT}" fi PKG_OBJECTS="$PKG_OBJECTS $j" ;; esac done vars="htmltree.c" for i in $vars; do case $i in \$*) # allow $-var names PKG_SOURCES="$PKG_SOURCES $i" PKG_OBJECTS="$PKG_OBJECTS $i" ;; *) # check for existence - allows for generic/win/unix VPATH if test ! -f "${srcdir}/$i" -a ! -f "${srcdir}/src/$i" \ -a ! -f "${srcdir}/win/$i" -a ! -f "${srcdir}/unix/$i" \ ; then { { echo "$as_me:$LINENO: error: could not find source file '$i'" >&5 echo "$as_me: error: could not find source file '$i'" >&2;} { (exit 1); exit 1; }; } fi PKG_SOURCES="$PKG_SOURCES $i" # this assumes it is in a VPATH dir i=`basename $i` # handle user calling this before or after TEA_SETUP_COMPILER if test x"${OBJEXT}" != x ; then j="`echo $i | sed -e 's/\.[^.]*$//'`.${OBJEXT}" else j="`echo $i | sed -e 's/\.[^.]*$//'`.\${OBJEXT}" fi PKG_OBJECTS="$PKG_OBJECTS $j" ;; esac done vars="swproc.c" for i in $vars; do case $i in \$*) # allow $-var names PKG_SOURCES="$PKG_SOURCES $i" PKG_OBJECTS="$PKG_OBJECTS $i" ;; *) # check for existence - allows for generic/win/unix VPATH if test ! -f "${srcdir}/$i" -a ! -f "${srcdir}/src/$i" \ -a ! -f "${srcdir}/win/$i" -a ! -f "${srcdir}/unix/$i" \ ; then { { echo "$as_me:$LINENO: error: could not find source file '$i'" >&5 echo "$as_me: error: could not find source file '$i'" >&2;} { (exit 1); exit 1; }; } fi PKG_SOURCES="$PKG_SOURCES $i" # this assumes it is in a VPATH dir i=`basename $i` # handle user calling this before or after TEA_SETUP_COMPILER if test x"${OBJEXT}" != x ; then j="`echo $i | sed -e 's/\.[^.]*$//'`.${OBJEXT}" else j="`echo $i | sed -e 's/\.[^.]*$//'`.\${OBJEXT}" fi PKG_OBJECTS="$PKG_OBJECTS $j" ;; esac done vars="restrack.c" for i in $vars; do case $i in \$*) # allow $-var names PKG_SOURCES="$PKG_SOURCES $i" PKG_OBJECTS="$PKG_OBJECTS $i" ;; *) # check for existence - allows for generic/win/unix VPATH if test ! -f "${srcdir}/$i" -a ! -f "${srcdir}/src/$i" \ -a ! -f "${srcdir}/win/$i" -a ! -f "${srcdir}/unix/$i" \ ; then { { echo "$as_me:$LINENO: error: could not find source file '$i'" >&5 echo "$as_me: error: could not find source file '$i'" >&2;} { (exit 1); exit 1; }; } fi PKG_SOURCES="$PKG_SOURCES $i" # this assumes it is in a VPATH dir i=`basename $i` # handle user calling this before or after TEA_SETUP_COMPILER if test x"${OBJEXT}" != x ; then j="`echo $i | sed -e 's/\.[^.]*$//'`.${OBJEXT}" else j="`echo $i | sed -e 's/\.[^.]*$//'`.\${OBJEXT}" fi PKG_OBJECTS="$PKG_OBJECTS $j" ;; esac done vars="htmldecode.c" for i in $vars; do case $i in \$*) # allow $-var names PKG_SOURCES="$PKG_SOURCES $i" PKG_OBJECTS="$PKG_OBJECTS $i" ;; *) # check for existence - allows for generic/win/unix VPATH if test ! -f "${srcdir}/$i" -a ! -f "${srcdir}/src/$i" \ -a ! -f "${srcdir}/win/$i" -a ! -f "${srcdir}/unix/$i" \ ; then { { echo "$as_me:$LINENO: error: could not find source file '$i'" >&5 echo "$as_me: error: could not find source file '$i'" >&2;} { (exit 1); exit 1; }; } fi PKG_SOURCES="$PKG_SOURCES $i" # this assumes it is in a VPATH dir i=`basename $i` # handle user calling this before or after TEA_SETUP_COMPILER if test x"${OBJEXT}" != x ; then j="`echo $i | sed -e 's/\.[^.]*$//'`.${OBJEXT}" else j="`echo $i | sed -e 's/\.[^.]*$//'`.\${OBJEXT}" fi PKG_OBJECTS="$PKG_OBJECTS $j" ;; esac done vars="htmltext.c" for i in $vars; do case $i in \$*) # allow $-var names PKG_SOURCES="$PKG_SOURCES $i" PKG_OBJECTS="$PKG_OBJECTS $i" ;; *) # check for existence - allows for generic/win/unix VPATH if test ! -f "${srcdir}/$i" -a ! -f "${srcdir}/src/$i" \ -a ! -f "${srcdir}/win/$i" -a ! -f "${srcdir}/unix/$i" \ ; then { { echo "$as_me:$LINENO: error: could not find source file '$i'" >&5 echo "$as_me: error: could not find source file '$i'" >&2;} { (exit 1); exit 1; }; } fi PKG_SOURCES="$PKG_SOURCES $i" # this assumes it is in a VPATH dir i=`basename $i` # handle user calling this before or after TEA_SETUP_COMPILER if test x"${OBJEXT}" != x ; then j="`echo $i | sed -e 's/\.[^.]*$//'`.${OBJEXT}" else j="`echo $i | sed -e 's/\.[^.]*$//'`.\${OBJEXT}" fi PKG_OBJECTS="$PKG_OBJECTS $j" ;; esac done vars="htmlutil.c" for i in $vars; do case $i in \$*) # allow $-var names PKG_SOURCES="$PKG_SOURCES $i" PKG_OBJECTS="$PKG_OBJECTS $i" ;; *) # check for existence - allows for generic/win/unix VPATH if test ! -f "${srcdir}/$i" -a ! -f "${srcdir}/src/$i" \ -a ! -f "${srcdir}/win/$i" -a ! -f "${srcdir}/unix/$i" \ ; then { { echo "$as_me:$LINENO: error: could not find source file '$i'" >&5 echo "$as_me: error: could not find source file '$i'" >&2;} { (exit 1); exit 1; }; } fi PKG_SOURCES="$PKG_SOURCES $i" # this assumes it is in a VPATH dir i=`basename $i` # handle user calling this before or after TEA_SETUP_COMPILER if test x"${OBJEXT}" != x ; then j="`echo $i | sed -e 's/\.[^.]*$//'`.${OBJEXT}" else j="`echo $i | sed -e 's/\.[^.]*$//'`.\${OBJEXT}" fi PKG_OBJECTS="$PKG_OBJECTS $j" ;; esac done vars="" for i in $vars; do # check for existence, be strict because it is installed if test ! -f "${srcdir}/$i" ; then { { echo "$as_me:$LINENO: error: could not find header file '${srcdir}/$i'" >&5 echo "$as_me: error: could not find header file '${srcdir}/$i'" >&2;} { (exit 1); exit 1; }; } fi PKG_HEADERS="$PKG_HEADERS $i" done vars="" for i in $vars; do PKG_INCLUDES="$PKG_INCLUDES $i" done vars="" for i in $vars; do if test "${TEA_PLATFORM}" = "windows" -a "$GCC" = "yes" ; then # Convert foo.lib to -lfoo for GCC. No-op if not *.lib i=`echo "$i" | sed -e 's/^\([^-].*\)\.lib$/-l\1/i'` fi PKG_LIBS="$PKG_LIBS $i" done PKG_CFLAGS="$PKG_CFLAGS " vars="" for i in $vars; do # check for existence - allows for generic/win/unix VPATH if test ! -f "${srcdir}/$i" -a ! -f "${srcdir}/generic/$i" \ -a ! -f "${srcdir}/win/$i" -a ! -f "${srcdir}/unix/$i" \ ; then { { echo "$as_me:$LINENO: error: could not find stub source file '$i'" >&5 echo "$as_me: error: could not find stub source file '$i'" >&2;} { (exit 1); exit 1; }; } fi PKG_STUB_SOURCES="$PKG_STUB_SOURCES $i" # this assumes it is in a VPATH dir i=`basename $i` # handle user calling this before or after TEA_SETUP_COMPILER if test x"${OBJEXT}" != x ; then j="`echo $i | sed -e 's/\.[^.]*$//'`.${OBJEXT}" else j="`echo $i | sed -e 's/\.[^.]*$//'`.\${OBJEXT}" fi PKG_STUB_OBJECTS="$PKG_STUB_OBJECTS $j" done vars="" for i in $vars; do # check for existence, be strict because it is installed if test ! -f "${srcdir}/$i" ; then { { echo "$as_me:$LINENO: error: could not find tcl source file '${srcdir}/$i'" >&5 echo "$as_me: error: could not find tcl source file '${srcdir}/$i'" >&2;} { (exit 1); exit 1; }; } fi PKG_TCL_SOURCES="$PKG_TCL_SOURCES $i" done #-------------------------------------------------------------------- # __CHANGE__ # A few miscellaneous platform-specific items: # # Define a special symbol for Windows (BUILD_sample in this case) so # that we create the export library with the dll. # # Windows creates a few extra files that need to be cleaned up. # You can add more files to clean if your extension creates any extra # files. # # TEA_ADD_* any platform specific compiler/build info here. #-------------------------------------------------------------------- if test "${TEA_PLATFORM}" = "windows" ; then cat >>confdefs.h <<\_ACEOF #define BUILD_sample 1 _ACEOF CLEANFILES="pkgIndex.tcl *.lib *.dll *.exp *.ilk *.pdb vc*.pch" #TEA_ADD_SOURCES([win/winFile.c]) #TEA_ADD_INCLUDES([-I\"$(${CYGPATH} ${srcdir}/win)\"]) # TEA_ADD_LIBS([-lopengl32 -lglu32 -lgdi32]) else CLEANFILES="pkgIndex.tcl" #TEA_ADD_SOURCES([unix/unixFile.c]) #TEA_ADD_LIBS([-lsuperfly]) # TEA_ADD_LIBS([-lGL -lGLU]) fi #-------------------------------------------------------------------- # __CHANGE__ # Choose which headers you need. Extension authors should try very # hard to only rely on the Tcl public header files. Internal headers # contain private data structures and are subject to change without # notice. # This MUST be called after TEA_LOAD_TCLCONFIG / TEA_LOAD_TKCONFIG #-------------------------------------------------------------------- echo "$as_me:$LINENO: checking for Tcl public headers" >&5 echo $ECHO_N "checking for Tcl public headers... $ECHO_C" >&6 # Check whether --with-tclinclude or --without-tclinclude was given. if test "${with_tclinclude+set}" = set; then withval="$with_tclinclude" with_tclinclude=${withval} fi; if test "${ac_cv_c_tclh+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else # Use the value from --with-tclinclude, if it was given if test x"${with_tclinclude}" != x ; then if test -f "${with_tclinclude}/tcl.h" ; then ac_cv_c_tclh=${with_tclinclude} else { { echo "$as_me:$LINENO: error: ${with_tclinclude} directory does not contain tcl.h" >&5 echo "$as_me: error: ${with_tclinclude} directory does not contain tcl.h" >&2;} { (exit 1); exit 1; }; } fi else if test "`uname -s`" = "Darwin"; then # If Tcl was built as a framework, attempt to use # the framework's Headers directory case ${TCL_DEFS} in *TCL_FRAMEWORK*) list="`ls -d ${TCL_BIN_DIR}/Headers 2>/dev/null`" ;; esac fi # Look in the source dir only if Tcl is not installed, # and in that situation, look there before installed locations. if test -f "${TCL_BIN_DIR}/Makefile" ; then list="$list `ls -d ${TCL_SRC_DIR}/generic 2>/dev/null`" fi # Check order: pkg --prefix location, Tcl's --prefix location, # relative to directory of tclConfig.sh. eval "temp_includedir=${includedir}" list="$list \ `ls -d ${temp_includedir} 2>/dev/null` \ `ls -d ${TCL_PREFIX}/include 2>/dev/null` \ `ls -d ${TCL_BIN_DIR}/../include 2>/dev/null`" if test "${TEA_PLATFORM}" != "windows" -o "$GCC" = "yes"; then list="$list /usr/local/include /usr/include" if test x"${TCL_INCLUDE_SPEC}" != x ; then d=`echo "${TCL_INCLUDE_SPEC}" | sed -e 's/^-I//'` list="$list `ls -d ${d} 2>/dev/null`" fi fi for i in $list ; do if test -f "$i/tcl.h" ; then ac_cv_c_tclh=$i break fi done fi fi # Print a message based on how we determined the include path if test x"${ac_cv_c_tclh}" = x ; then { { echo "$as_me:$LINENO: error: tcl.h not found. Please specify its location with --with-tclinclude" >&5 echo "$as_me: error: tcl.h not found. Please specify its location with --with-tclinclude" >&2;} { (exit 1); exit 1; }; } else echo "$as_me:$LINENO: result: ${ac_cv_c_tclh}" >&5 echo "${ECHO_T}${ac_cv_c_tclh}" >&6 fi # Convert to a native path and substitute into the output files. INCLUDE_DIR_NATIVE=`${CYGPATH} ${ac_cv_c_tclh}` TCL_INCLUDES=-I\"${INCLUDE_DIR_NATIVE}\" #TEA_PRIVATE_TCL_HEADERS echo "$as_me:$LINENO: checking for Tk public headers" >&5 echo $ECHO_N "checking for Tk public headers... $ECHO_C" >&6 # Check whether --with-tkinclude or --without-tkinclude was given. if test "${with_tkinclude+set}" = set; then withval="$with_tkinclude" with_tkinclude=${withval} fi; if test "${ac_cv_c_tkh+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else # Use the value from --with-tkinclude, if it was given if test x"${with_tkinclude}" != x ; then if test -f "${with_tkinclude}/tk.h" ; then ac_cv_c_tkh=${with_tkinclude} else { { echo "$as_me:$LINENO: error: ${with_tkinclude} directory does not contain tk.h" >&5 echo "$as_me: error: ${with_tkinclude} directory does not contain tk.h" >&2;} { (exit 1); exit 1; }; } fi else if test "`uname -s`" = "Darwin"; then # If Tk was built as a framework, attempt to use # the framework's Headers directory. case ${TK_DEFS} in *TK_FRAMEWORK*) list="`ls -d ${TK_BIN_DIR}/Headers 2>/dev/null`" ;; esac fi # Look in the source dir only if Tk is not installed, # and in that situation, look there before installed locations. if test -f "${TK_BIN_DIR}/Makefile" ; then list="$list `ls -d ${TK_SRC_DIR}/generic 2>/dev/null`" fi # Check order: pkg --prefix location, Tk's --prefix location, # relative to directory of tkConfig.sh, Tcl's --prefix location, # relative to directory of tclConfig.sh. eval "temp_includedir=${includedir}" list="$list \ `ls -d ${temp_includedir} 2>/dev/null` \ `ls -d ${TK_PREFIX}/include 2>/dev/null` \ `ls -d ${TK_BIN_DIR}/../include 2>/dev/null` \ `ls -d ${TCL_PREFIX}/include 2>/dev/null` \ `ls -d ${TCL_BIN_DIR}/../include 2>/dev/null`" if test "${TEA_PLATFORM}" != "windows" -o "$GCC" = "yes"; then list="$list /usr/local/include /usr/include" fi for i in $list ; do if test -f "$i/tk.h" ; then ac_cv_c_tkh=$i break fi done fi fi # Print a message based on how we determined the include path if test x"${ac_cv_c_tkh}" = x ; then { { echo "$as_me:$LINENO: error: tk.h not found. Please specify its location with --with-tkinclude" >&5 echo "$as_me: error: tk.h not found. Please specify its location with --with-tkinclude" >&2;} { (exit 1); exit 1; }; } else echo "$as_me:$LINENO: result: ${ac_cv_c_tkh}" >&5 echo "${ECHO_T}${ac_cv_c_tkh}" >&6 fi # Convert to a native path and substitute into the output files. INCLUDE_DIR_NATIVE=`${CYGPATH} ${ac_cv_c_tkh}` TK_INCLUDES=-I\"${INCLUDE_DIR_NATIVE}\" if test "${TEA_WINDOWINGSYSTEM}" = "win32" \ -o "${TEA_WINDOWINGSYSTEM}" = "aqua"; then # On Windows and Aqua, we need the X compat headers echo "$as_me:$LINENO: checking for X11 header files" >&5 echo $ECHO_N "checking for X11 header files... $ECHO_C" >&6 if test ! -r "${INCLUDE_DIR_NATIVE}/X11/Xlib.h"; then INCLUDE_DIR_NATIVE="`${CYGPATH} ${TK_SRC_DIR}/xlib`" TK_XINCLUDES=-I\"${INCLUDE_DIR_NATIVE}\" fi echo "$as_me:$LINENO: result: ${INCLUDE_DIR_NATIVE}" >&5 echo "${ECHO_T}${INCLUDE_DIR_NATIVE}" >&6 fi #TEA_PRIVATE_TK_HEADERS if test "${TEA_WINDOWINGSYSTEM}" = "x11" ; then echo "$as_me:$LINENO: checking for X" >&5 echo $ECHO_N "checking for X... $ECHO_C" >&6 # Check whether --with-x or --without-x was given. if test "${with_x+set}" = set; then withval="$with_x" fi; # $have_x is `yes', `no', `disabled', or empty when we do not yet know. if test "x$with_x" = xno; then # The user explicitly disabled X. have_x=disabled else if test "x$x_includes" != xNONE && test "x$x_libraries" != xNONE; then # Both variables are already set. have_x=yes else if test "${ac_cv_have_x+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else # One or both of the vars are not set, and there is no cached value. ac_x_includes=no ac_x_libraries=no rm -fr conftest.dir if mkdir conftest.dir; then cd conftest.dir # Make sure to not put "make" in the Imakefile rules, since we grep it out. cat >Imakefile <<'_ACEOF' acfindx: @echo 'ac_im_incroot="${INCROOT}"; ac_im_usrlibdir="${USRLIBDIR}"; ac_im_libdir="${LIBDIR}"' _ACEOF if (xmkmf) >/dev/null 2>/dev/null && test -f Makefile; then # GNU make sometimes prints "make[1]: Entering...", which would confuse us. eval `${MAKE-make} acfindx 2>/dev/null | grep -v make` # Open Windows xmkmf reportedly sets LIBDIR instead of USRLIBDIR. for ac_extension in a so sl; do if test ! -f $ac_im_usrlibdir/libX11.$ac_extension && test -f $ac_im_libdir/libX11.$ac_extension; then ac_im_usrlibdir=$ac_im_libdir; break fi done # Screen out bogus values from the imake configuration. They are # bogus both because they are the default anyway, and because # using them would break gcc on systems where it needs fixed includes. case $ac_im_incroot in /usr/include) ;; *) test -f "$ac_im_incroot/X11/Xos.h" && ac_x_includes=$ac_im_incroot;; esac case $ac_im_usrlibdir in /usr/lib | /lib) ;; *) test -d "$ac_im_usrlibdir" && ac_x_libraries=$ac_im_usrlibdir ;; esac fi cd .. rm -fr conftest.dir fi # Standard set of common directories for X headers. # Check X11 before X11Rn because it is often a symlink to the current release. ac_x_header_dirs=' /usr/X11/include /usr/X11R6/include /usr/X11R5/include /usr/X11R4/include /usr/include/X11 /usr/include/X11R6 /usr/include/X11R5 /usr/include/X11R4 /usr/local/X11/include /usr/local/X11R6/include /usr/local/X11R5/include /usr/local/X11R4/include /usr/local/include/X11 /usr/local/include/X11R6 /usr/local/include/X11R5 /usr/local/include/X11R4 /usr/X386/include /usr/x386/include /usr/XFree86/include/X11 /usr/include /usr/local/include /usr/unsupported/include /usr/athena/include /usr/local/x11r5/include /usr/lpp/Xamples/include /usr/openwin/include /usr/openwin/share/include' if test "$ac_x_includes" = no; then # Guess where to find include files, by looking for Intrinsic.h. # First, try using that file with no special directory specified. cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include _ACEOF if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } >/dev/null; then if test -s conftest.err; then ac_cpp_err=$ac_c_preproc_warn_flag ac_cpp_err=$ac_cpp_err$ac_c_werror_flag else ac_cpp_err= fi else ac_cpp_err=yes fi if test -z "$ac_cpp_err"; then # We can compile using X headers with no special include directory. ac_x_includes= else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 for ac_dir in $ac_x_header_dirs; do if test -r "$ac_dir/X11/Intrinsic.h"; then ac_x_includes=$ac_dir break fi done fi rm -f conftest.err conftest.$ac_ext fi # $ac_x_includes = no if test "$ac_x_libraries" = no; then # Check for the libraries. # See if we find them without any special options. # Don't add to $LIBS permanently. ac_save_LIBS=$LIBS LIBS="-lXt $LIBS" cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include int main () { XtMalloc (0) ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest$ac_exeext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then LIBS=$ac_save_LIBS # We can link X programs with no special library path. ac_x_libraries= else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 LIBS=$ac_save_LIBS for ac_dir in `echo "$ac_x_includes $ac_x_header_dirs" | sed s/include/lib/g` do # Don't even attempt the hair of trying to link an X program! for ac_extension in a so sl; do if test -r $ac_dir/libXt.$ac_extension; then ac_x_libraries=$ac_dir break 2 fi done done fi rm -f conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi # $ac_x_libraries = no if test "$ac_x_includes" = no || test "$ac_x_libraries" = no; then # Didn't find X anywhere. Cache the known absence of X. ac_cv_have_x="have_x=no" else # Record where we found X for the cache. ac_cv_have_x="have_x=yes \ ac_x_includes=$ac_x_includes ac_x_libraries=$ac_x_libraries" fi fi fi eval "$ac_cv_have_x" fi # $with_x != no if test "$have_x" != yes; then echo "$as_me:$LINENO: result: $have_x" >&5 echo "${ECHO_T}$have_x" >&6 no_x=yes else # If each of the values was on the command line, it overrides each guess. test "x$x_includes" = xNONE && x_includes=$ac_x_includes test "x$x_libraries" = xNONE && x_libraries=$ac_x_libraries # Update the cache value to reflect the command line values. ac_cv_have_x="have_x=yes \ ac_x_includes=$x_includes ac_x_libraries=$x_libraries" echo "$as_me:$LINENO: result: libraries $x_libraries, headers $x_includes" >&5 echo "${ECHO_T}libraries $x_libraries, headers $x_includes" >&6 fi not_really_there="" if test "$no_x" = ""; then if test "$x_includes" = ""; then cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include _ACEOF if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } >/dev/null; then if test -s conftest.err; then ac_cpp_err=$ac_c_preproc_warn_flag ac_cpp_err=$ac_cpp_err$ac_c_werror_flag else ac_cpp_err= fi else ac_cpp_err=yes fi if test -z "$ac_cpp_err"; then : else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 not_really_there="yes" fi rm -f conftest.err conftest.$ac_ext else if test ! -r $x_includes/X11/Intrinsic.h; then not_really_there="yes" fi fi fi if test "$no_x" = "yes" -o "$not_really_there" = "yes"; then echo "$as_me:$LINENO: checking for X11 header files" >&5 echo $ECHO_N "checking for X11 header files... $ECHO_C" >&6 found_xincludes="no" cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include _ACEOF if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } >/dev/null; then if test -s conftest.err; then ac_cpp_err=$ac_c_preproc_warn_flag ac_cpp_err=$ac_cpp_err$ac_c_werror_flag else ac_cpp_err= fi else ac_cpp_err=yes fi if test -z "$ac_cpp_err"; then found_xincludes="yes" else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 found_xincludes="no" fi rm -f conftest.err conftest.$ac_ext if test "$found_xincludes" = "no"; then dirs="/usr/unsupported/include /usr/local/include /usr/X386/include /usr/X11R6/include /usr/X11R5/include /usr/include/X11R5 /usr/include/X11R4 /usr/openwin/include /usr/X11/include /usr/sww/include" for i in $dirs ; do if test -r $i/X11/Intrinsic.h; then echo "$as_me:$LINENO: result: $i" >&5 echo "${ECHO_T}$i" >&6 XINCLUDES=" -I$i" found_xincludes="yes" break fi done fi else if test "$x_includes" != ""; then XINCLUDES="-I$x_includes" found_xincludes="yes" fi fi if test found_xincludes = "no"; then echo "$as_me:$LINENO: result: couldn't find any!" >&5 echo "${ECHO_T}couldn't find any!" >&6 fi if test "$no_x" = yes; then echo "$as_me:$LINENO: checking for X11 libraries" >&5 echo $ECHO_N "checking for X11 libraries... $ECHO_C" >&6 XLIBSW=nope dirs="/usr/unsupported/lib /usr/local/lib /usr/X386/lib /usr/X11R6/lib /usr/X11R5/lib /usr/lib/X11R5 /usr/lib/X11R4 /usr/openwin/lib /usr/X11/lib /usr/sww/X11/lib" for i in $dirs ; do if test -r $i/libX11.a -o -r $i/libX11.so -o -r $i/libX11.sl; then echo "$as_me:$LINENO: result: $i" >&5 echo "${ECHO_T}$i" >&6 XLIBSW="-L$i -lX11" x_libraries="$i" break fi done else if test "$x_libraries" = ""; then XLIBSW=-lX11 else XLIBSW="-L$x_libraries -lX11" fi fi if test "$XLIBSW" = nope ; then echo "$as_me:$LINENO: checking for XCreateWindow in -lXwindow" >&5 echo $ECHO_N "checking for XCreateWindow in -lXwindow... $ECHO_C" >&6 if test "${ac_cv_lib_Xwindow_XCreateWindow+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lXwindow $LIBS" cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ /* Override any gcc2 internal prototype to avoid an error. */ #ifdef __cplusplus extern "C" #endif /* We use char because int might match the return type of a gcc2 builtin and then its argument prototype would still apply. */ char XCreateWindow (); int main () { XCreateWindow (); ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest$ac_exeext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_lib_Xwindow_XCreateWindow=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_lib_Xwindow_XCreateWindow=no fi rm -f conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi echo "$as_me:$LINENO: result: $ac_cv_lib_Xwindow_XCreateWindow" >&5 echo "${ECHO_T}$ac_cv_lib_Xwindow_XCreateWindow" >&6 if test $ac_cv_lib_Xwindow_XCreateWindow = yes; then XLIBSW=-lXwindow fi fi if test "$XLIBSW" = nope ; then echo "$as_me:$LINENO: result: could not find any! Using -lX11." >&5 echo "${ECHO_T}could not find any! Using -lX11." >&6 XLIBSW=-lX11 fi if test x"${XLIBSW}" != x ; then PKG_LIBS="${PKG_LIBS} ${XLIBSW}" fi fi #-------------------------------------------------------------------- # Check whether --enable-threads or --disable-threads was given. # This auto-enables if Tcl was compiled threaded. #-------------------------------------------------------------------- # Check whether --enable-threads or --disable-threads was given. if test "${enable_threads+set}" = set; then enableval="$enable_threads" tcl_ok=$enableval else tcl_ok=yes fi; if test "${enable_threads+set}" = set; then enableval="$enable_threads" tcl_ok=$enableval else tcl_ok=yes fi if test "$tcl_ok" = "yes" -o "${TCL_THREADS}" = 1; then TCL_THREADS=1 if test "${TEA_PLATFORM}" != "windows" ; then # We are always OK on Windows, so check what this platform wants: # USE_THREAD_ALLOC tells us to try the special thread-based # allocator that significantly reduces lock contention cat >>confdefs.h <<\_ACEOF #define USE_THREAD_ALLOC 1 _ACEOF cat >>confdefs.h <<\_ACEOF #define _REENTRANT 1 _ACEOF if test "`uname -s`" = "SunOS" ; then cat >>confdefs.h <<\_ACEOF #define _POSIX_PTHREAD_SEMANTICS 1 _ACEOF fi cat >>confdefs.h <<\_ACEOF #define _THREAD_SAFE 1 _ACEOF echo "$as_me:$LINENO: checking for pthread_mutex_init in -lpthread" >&5 echo $ECHO_N "checking for pthread_mutex_init in -lpthread... $ECHO_C" >&6 if test "${ac_cv_lib_pthread_pthread_mutex_init+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lpthread $LIBS" cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ /* Override any gcc2 internal prototype to avoid an error. */ #ifdef __cplusplus extern "C" #endif /* We use char because int might match the return type of a gcc2 builtin and then its argument prototype would still apply. */ char pthread_mutex_init (); int main () { pthread_mutex_init (); ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest$ac_exeext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_lib_pthread_pthread_mutex_init=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_lib_pthread_pthread_mutex_init=no fi rm -f conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi echo "$as_me:$LINENO: result: $ac_cv_lib_pthread_pthread_mutex_init" >&5 echo "${ECHO_T}$ac_cv_lib_pthread_pthread_mutex_init" >&6 if test $ac_cv_lib_pthread_pthread_mutex_init = yes; then tcl_ok=yes else tcl_ok=no fi if test "$tcl_ok" = "no"; then # Check a little harder for __pthread_mutex_init in the same # library, as some systems hide it there until pthread.h is # defined. We could alternatively do an AC_TRY_COMPILE with # pthread.h, but that will work with libpthread really doesn't # exist, like AIX 4.2. [Bug: 4359] echo "$as_me:$LINENO: checking for __pthread_mutex_init in -lpthread" >&5 echo $ECHO_N "checking for __pthread_mutex_init in -lpthread... $ECHO_C" >&6 if test "${ac_cv_lib_pthread___pthread_mutex_init+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lpthread $LIBS" cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ /* Override any gcc2 internal prototype to avoid an error. */ #ifdef __cplusplus extern "C" #endif /* We use char because int might match the return type of a gcc2 builtin and then its argument prototype would still apply. */ char __pthread_mutex_init (); int main () { __pthread_mutex_init (); ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest$ac_exeext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_lib_pthread___pthread_mutex_init=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_lib_pthread___pthread_mutex_init=no fi rm -f conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi echo "$as_me:$LINENO: result: $ac_cv_lib_pthread___pthread_mutex_init" >&5 echo "${ECHO_T}$ac_cv_lib_pthread___pthread_mutex_init" >&6 if test $ac_cv_lib_pthread___pthread_mutex_init = yes; then tcl_ok=yes else tcl_ok=no fi fi if test "$tcl_ok" = "yes"; then # The space is needed THREADS_LIBS=" -lpthread" else echo "$as_me:$LINENO: checking for pthread_mutex_init in -lpthreads" >&5 echo $ECHO_N "checking for pthread_mutex_init in -lpthreads... $ECHO_C" >&6 if test "${ac_cv_lib_pthreads_pthread_mutex_init+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lpthreads $LIBS" cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ /* Override any gcc2 internal prototype to avoid an error. */ #ifdef __cplusplus extern "C" #endif /* We use char because int might match the return type of a gcc2 builtin and then its argument prototype would still apply. */ char pthread_mutex_init (); int main () { pthread_mutex_init (); ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest$ac_exeext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_lib_pthreads_pthread_mutex_init=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_lib_pthreads_pthread_mutex_init=no fi rm -f conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi echo "$as_me:$LINENO: result: $ac_cv_lib_pthreads_pthread_mutex_init" >&5 echo "${ECHO_T}$ac_cv_lib_pthreads_pthread_mutex_init" >&6 if test $ac_cv_lib_pthreads_pthread_mutex_init = yes; then tcl_ok=yes else tcl_ok=no fi if test "$tcl_ok" = "yes"; then # The space is needed THREADS_LIBS=" -lpthreads" else echo "$as_me:$LINENO: checking for pthread_mutex_init in -lc" >&5 echo $ECHO_N "checking for pthread_mutex_init in -lc... $ECHO_C" >&6 if test "${ac_cv_lib_c_pthread_mutex_init+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lc $LIBS" cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ /* Override any gcc2 internal prototype to avoid an error. */ #ifdef __cplusplus extern "C" #endif /* We use char because int might match the return type of a gcc2 builtin and then its argument prototype would still apply. */ char pthread_mutex_init (); int main () { pthread_mutex_init (); ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest$ac_exeext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_lib_c_pthread_mutex_init=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_lib_c_pthread_mutex_init=no fi rm -f conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi echo "$as_me:$LINENO: result: $ac_cv_lib_c_pthread_mutex_init" >&5 echo "${ECHO_T}$ac_cv_lib_c_pthread_mutex_init" >&6 if test $ac_cv_lib_c_pthread_mutex_init = yes; then tcl_ok=yes else tcl_ok=no fi if test "$tcl_ok" = "no"; then echo "$as_me:$LINENO: checking for pthread_mutex_init in -lc_r" >&5 echo $ECHO_N "checking for pthread_mutex_init in -lc_r... $ECHO_C" >&6 if test "${ac_cv_lib_c_r_pthread_mutex_init+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lc_r $LIBS" cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ /* Override any gcc2 internal prototype to avoid an error. */ #ifdef __cplusplus extern "C" #endif /* We use char because int might match the return type of a gcc2 builtin and then its argument prototype would still apply. */ char pthread_mutex_init (); int main () { pthread_mutex_init (); ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest$ac_exeext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_lib_c_r_pthread_mutex_init=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_lib_c_r_pthread_mutex_init=no fi rm -f conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi echo "$as_me:$LINENO: result: $ac_cv_lib_c_r_pthread_mutex_init" >&5 echo "${ECHO_T}$ac_cv_lib_c_r_pthread_mutex_init" >&6 if test $ac_cv_lib_c_r_pthread_mutex_init = yes; then tcl_ok=yes else tcl_ok=no fi if test "$tcl_ok" = "yes"; then # The space is needed THREADS_LIBS=" -pthread" else TCL_THREADS=0 { echo "$as_me:$LINENO: WARNING: Do not know how to find pthread lib on your system - thread support disabled" >&5 echo "$as_me: WARNING: Do not know how to find pthread lib on your system - thread support disabled" >&2;} fi fi fi fi fi else TCL_THREADS=0 fi # Do checking message here to not mess up interleaved configure output echo "$as_me:$LINENO: checking for building with threads" >&5 echo $ECHO_N "checking for building with threads... $ECHO_C" >&6 if test "${TCL_THREADS}" = 1; then cat >>confdefs.h <<\_ACEOF #define TCL_THREADS 1 _ACEOF echo "$as_me:$LINENO: result: yes (default)" >&5 echo "${ECHO_T}yes (default)" >&6 else echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6 fi # TCL_THREADS sanity checking. See if our request for building with # threads is the same as the way Tcl was built. If not, warn the user. case ${TCL_DEFS} in *THREADS=1*) if test "${TCL_THREADS}" = "0"; then { echo "$as_me:$LINENO: WARNING: Building ${PACKAGE_NAME} without threads enabled, but building against Tcl that IS thread-enabled. It is recommended to use --enable-threads." >&5 echo "$as_me: WARNING: Building ${PACKAGE_NAME} without threads enabled, but building against Tcl that IS thread-enabled. It is recommended to use --enable-threads." >&2;} fi ;; *) if test "${TCL_THREADS}" = "1"; then { echo "$as_me:$LINENO: WARNING: --enable-threads requested, but building against a Tcl that is NOT thread-enabled. This is an OK configuration that will also run in a thread-enabled core." >&5 echo "$as_me: WARNING: --enable-threads requested, but building against a Tcl that is NOT thread-enabled. This is an OK configuration that will also run in a thread-enabled core." >&2;} fi ;; esac #-------------------------------------------------------------------- # The statement below defines a collection of symbols related to # building as a shared library instead of a static library. #-------------------------------------------------------------------- echo "$as_me:$LINENO: checking how to build libraries" >&5 echo $ECHO_N "checking how to build libraries... $ECHO_C" >&6 # Check whether --enable-shared or --disable-shared was given. if test "${enable_shared+set}" = set; then enableval="$enable_shared" tcl_ok=$enableval else tcl_ok=yes fi; if test "${enable_shared+set}" = set; then enableval="$enable_shared" tcl_ok=$enableval else tcl_ok=yes fi if test "$tcl_ok" = "yes" ; then echo "$as_me:$LINENO: result: shared" >&5 echo "${ECHO_T}shared" >&6 SHARED_BUILD=1 else echo "$as_me:$LINENO: result: static" >&5 echo "${ECHO_T}static" >&6 SHARED_BUILD=0 cat >>confdefs.h <<\_ACEOF #define STATIC_BUILD 1 _ACEOF fi #-------------------------------------------------------------------- # This macro figures out what flags to use with the compiler/linker # when building shared/static debug/optimized objects. This information # can be taken from the tclConfig.sh file, but this figures it all out. #-------------------------------------------------------------------- # Step 0.a: Enable 64 bit support? echo "$as_me:$LINENO: checking if 64bit support is requested" >&5 echo $ECHO_N "checking if 64bit support is requested... $ECHO_C" >&6 # Check whether --enable-64bit or --disable-64bit was given. if test "${enable_64bit+set}" = set; then enableval="$enable_64bit" do64bit=$enableval else do64bit=no fi; echo "$as_me:$LINENO: result: $do64bit" >&5 echo "${ECHO_T}$do64bit" >&6 # Step 0.b: Enable Solaris 64 bit VIS support? echo "$as_me:$LINENO: checking if 64bit Sparc VIS support is requested" >&5 echo $ECHO_N "checking if 64bit Sparc VIS support is requested... $ECHO_C" >&6 # Check whether --enable-64bit-vis or --disable-64bit-vis was given. if test "${enable_64bit_vis+set}" = set; then enableval="$enable_64bit_vis" do64bitVIS=$enableval else do64bitVIS=no fi; echo "$as_me:$LINENO: result: $do64bitVIS" >&5 echo "${ECHO_T}$do64bitVIS" >&6 if test "$do64bitVIS" = "yes"; then # Force 64bit on with VIS do64bit=yes fi # Step 0.c: Cross-compiling options for Windows/CE builds? if test "${TEA_PLATFORM}" = "windows" ; then echo "$as_me:$LINENO: checking if Windows/CE build is requested" >&5 echo $ECHO_N "checking if Windows/CE build is requested... $ECHO_C" >&6 # Check whether --enable-wince or --disable-wince was given. if test "${enable_wince+set}" = set; then enableval="$enable_wince" doWince=$enableval else doWince=no fi; echo "$as_me:$LINENO: result: $doWince" >&5 echo "${ECHO_T}$doWince" >&6 fi # Step 1: set the variable "system" to hold the name and version number # for the system. echo "$as_me:$LINENO: checking system version" >&5 echo $ECHO_N "checking system version... $ECHO_C" >&6 if test "${tcl_cv_sys_version+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else if test "${TEA_PLATFORM}" = "windows" ; then tcl_cv_sys_version=windows elif test -f /usr/lib/NextStep/software_version; then tcl_cv_sys_version=NEXTSTEP-`awk '/3/,/3/' /usr/lib/NextStep/software_version` else tcl_cv_sys_version=`uname -s`-`uname -r` if test "$?" -ne 0 ; then { echo "$as_me:$LINENO: WARNING: can't find uname command" >&5 echo "$as_me: WARNING: can't find uname command" >&2;} tcl_cv_sys_version=unknown else # Special check for weird MP-RAS system (uname returns weird # results, and the version is kept in special file). if test -r /etc/.relid -a "X`uname -n`" = "X`uname -s`" ; then tcl_cv_sys_version=MP-RAS-`awk '{print }' /etc/.relid` fi if test "`uname -s`" = "AIX" ; then tcl_cv_sys_version=AIX-`uname -v`.`uname -r` fi fi fi fi echo "$as_me:$LINENO: result: $tcl_cv_sys_version" >&5 echo "${ECHO_T}$tcl_cv_sys_version" >&6 system=$tcl_cv_sys_version # Step 2: check for existence of -ldl library. This is needed because # Linux can use either -ldl or -ldld for dynamic loading. echo "$as_me:$LINENO: checking for dlopen in -ldl" >&5 echo $ECHO_N "checking for dlopen in -ldl... $ECHO_C" >&6 if test "${ac_cv_lib_dl_dlopen+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-ldl $LIBS" cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ /* Override any gcc2 internal prototype to avoid an error. */ #ifdef __cplusplus extern "C" #endif /* We use char because int might match the return type of a gcc2 builtin and then its argument prototype would still apply. */ char dlopen (); int main () { dlopen (); ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest$ac_exeext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_lib_dl_dlopen=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_lib_dl_dlopen=no fi rm -f conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi echo "$as_me:$LINENO: result: $ac_cv_lib_dl_dlopen" >&5 echo "${ECHO_T}$ac_cv_lib_dl_dlopen" >&6 if test $ac_cv_lib_dl_dlopen = yes; then have_dl=yes else have_dl=no fi # Require ranlib early so we can override it in special cases below. # Step 3: set configuration options based on system name and version. # This is similar to Tcl's unix/tcl.m4 except that we've added a # "windows" case. do64bit_ok=no LDFLAGS_ORIG="$LDFLAGS" # When ld needs options to work in 64-bit mode, put them in # LDFLAGS_ARCH so they eventually end up in LDFLAGS even if [load] # is disabled by the user. [Bug 1016796] LDFLAGS_ARCH="" TCL_EXPORT_FILE_SUFFIX="" UNSHARED_LIB_SUFFIX="" TCL_TRIM_DOTS='`echo ${PACKAGE_VERSION} | tr -d .`' ECHO_VERSION='`echo ${PACKAGE_VERSION}`' TCL_LIB_VERSIONS_OK=ok CFLAGS_DEBUG=-g CFLAGS_OPTIMIZE=-O if test "$GCC" = "yes" ; then CFLAGS_OPTIMIZE=-O2 CFLAGS_WARNING="-Wall -Wno-implicit-int" else CFLAGS_WARNING="" fi TCL_NEEDS_EXP_FILE=0 TCL_BUILD_EXP_FILE="" TCL_EXP_FILE="" # Extract the first word of "ar", so it can be a program name with args. set dummy ar; ac_word=$2 echo "$as_me:$LINENO: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 if test "${ac_cv_prog_AR+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else if test -n "$AR"; then ac_cv_prog_AR="$AR" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_AR="ar" echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done fi fi AR=$ac_cv_prog_AR if test -n "$AR"; then echo "$as_me:$LINENO: result: $AR" >&5 echo "${ECHO_T}$AR" >&6 else echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6 fi STLIB_LD='${AR} cr' LD_LIBRARY_PATH_VAR="LD_LIBRARY_PATH" case $system in windows) # This is a 2-stage check to make sure we have the 64-bit SDK # We have to know where the SDK is installed. # This magic is based on MS Platform SDK for Win2003 SP1 - hobbs # MACHINE is IX86 for LINK, but this is used by the manifest, # which requires x86|amd64|ia64. MACHINE="X86" if test "$do64bit" != "no" ; then if test "x${MSSDK}x" = "xx" ; then MSSDK="C:/Progra~1/Microsoft Platform SDK" fi MSSDK=`echo "$MSSDK" | sed -e 's!\\\!/!g'` PATH64="" case "$do64bit" in amd64|x64|yes) MACHINE="AMD64" ; # default to AMD64 64-bit build PATH64="${MSSDK}/Bin/Win64/x86/AMD64" ;; ia64) MACHINE="IA64" PATH64="${MSSDK}/Bin/Win64" ;; esac if test ! -d "${PATH64}" ; then { echo "$as_me:$LINENO: WARNING: Could not find 64-bit $MACHINE SDK to enable 64bit mode" >&5 echo "$as_me: WARNING: Could not find 64-bit $MACHINE SDK to enable 64bit mode" >&2;} { echo "$as_me:$LINENO: WARNING: Ensure latest Platform SDK is installed" >&5 echo "$as_me: WARNING: Ensure latest Platform SDK is installed" >&2;} do64bit="no" else echo "$as_me:$LINENO: result: Using 64-bit $MACHINE mode" >&5 echo "${ECHO_T} Using 64-bit $MACHINE mode" >&6 do64bit_ok="yes" fi fi if test "$doWince" != "no" ; then if test "$do64bit" != "no" ; then { { echo "$as_me:$LINENO: error: Windows/CE and 64-bit builds incompatible" >&5 echo "$as_me: error: Windows/CE and 64-bit builds incompatible" >&2;} { (exit 1); exit 1; }; } fi if test "$GCC" = "yes" ; then { { echo "$as_me:$LINENO: error: Windows/CE and GCC builds incompatible" >&5 echo "$as_me: error: Windows/CE and GCC builds incompatible" >&2;} { (exit 1); exit 1; }; } fi # First, look for one uninstalled. # the alternative search directory is invoked by --with-celib if test x"${no_celib}" = x ; then # we reset no_celib in case something fails here no_celib=true # Check whether --with-celib or --without-celib was given. if test "${with_celib+set}" = set; then withval="$with_celib" with_celibconfig=${withval} fi; echo "$as_me:$LINENO: checking for Windows/CE celib directory" >&5 echo $ECHO_N "checking for Windows/CE celib directory... $ECHO_C" >&6 if test "${ac_cv_c_celibconfig+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else # First check to see if --with-celibconfig was specified. if test x"${with_celibconfig}" != x ; then if test -d "${with_celibconfig}/inc" ; then ac_cv_c_celibconfig=`(cd ${with_celibconfig}; pwd)` else { { echo "$as_me:$LINENO: error: ${with_celibconfig} directory doesn't contain inc directory" >&5 echo "$as_me: error: ${with_celibconfig} directory doesn't contain inc directory" >&2;} { (exit 1); exit 1; }; } fi fi # then check for a celib library if test x"${ac_cv_c_celibconfig}" = x ; then for i in \ ../celib-palm-3.0 \ ../celib \ ../../celib-palm-3.0 \ ../../celib \ `ls -dr ../celib-*3.[0-9]* 2>/dev/null` \ ${srcdir}/../celib-palm-3.0 \ ${srcdir}/../celib \ `ls -dr ${srcdir}/../celib-*3.[0-9]* 2>/dev/null` \ ; do if test -d "$i/inc" ; then ac_cv_c_celibconfig=`(cd $i; pwd)` break fi done fi fi if test x"${ac_cv_c_celibconfig}" = x ; then { { echo "$as_me:$LINENO: error: Cannot find celib support library directory" >&5 echo "$as_me: error: Cannot find celib support library directory" >&2;} { (exit 1); exit 1; }; } else no_celib= CELIB_DIR=${ac_cv_c_celibconfig} CELIB_DIR=`echo "$CELIB_DIR" | sed -e 's!\\\!/!g'` echo "$as_me:$LINENO: result: found $CELIB_DIR" >&5 echo "${ECHO_T}found $CELIB_DIR" >&6 fi fi # Set defaults for common evc4/PPC2003 setup # Currently Tcl requires 300+, possibly 420+ for sockets CEVERSION=420; # could be 211 300 301 400 420 ... TARGETCPU=ARMV4; # could be ARMV4 ARM MIPS SH3 X86 ... ARCH=ARM; # could be ARM MIPS X86EM ... PLATFORM="Pocket PC 2003"; # or "Pocket PC 2002" if test "$doWince" != "yes"; then # If !yes then the user specified something # Reset ARCH to allow user to skip specifying it ARCH= eval `echo $doWince | awk -F, '{ \ if (length($1)) { printf "CEVERSION=\"%s\"\n", $1; \ if ($1 < 400) { printf "PLATFORM=\"Pocket PC 2002\"\n" } }; \ if (length($2)) { printf "TARGETCPU=\"%s\"\n", toupper($2) }; \ if (length($3)) { printf "ARCH=\"%s\"\n", toupper($3) }; \ if (length($4)) { printf "PLATFORM=\"%s\"\n", $4 }; \ }'` if test "x${ARCH}" = "x" ; then ARCH=$TARGETCPU; fi fi OSVERSION=WCE$CEVERSION; if test "x${WCEROOT}" = "x" ; then WCEROOT="C:/Program Files/Microsoft eMbedded C++ 4.0" if test ! -d "${WCEROOT}" ; then WCEROOT="C:/Program Files/Microsoft eMbedded Tools" fi fi if test "x${SDKROOT}" = "x" ; then SDKROOT="C:/Program Files/Windows CE Tools" if test ! -d "${SDKROOT}" ; then SDKROOT="C:/Windows CE Tools" fi fi WCEROOT=`echo "$WCEROOT" | sed -e 's!\\\!/!g'` SDKROOT=`echo "$SDKROOT" | sed -e 's!\\\!/!g'` if test ! -d "${SDKROOT}/${OSVERSION}/${PLATFORM}/Lib/${TARGETCPU}" \ -o ! -d "${WCEROOT}/EVC/${OSVERSION}/bin"; then { { echo "$as_me:$LINENO: error: could not find PocketPC SDK or target compiler to enable WinCE mode $CEVERSION,$TARGETCPU,$ARCH,$PLATFORM" >&5 echo "$as_me: error: could not find PocketPC SDK or target compiler to enable WinCE mode $CEVERSION,$TARGETCPU,$ARCH,$PLATFORM" >&2;} { (exit 1); exit 1; }; } doWince="no" else # We could PATH_NOSPACE these, but that's not important, # as long as we quote them when used. CEINCLUDE="${SDKROOT}/${OSVERSION}/${PLATFORM}/include" if test -d "${CEINCLUDE}/${TARGETCPU}" ; then CEINCLUDE="${CEINCLUDE}/${TARGETCPU}" fi CELIBPATH="${SDKROOT}/${OSVERSION}/${PLATFORM}/Lib/${TARGETCPU}" fi fi if test "$GCC" != "yes" ; then if test "${SHARED_BUILD}" = "0" ; then runtime=-MT else runtime=-MD fi if test "$do64bit" != "no" ; then # All this magic is necessary for the Win64 SDK RC1 - hobbs CC="\"${PATH64}/cl.exe\"" CFLAGS="${CFLAGS} -I\"${MSSDK}/Include\" -I\"${MSSDK}/Include/crt\" -I\"${MSSDK}/Include/crt/sys\"" RC="\"${MSSDK}/bin/rc.exe\"" lflags="-nologo -MACHINE:${MACHINE} -LIBPATH:\"${MSSDK}/Lib/${MACHINE}\"" LINKBIN="\"${PATH64}/link.exe\"" CFLAGS_DEBUG="-nologo -Zi -Od -W3 ${runtime}d" CFLAGS_OPTIMIZE="-nologo -O2 -W2 ${runtime}" # Avoid 'unresolved external symbol __security_cookie' # errors, c.f. http://support.microsoft.com/?id=894573 vars="bufferoverflowU.lib" for i in $vars; do if test "${TEA_PLATFORM}" = "windows" -a "$GCC" = "yes" ; then # Convert foo.lib to -lfoo for GCC. No-op if not *.lib i=`echo "$i" | sed -e 's/^\([^-].*\)\.lib$/-l\1/i'` fi PKG_LIBS="$PKG_LIBS $i" done elif test "$doWince" != "no" ; then CEBINROOT="${WCEROOT}/EVC/${OSVERSION}/bin" if test "${TARGETCPU}" = "X86"; then CC="\"${CEBINROOT}/cl.exe\"" else CC="\"${CEBINROOT}/cl${ARCH}.exe\"" fi CFLAGS="$CFLAGS -I\"${CELIB_DIR}/inc\" -I\"${CEINCLUDE}\"" RC="\"${WCEROOT}/Common/EVC/bin/rc.exe\"" arch=`echo ${ARCH} | awk '{print tolower($0)}'` defs="${ARCH} _${ARCH}_ ${arch} PALM_SIZE _MT _WINDOWS" if test "${SHARED_BUILD}" = "1" ; then # Static CE builds require static celib as well defs="${defs} _DLL" fi for i in $defs ; do cat >>confdefs.h <<_ACEOF #define $i 1 _ACEOF done cat >>confdefs.h <<_ACEOF #define _WIN32_WCE $CEVERSION _ACEOF cat >>confdefs.h <<_ACEOF #define UNDER_CE $CEVERSION _ACEOF CFLAGS_DEBUG="-nologo -Zi -Od" CFLAGS_OPTIMIZE="-nologo -Ox" lversion=`echo ${CEVERSION} | sed -e 's/\(.\)\(..\)/\1\.\2/'` lflags="-MACHINE:${ARCH} -LIBPATH:\"${CELIBPATH}\" -subsystem:windowsce,${lversion} -nologo" LINKBIN="\"${CEBINROOT}/link.exe\"" else RC="rc" lflags="-nologo" LINKBIN="link" CFLAGS_DEBUG="-nologo -Z7 -Od -W3 -WX ${runtime}d" CFLAGS_OPTIMIZE="-nologo -O2 -W2 ${runtime}" fi fi if test "$GCC" = "yes"; then # mingw gcc mode RC="windres" CFLAGS_DEBUG="-g" CFLAGS_OPTIMIZE="-O2 -fomit-frame-pointer" SHLIB_LD="$CC -shared" UNSHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.a' LDFLAGS_CONSOLE="-wl,--subsystem,console ${lflags}" LDFLAGS_WINDOW="-wl,--subsystem,windows ${lflags}" else SHLIB_LD="${LINKBIN} -dll ${lflags}" # link -lib only works when -lib is the first arg STLIB_LD="${LINKBIN} -lib ${lflags}" UNSHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.lib' PATHTYPE=-w # For information on what debugtype is most useful, see: # http://msdn.microsoft.com/library/en-us/dnvc60/html/gendepdebug.asp # This essentially turns it all on. LDFLAGS_DEBUG="-debug:full -debugtype:both -warn:2" LDFLAGS_OPTIMIZE="-release" if test "$doWince" != "no" ; then LDFLAGS_CONSOLE="-link ${lflags}" LDFLAGS_WINDOW=${LDFLAGS_CONSOLE} else LDFLAGS_CONSOLE="-link -subsystem:console ${lflags}" LDFLAGS_WINDOW="-link -subsystem:windows ${lflags}" fi fi SHLIB_LD_LIBS='${LIBS}' SHLIB_SUFFIX=".dll" SHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.dll' TCL_LIB_VERSIONS_OK=nodots # Bogus to avoid getting this turned off DL_OBJS="tclLoadNone.obj" ;; AIX-*) if test "${TCL_THREADS}" = "1" -a "$GCC" != "yes" ; then # AIX requires the _r compiler when gcc isn't being used case "${CC}" in *_r) # ok ... ;; *) CC=${CC}_r ;; esac echo "$as_me:$LINENO: result: Using $CC for compiling with threads" >&5 echo "${ECHO_T}Using $CC for compiling with threads" >&6 fi LIBS="$LIBS -lc" SHLIB_CFLAGS="" SHLIB_LD_LIBS='${LIBS}' SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" LD_LIBRARY_PATH_VAR="LIBPATH" # Check to enable 64-bit flags for compiler/linker on AIX 4+ if test "$do64bit" = "yes" -a "`uname -v`" -gt "3" ; then if test "$GCC" = "yes" ; then { echo "$as_me:$LINENO: WARNING: 64bit mode not supported with GCC on $system" >&5 echo "$as_me: WARNING: 64bit mode not supported with GCC on $system" >&2;} else do64bit_ok=yes CFLAGS="$CFLAGS -q64" LDFLAGS_ARCH="-q64" RANLIB="${RANLIB} -X64" AR="${AR} -X64" SHLIB_LD_FLAGS="-b64" fi fi if test "`uname -m`" = "ia64" ; then # AIX-5 uses ELF style dynamic libraries on IA-64, but not PPC SHLIB_LD="/usr/ccs/bin/ld -G -z text" # AIX-5 has dl* in libc.so DL_LIBS="" if test "$GCC" = "yes" ; then CC_SEARCH_FLAGS='-Wl,-R,${LIB_RUNTIME_DIR}' else CC_SEARCH_FLAGS='-R${LIB_RUNTIME_DIR}' fi LD_SEARCH_FLAGS='-R ${LIB_RUNTIME_DIR}' else if test "$GCC" = "yes" ; then SHLIB_LD="gcc -shared" else SHLIB_LD="/bin/ld -bhalt:4 -bM:SRE -bE:lib.exp -H512 -T512 -bnoentry" fi SHLIB_LD="${TCL_SRC_DIR}/unix/ldAix ${SHLIB_LD} ${SHLIB_LD_FLAGS}" DL_LIBS="-ldl" CC_SEARCH_FLAGS='-L${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} TCL_NEEDS_EXP_FILE=1 TCL_EXPORT_FILE_SUFFIX='${PACKAGE_VERSION}.exp' fi # AIX v<=4.1 has some different flags than 4.2+ if test "$system" = "AIX-4.1" -o "`uname -v`" -lt "4" ; then case $LIBOBJS in "tclLoadAix.$ac_objext" | \ *" tclLoadAix.$ac_objext" | \ "tclLoadAix.$ac_objext "* | \ *" tclLoadAix.$ac_objext "* ) ;; *) LIBOBJS="$LIBOBJS tclLoadAix.$ac_objext" ;; esac DL_LIBS="-lld" fi # On AIX <=v4 systems, libbsd.a has to be linked in to support # non-blocking file IO. This library has to be linked in after # the MATH_LIBS or it breaks the pow() function. The way to # insure proper sequencing, is to add it to the tail of MATH_LIBS. # This library also supplies gettimeofday. # # AIX does not have a timezone field in struct tm. When the AIX # bsd library is used, the timezone global and the gettimeofday # methods are to be avoided for timezone deduction instead, we # deduce the timezone by comparing the localtime result on a # known GMT value. echo "$as_me:$LINENO: checking for gettimeofday in -lbsd" >&5 echo $ECHO_N "checking for gettimeofday in -lbsd... $ECHO_C" >&6 if test "${ac_cv_lib_bsd_gettimeofday+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lbsd $LIBS" cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ /* Override any gcc2 internal prototype to avoid an error. */ #ifdef __cplusplus extern "C" #endif /* We use char because int might match the return type of a gcc2 builtin and then its argument prototype would still apply. */ char gettimeofday (); int main () { gettimeofday (); ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest$ac_exeext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_lib_bsd_gettimeofday=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_lib_bsd_gettimeofday=no fi rm -f conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi echo "$as_me:$LINENO: result: $ac_cv_lib_bsd_gettimeofday" >&5 echo "${ECHO_T}$ac_cv_lib_bsd_gettimeofday" >&6 if test $ac_cv_lib_bsd_gettimeofday = yes; then libbsd=yes else libbsd=no fi if test $libbsd = yes; then MATH_LIBS="$MATH_LIBS -lbsd" cat >>confdefs.h <<\_ACEOF #define USE_DELTA_FOR_TZ 1 _ACEOF fi ;; BeOS*) SHLIB_CFLAGS="-fPIC" SHLIB_LD="${CC} -nostart" SHLIB_LD_LIBS='${LIBS}' SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" DL_LIBS="-ldl" #----------------------------------------------------------- # Check for inet_ntoa in -lbind, for BeOS (which also needs # -lsocket, even if the network functions are in -lnet which # is always linked to, for compatibility. #----------------------------------------------------------- echo "$as_me:$LINENO: checking for inet_ntoa in -lbind" >&5 echo $ECHO_N "checking for inet_ntoa in -lbind... $ECHO_C" >&6 if test "${ac_cv_lib_bind_inet_ntoa+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lbind $LIBS" cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ /* Override any gcc2 internal prototype to avoid an error. */ #ifdef __cplusplus extern "C" #endif /* We use char because int might match the return type of a gcc2 builtin and then its argument prototype would still apply. */ char inet_ntoa (); int main () { inet_ntoa (); ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest$ac_exeext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_lib_bind_inet_ntoa=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_lib_bind_inet_ntoa=no fi rm -f conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi echo "$as_me:$LINENO: result: $ac_cv_lib_bind_inet_ntoa" >&5 echo "${ECHO_T}$ac_cv_lib_bind_inet_ntoa" >&6 if test $ac_cv_lib_bind_inet_ntoa = yes; then LIBS="$LIBS -lbind -lsocket" fi ;; BSD/OS-2.1*|BSD/OS-3*) SHLIB_CFLAGS="" SHLIB_LD="shlicc -r" SHLIB_LD_LIBS='${LIBS}' SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" DL_LIBS="-ldl" CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" ;; BSD/OS-4.*) SHLIB_CFLAGS="-export-dynamic -fPIC" SHLIB_LD="cc -shared" SHLIB_LD_LIBS='${LIBS}' SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" DL_LIBS="-ldl" LDFLAGS="$LDFLAGS -export-dynamic" CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" ;; dgux*) SHLIB_CFLAGS="-K PIC" SHLIB_LD="cc -G" SHLIB_LD_LIBS="" SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" DL_LIBS="-ldl" CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" ;; HP-UX-*.11.*) # Use updated header definitions where possible cat >>confdefs.h <<\_ACEOF #define _XOPEN_SOURCE_EXTENDED 1 _ACEOF # Needed by Tcl, but not most extensions #AC_DEFINE(_XOPEN_SOURCE, 1, [Do we want to use the XOPEN network library?]) #LIBS="$LIBS -lxnet" # Use the XOPEN network library SHLIB_SUFFIX=".sl" echo "$as_me:$LINENO: checking for shl_load in -ldld" >&5 echo $ECHO_N "checking for shl_load in -ldld... $ECHO_C" >&6 if test "${ac_cv_lib_dld_shl_load+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-ldld $LIBS" cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ /* Override any gcc2 internal prototype to avoid an error. */ #ifdef __cplusplus extern "C" #endif /* We use char because int might match the return type of a gcc2 builtin and then its argument prototype would still apply. */ char shl_load (); int main () { shl_load (); ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest$ac_exeext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_lib_dld_shl_load=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_lib_dld_shl_load=no fi rm -f conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi echo "$as_me:$LINENO: result: $ac_cv_lib_dld_shl_load" >&5 echo "${ECHO_T}$ac_cv_lib_dld_shl_load" >&6 if test $ac_cv_lib_dld_shl_load = yes; then tcl_ok=yes else tcl_ok=no fi if test "$tcl_ok" = yes; then SHLIB_CFLAGS="+z" SHLIB_LD="ld -b" SHLIB_LD_LIBS='${LIBS}' DL_OBJS="tclLoadShl.o" DL_LIBS="-ldld" LDFLAGS="$LDFLAGS -Wl,-E" CC_SEARCH_FLAGS='-Wl,+s,+b,${LIB_RUNTIME_DIR}:.' LD_SEARCH_FLAGS='+s +b ${LIB_RUNTIME_DIR}:.' LD_LIBRARY_PATH_VAR="SHLIB_PATH" fi if test "$GCC" = "yes" ; then SHLIB_LD="gcc -shared" SHLIB_LD_LIBS='${LIBS}' LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} fi # Users may want PA-RISC 1.1/2.0 portable code - needs HP cc #CFLAGS="$CFLAGS +DAportable" # Check to enable 64-bit flags for compiler/linker if test "$do64bit" = "yes" ; then if test "$GCC" = "yes" ; then hpux_arch=`${CC} -dumpmachine` case $hpux_arch in hppa64*) # 64-bit gcc in use. Fix flags for GNU ld. do64bit_ok=yes SHLIB_LD="${CC} -shared" SHLIB_LD_LIBS='${LIBS}' CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} ;; *) { echo "$as_me:$LINENO: WARNING: 64bit mode not supported with GCC on $system" >&5 echo "$as_me: WARNING: 64bit mode not supported with GCC on $system" >&2;} ;; esac else do64bit_ok=yes CFLAGS="$CFLAGS +DD64" LDFLAGS_ARCH="+DD64" fi fi ;; HP-UX-*.08.*|HP-UX-*.09.*|HP-UX-*.10.*) SHLIB_SUFFIX=".sl" echo "$as_me:$LINENO: checking for shl_load in -ldld" >&5 echo $ECHO_N "checking for shl_load in -ldld... $ECHO_C" >&6 if test "${ac_cv_lib_dld_shl_load+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-ldld $LIBS" cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ /* Override any gcc2 internal prototype to avoid an error. */ #ifdef __cplusplus extern "C" #endif /* We use char because int might match the return type of a gcc2 builtin and then its argument prototype would still apply. */ char shl_load (); int main () { shl_load (); ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest$ac_exeext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_lib_dld_shl_load=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_lib_dld_shl_load=no fi rm -f conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi echo "$as_me:$LINENO: result: $ac_cv_lib_dld_shl_load" >&5 echo "${ECHO_T}$ac_cv_lib_dld_shl_load" >&6 if test $ac_cv_lib_dld_shl_load = yes; then tcl_ok=yes else tcl_ok=no fi if test "$tcl_ok" = yes; then SHLIB_CFLAGS="+z" SHLIB_LD="ld -b" SHLIB_LD_LIBS="" DL_OBJS="tclLoadShl.o" DL_LIBS="-ldld" LDFLAGS="$LDFLAGS -Wl,-E" CC_SEARCH_FLAGS='-Wl,+s,+b,${LIB_RUNTIME_DIR}:.' LD_SEARCH_FLAGS='+s +b ${LIB_RUNTIME_DIR}:.' LD_LIBRARY_PATH_VAR="SHLIB_PATH" fi ;; IRIX-5.*) SHLIB_CFLAGS="" SHLIB_LD="ld -shared -rdata_shared" SHLIB_LD_LIBS='${LIBS}' SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" DL_LIBS="" CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS='-rpath ${LIB_RUNTIME_DIR}' ;; IRIX-6.*) SHLIB_CFLAGS="" SHLIB_LD="ld -n32 -shared -rdata_shared" SHLIB_LD_LIBS='${LIBS}' SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" DL_LIBS="" CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS='-rpath ${LIB_RUNTIME_DIR}' if test "$GCC" = "yes" ; then CFLAGS="$CFLAGS -mabi=n32" LDFLAGS="$LDFLAGS -mabi=n32" else case $system in IRIX-6.3) # Use to build 6.2 compatible binaries on 6.3. CFLAGS="$CFLAGS -n32 -D_OLD_TERMIOS" ;; *) CFLAGS="$CFLAGS -n32" ;; esac LDFLAGS="$LDFLAGS -n32" fi ;; IRIX64-6.*) SHLIB_CFLAGS="" SHLIB_LD="ld -n32 -shared -rdata_shared" SHLIB_LD_LIBS='${LIBS}' SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" DL_LIBS="" CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS='-rpath ${LIB_RUNTIME_DIR}' # Check to enable 64-bit flags for compiler/linker if test "$do64bit" = "yes" ; then if test "$GCC" = "yes" ; then { echo "$as_me:$LINENO: WARNING: 64bit mode not supported by gcc" >&5 echo "$as_me: WARNING: 64bit mode not supported by gcc" >&2;} else do64bit_ok=yes SHLIB_LD="ld -64 -shared -rdata_shared" CFLAGS="$CFLAGS -64" LDFLAGS_ARCH="-64" fi fi ;; Linux*) SHLIB_CFLAGS="-fPIC" SHLIB_LD_LIBS='${LIBS}' SHLIB_SUFFIX=".so" CFLAGS_OPTIMIZE="-O2 -fomit-frame-pointer" # egcs-2.91.66 on Redhat Linux 6.0 generates lots of warnings # when you inline the string and math operations. Turn this off to # get rid of the warnings. #CFLAGS_OPTIMIZE="${CFLAGS_OPTIMIZE} -D__NO_STRING_INLINES -D__NO_MATH_INLINES" SHLIB_LD="${CC} -shared" DL_OBJS="tclLoadDl.o" DL_LIBS="-ldl" LDFLAGS="$LDFLAGS -Wl,--export-dynamic" CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} if test "`uname -m`" = "alpha" ; then CFLAGS="$CFLAGS -mieee" fi # The combo of gcc + glibc has a bug related # to inlining of functions like strtod(). The # -fno-builtin flag should address this problem # but it does not work. The -fno-inline flag # is kind of overkill but it works. # Disable inlining only when one of the # files in compat/*.c is being linked in. if test x"${USE_COMPAT}" != x ; then CFLAGS="$CFLAGS -fno-inline" fi ;; GNU*) SHLIB_CFLAGS="-fPIC" SHLIB_LD_LIBS='${LIBS}' SHLIB_SUFFIX=".so" SHLIB_LD="${CC} -shared" DL_OBJS="" DL_LIBS="-ldl" LDFLAGS="$LDFLAGS -Wl,--export-dynamic" CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" if test "`uname -m`" = "alpha" ; then CFLAGS="$CFLAGS -mieee" fi ;; Lynx*) SHLIB_CFLAGS="-fPIC" SHLIB_LD_LIBS='${LIBS}' SHLIB_SUFFIX=".so" CFLAGS_OPTIMIZE=-02 SHLIB_LD="${CC} -shared " DL_OBJS="tclLoadDl.o" DL_LIBS="-mshared -ldl" LD_FLAGS="-Wl,--export-dynamic" CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' ;; MP-RAS-02*) SHLIB_CFLAGS="-K PIC" SHLIB_LD="cc -G" SHLIB_LD_LIBS="" SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" DL_LIBS="-ldl" CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" ;; MP-RAS-*) SHLIB_CFLAGS="-K PIC" SHLIB_LD="cc -G" SHLIB_LD_LIBS="" SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" DL_LIBS="-ldl" LDFLAGS="$LDFLAGS -Wl,-Bexport" CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" ;; NetBSD-*|FreeBSD-[1-2].*) # NetBSD/SPARC needs -fPIC, -fpic will not do. SHLIB_CFLAGS="-fPIC" SHLIB_LD="ld -Bshareable -x" SHLIB_LD_LIBS="" SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" DL_LIBS="" CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS='-rpath ${LIB_RUNTIME_DIR}' echo "$as_me:$LINENO: checking for ELF" >&5 echo $ECHO_N "checking for ELF... $ECHO_C" >&6 if test "${tcl_cv_ld_elf+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #ifdef __ELF__ yes #endif _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "yes" >/dev/null 2>&1; then tcl_cv_ld_elf=yes else tcl_cv_ld_elf=no fi rm -f conftest* fi echo "$as_me:$LINENO: result: $tcl_cv_ld_elf" >&5 echo "${ECHO_T}$tcl_cv_ld_elf" >&6 if test $tcl_cv_ld_elf = yes; then SHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.so' else SHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.so.1.0' fi # Ancient FreeBSD doesn't handle version numbers with dots. UNSHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.a' TCL_LIB_VERSIONS_OK=nodots ;; OpenBSD-*) # OpenBSD/SPARC[64] needs -fPIC, -fpic will not do. case `machine` in sparc|sparc64) SHLIB_CFLAGS="-fPIC";; *) SHLIB_CFLAGS="-fpic";; esac SHLIB_LD="${CC} -shared ${SHLIB_CFLAGS}" SHLIB_LD_LIBS='${LIBS}' SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" DL_LIBS="" CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} SHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.so.1.0' echo "$as_me:$LINENO: checking for ELF" >&5 echo $ECHO_N "checking for ELF... $ECHO_C" >&6 if test "${tcl_cv_ld_elf+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #ifdef __ELF__ yes #endif _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "yes" >/dev/null 2>&1; then tcl_cv_ld_elf=yes else tcl_cv_ld_elf=no fi rm -f conftest* fi echo "$as_me:$LINENO: result: $tcl_cv_ld_elf" >&5 echo "${ECHO_T}$tcl_cv_ld_elf" >&6 if test $tcl_cv_ld_elf = yes; then LDFLAGS=-Wl,-export-dynamic else LDFLAGS="" fi # OpenBSD doesn't do version numbers with dots. UNSHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.a' TCL_LIB_VERSIONS_OK=nodots ;; FreeBSD-*) # FreeBSD 3.* and greater have ELF. SHLIB_CFLAGS="-fPIC" SHLIB_LD="ld -Bshareable -x" SHLIB_LD_LIBS='${LIBS}' SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" DL_LIBS="" LDFLAGS="$LDFLAGS -export-dynamic" CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS='-rpath ${LIB_RUNTIME_DIR}' if test "${TCL_THREADS}" = "1" ; then # The -pthread needs to go in the CFLAGS, not LIBS LIBS=`echo $LIBS | sed s/-pthread//` CFLAGS="$CFLAGS -pthread" LDFLAGS="$LDFLAGS -pthread" fi case $system in FreeBSD-3.*) # FreeBSD-3 doesn't handle version numbers with dots. UNSHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.a' SHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.so' TCL_LIB_VERSIONS_OK=nodots ;; esac ;; Darwin-*) CFLAGS_OPTIMIZE="-Os" SHLIB_CFLAGS="-fno-common" if test $do64bit = yes; then do64bit_ok=yes CFLAGS="$CFLAGS -arch ppc64 -mpowerpc64 -mcpu=G5" fi # TEA specific: use LDFLAGS_DEFAULT instead of LDFLAGS here: SHLIB_LD='${CC} -dynamiclib ${CFLAGS} ${LDFLAGS_DEFAULT}' echo "$as_me:$LINENO: checking if ld accepts -single_module flag" >&5 echo $ECHO_N "checking if ld accepts -single_module flag... $ECHO_C" >&6 if test "${tcl_cv_ld_single_module+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else hold_ldflags=$LDFLAGS LDFLAGS="$LDFLAGS -dynamiclib -Wl,-single_module" cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ int main () { int i; ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest$ac_exeext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then tcl_cv_ld_single_module=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 tcl_cv_ld_single_module=no fi rm -f conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LDFLAGS=$hold_ldflags fi echo "$as_me:$LINENO: result: $tcl_cv_ld_single_module" >&5 echo "${ECHO_T}$tcl_cv_ld_single_module" >&6 if test $tcl_cv_ld_single_module = yes; then SHLIB_LD="${SHLIB_LD} -Wl,-single_module" fi SHLIB_LD_LIBS='${LIBS}' SHLIB_SUFFIX=".dylib" DL_OBJS="tclLoadDyld.o" DL_LIBS="" # Don't use -prebind when building for Mac OS X 10.4 or later only: test -z "${MACOSX_DEPLOYMENT_TARGET}" || \ test "`echo "${MACOSX_DEPLOYMENT_TARGET}" | awk -F. '{print $2}'`" -lt 4 && \ LDFLAGS="$LDFLAGS -prebind" LDFLAGS="$LDFLAGS -headerpad_max_install_names" echo "$as_me:$LINENO: checking if ld accepts -search_paths_first flag" >&5 echo $ECHO_N "checking if ld accepts -search_paths_first flag... $ECHO_C" >&6 if test "${tcl_cv_ld_search_paths_first+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else hold_ldflags=$LDFLAGS LDFLAGS="$LDFLAGS -Wl,-search_paths_first" cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ int main () { int i; ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest$ac_exeext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then tcl_cv_ld_search_paths_first=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 tcl_cv_ld_search_paths_first=no fi rm -f conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LDFLAGS=$hold_ldflags fi echo "$as_me:$LINENO: result: $tcl_cv_ld_search_paths_first" >&5 echo "${ECHO_T}$tcl_cv_ld_search_paths_first" >&6 if test $tcl_cv_ld_search_paths_first = yes; then LDFLAGS="$LDFLAGS -Wl,-search_paths_first" fi CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" LD_LIBRARY_PATH_VAR="DYLD_LIBRARY_PATH" # TEA specific: for Tk extensions, remove -arch ppc64 from CFLAGS # for fat builds, as neither TkAqua nor TkX11 can be built for 64bit # at present (no 64bit GUI libraries). test $do64bit_ok = no && test -n "${TK_BIN_DIR}" && \ CFLAGS="`echo "$CFLAGS" | sed -e 's/-arch ppc64/-arch ppc/g'`" ;; NEXTSTEP-*) SHLIB_CFLAGS="" SHLIB_LD="cc -nostdlib -r" SHLIB_LD_LIBS="" SHLIB_SUFFIX=".so" DL_OBJS="tclLoadNext.o" DL_LIBS="" CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" ;; OS/390-*) CFLAGS_OPTIMIZE="" # Optimizer is buggy cat >>confdefs.h <<\_ACEOF #define _OE_SOCKETS 1 _ACEOF ;; OSF1-1.0|OSF1-1.1|OSF1-1.2) # OSF/1 1.[012] from OSF, and derivatives, including Paragon OSF/1 SHLIB_CFLAGS="" # Hack: make package name same as library name SHLIB_LD='ld -R -export :' SHLIB_LD_LIBS="" SHLIB_SUFFIX=".so" DL_OBJS="tclLoadOSF.o" DL_LIBS="" CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" ;; OSF1-1.*) # OSF/1 1.3 from OSF using ELF, and derivatives, including AD2 SHLIB_CFLAGS="-fPIC" if test "$SHARED_BUILD" = "1" ; then SHLIB_LD="ld -shared" else SHLIB_LD="ld -non_shared" fi SHLIB_LD_LIBS="" SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" DL_LIBS="" CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" ;; OSF1-V*) # Digital OSF/1 SHLIB_CFLAGS="" if test "$SHARED_BUILD" = "1" ; then SHLIB_LD='ld -shared -expect_unresolved "*"' else SHLIB_LD='ld -non_shared -expect_unresolved "*"' fi SHLIB_LD_LIBS="" SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" DL_LIBS="" CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS='-rpath ${LIB_RUNTIME_DIR}' if test "$GCC" = "yes" ; then CFLAGS="$CFLAGS -mieee" else CFLAGS="$CFLAGS -DHAVE_TZSET -std1 -ieee" fi # see pthread_intro(3) for pthread support on osf1, k.furukawa if test "${TCL_THREADS}" = "1" ; then CFLAGS="$CFLAGS -DHAVE_PTHREAD_ATTR_SETSTACKSIZE" CFLAGS="$CFLAGS -DTCL_THREAD_STACK_MIN=PTHREAD_STACK_MIN*64" LIBS=`echo $LIBS | sed s/-lpthreads//` if test "$GCC" = "yes" ; then LIBS="$LIBS -lpthread -lmach -lexc" else CFLAGS="$CFLAGS -pthread" LDFLAGS="$LDFLAGS -pthread" fi fi ;; QNX-6*) # QNX RTP # This may work for all QNX, but it was only reported for v6. SHLIB_CFLAGS="-fPIC" SHLIB_LD="ld -Bshareable -x" SHLIB_LD_LIBS="" SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" # dlopen is in -lc on QNX DL_LIBS="" CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" ;; SCO_SV-3.2*) # Note, dlopen is available only on SCO 3.2.5 and greater. However, # this test works, since "uname -s" was non-standard in 3.2.4 and # below. if test "$GCC" = "yes" ; then SHLIB_CFLAGS="-fPIC -melf" LDFLAGS="$LDFLAGS -melf -Wl,-Bexport" else SHLIB_CFLAGS="-Kpic -belf" LDFLAGS="$LDFLAGS -belf -Wl,-Bexport" fi SHLIB_LD="ld -G" SHLIB_LD_LIBS="" SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" DL_LIBS="" CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" ;; SINIX*5.4*) SHLIB_CFLAGS="-K PIC" SHLIB_LD="cc -G" SHLIB_LD_LIBS="" SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" DL_LIBS="-ldl" CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" ;; SunOS-4*) SHLIB_CFLAGS="-PIC" SHLIB_LD="ld" SHLIB_LD_LIBS="" SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" DL_LIBS="-ldl" CC_SEARCH_FLAGS='-L${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} # SunOS can't handle version numbers with dots in them in library # specs, like -ltcl7.5, so use -ltcl75 instead. Also, it # requires an extra version number at the end of .so file names. # So, the library has to have a name like libtcl75.so.1.0 SHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.so.1.0' UNSHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.a' TCL_LIB_VERSIONS_OK=nodots ;; SunOS-5.[0-6]) # Careful to not let 5.10+ fall into this case # Note: If _REENTRANT isn't defined, then Solaris # won't define thread-safe library routines. cat >>confdefs.h <<\_ACEOF #define _REENTRANT 1 _ACEOF cat >>confdefs.h <<\_ACEOF #define _POSIX_PTHREAD_SEMANTICS 1 _ACEOF SHLIB_CFLAGS="-KPIC" # Note: need the LIBS below, otherwise Tk won't find Tcl's # symbols when dynamically loaded into tclsh. SHLIB_LD_LIBS='${LIBS}' SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" DL_LIBS="-ldl" if test "$GCC" = "yes" ; then SHLIB_LD="$CC -shared" CC_SEARCH_FLAGS='-Wl,-R,${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} else SHLIB_LD="/usr/ccs/bin/ld -G -z text" CC_SEARCH_FLAGS='-R ${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} fi ;; SunOS-5*) # Note: If _REENTRANT isn't defined, then Solaris # won't define thread-safe library routines. cat >>confdefs.h <<\_ACEOF #define _REENTRANT 1 _ACEOF cat >>confdefs.h <<\_ACEOF #define _POSIX_PTHREAD_SEMANTICS 1 _ACEOF SHLIB_CFLAGS="-KPIC" # Check to enable 64-bit flags for compiler/linker if test "$do64bit" = "yes" ; then arch=`isainfo` if test "$arch" = "sparcv9 sparc" ; then if test "$GCC" = "yes" ; then if test "`gcc -dumpversion | awk -F. '{print $1}'`" -lt "3" ; then { echo "$as_me:$LINENO: WARNING: 64bit mode not supported with GCC < 3.2 on $system" >&5 echo "$as_me: WARNING: 64bit mode not supported with GCC < 3.2 on $system" >&2;} else do64bit_ok=yes CFLAGS="$CFLAGS -m64 -mcpu=v9" LDFLAGS="$LDFLAGS -m64 -mcpu=v9" SHLIB_CFLAGS="-fPIC" fi else do64bit_ok=yes if test "$do64bitVIS" = "yes" ; then CFLAGS="$CFLAGS -xarch=v9a" LDFLAGS_ARCH="-xarch=v9a" else CFLAGS="$CFLAGS -xarch=v9" LDFLAGS_ARCH="-xarch=v9" fi # Solaris 64 uses this as well #LD_LIBRARY_PATH_VAR="LD_LIBRARY_PATH_64" fi elif test "$arch" = "amd64 i386" ; then if test "$GCC" = "yes" ; then { echo "$as_me:$LINENO: WARNING: 64bit mode not supported with GCC on $system" >&5 echo "$as_me: WARNING: 64bit mode not supported with GCC on $system" >&2;} else do64bit_ok=yes CFLAGS="$CFLAGS -xarch=amd64" LDFLAGS="$LDFLAGS -xarch=amd64" fi else { echo "$as_me:$LINENO: WARNING: 64bit mode not supported for $arch" >&5 echo "$as_me: WARNING: 64bit mode not supported for $arch" >&2;} fi fi # Note: need the LIBS below, otherwise Tk won't find Tcl's # symbols when dynamically loaded into tclsh. SHLIB_LD_LIBS='${LIBS}' SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" DL_LIBS="-ldl" if test "$GCC" = "yes" ; then SHLIB_LD="$CC -shared" CC_SEARCH_FLAGS='-Wl,-R,${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} if test "$do64bit_ok" = "yes" ; then # We need to specify -static-libgcc or we need to # add the path to the sparv9 libgcc. # JH: static-libgcc is necessary for core Tcl, but may # not be necessary for extensions. SHLIB_LD="$SHLIB_LD -m64 -mcpu=v9 -static-libgcc" # for finding sparcv9 libgcc, get the regular libgcc # path, remove so name and append 'sparcv9' #v9gcclibdir="`gcc -print-file-name=libgcc_s.so` | ..." #CC_SEARCH_FLAGS="${CC_SEARCH_FLAGS},-R,$v9gcclibdir" fi else SHLIB_LD="/usr/ccs/bin/ld -G -z text" CC_SEARCH_FLAGS='-Wl,-R,${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS='-R ${LIB_RUNTIME_DIR}' fi ;; UNIX_SV* | UnixWare-5*) SHLIB_CFLAGS="-KPIC" SHLIB_LD="cc -G" SHLIB_LD_LIBS="" SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" DL_LIBS="-ldl" # Some UNIX_SV* systems (unixware 1.1.2 for example) have linkers # that don't grok the -Bexport option. Test that it does. echo "$as_me:$LINENO: checking for ld accepts -Bexport flag" >&5 echo $ECHO_N "checking for ld accepts -Bexport flag... $ECHO_C" >&6 if test "${tcl_cv_ld_Bexport+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else hold_ldflags=$LDFLAGS LDFLAGS="$LDFLAGS -Wl,-Bexport" cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ int main () { int i; ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest$ac_exeext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then tcl_cv_ld_Bexport=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 tcl_cv_ld_Bexport=no fi rm -f conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LDFLAGS=$hold_ldflags fi echo "$as_me:$LINENO: result: $tcl_cv_ld_Bexport" >&5 echo "${ECHO_T}$tcl_cv_ld_Bexport" >&6 if test $tcl_cv_ld_Bexport = yes; then LDFLAGS="$LDFLAGS -Wl,-Bexport" fi CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" ;; esac if test "$do64bit" = "yes" -a "$do64bit_ok" = "no" ; then { echo "$as_me:$LINENO: WARNING: 64bit support being disabled -- don't know magic for this platform" >&5 echo "$as_me: WARNING: 64bit support being disabled -- don't know magic for this platform" >&2;} fi # Step 4: disable dynamic loading if requested via a command-line switch. # Check whether --enable-load or --disable-load was given. if test "${enable_load+set}" = set; then enableval="$enable_load" tcl_ok=$enableval else tcl_ok=yes fi; if test "$tcl_ok" = "no"; then DL_OBJS="" fi if test "x$DL_OBJS" != "x" ; then BUILD_DLTEST="\$(DLTEST_TARGETS)" else echo "Can't figure out how to do dynamic loading or shared libraries" echo "on this system." SHLIB_CFLAGS="" SHLIB_LD="" SHLIB_SUFFIX="" DL_OBJS="tclLoadNone.o" DL_LIBS="" LDFLAGS="$LDFLAGS_ORIG" CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" BUILD_DLTEST="" fi LDFLAGS="$LDFLAGS $LDFLAGS_ARCH" # If we're running gcc, then change the C flags for compiling shared # libraries to the right flags for gcc, instead of those for the # standard manufacturer compiler. if test "$DL_OBJS" != "tclLoadNone.o" ; then if test "$GCC" = "yes" ; then case $system in AIX-*) ;; BSD/OS*) ;; IRIX*) ;; NetBSD-*|FreeBSD-*) ;; Darwin-*) ;; SCO_SV-3.2*) ;; windows) ;; *) SHLIB_CFLAGS="-fPIC" ;; esac fi fi if test "$SHARED_LIB_SUFFIX" = "" ; then SHARED_LIB_SUFFIX='${PACKAGE_VERSION}${SHLIB_SUFFIX}' fi if test "$UNSHARED_LIB_SUFFIX" = "" ; then UNSHARED_LIB_SUFFIX='${PACKAGE_VERSION}.a' fi # These must be called after we do the basic CFLAGS checks and # verify any possible 64-bit or similar switches are necessary echo "$as_me:$LINENO: checking for required early compiler flags" >&5 echo $ECHO_N "checking for required early compiler flags... $ECHO_C" >&6 tcl_flags="" if test "${tcl_cv_flag__isoc99_source+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include int main () { char *p = (char *)strtoll; char *q = (char *)strtoull; ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then tcl_cv_flag__isoc99_source=no else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #define _ISOC99_SOURCE 1 #include int main () { char *p = (char *)strtoll; char *q = (char *)strtoull; ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then tcl_cv_flag__isoc99_source=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 tcl_cv_flag__isoc99_source=no fi rm -f conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f conftest.err conftest.$ac_objext conftest.$ac_ext fi if test "x${tcl_cv_flag__isoc99_source}" = "xyes" ; then cat >>confdefs.h <<\_ACEOF #define _ISOC99_SOURCE 1 _ACEOF tcl_flags="$tcl_flags _ISOC99_SOURCE" fi if test "${tcl_cv_flag__largefile64_source+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include int main () { struct stat64 buf; int i = stat64("/", &buf); ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then tcl_cv_flag__largefile64_source=no else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #define _LARGEFILE64_SOURCE 1 #include int main () { struct stat64 buf; int i = stat64("/", &buf); ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then tcl_cv_flag__largefile64_source=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 tcl_cv_flag__largefile64_source=no fi rm -f conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f conftest.err conftest.$ac_objext conftest.$ac_ext fi if test "x${tcl_cv_flag__largefile64_source}" = "xyes" ; then cat >>confdefs.h <<\_ACEOF #define _LARGEFILE64_SOURCE 1 _ACEOF tcl_flags="$tcl_flags _LARGEFILE64_SOURCE" fi if test "${tcl_cv_flag__largefile_source64+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include int main () { char *p = (char *)open64; ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then tcl_cv_flag__largefile_source64=no else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #define _LARGEFILE_SOURCE64 1 #include int main () { char *p = (char *)open64; ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then tcl_cv_flag__largefile_source64=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 tcl_cv_flag__largefile_source64=no fi rm -f conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f conftest.err conftest.$ac_objext conftest.$ac_ext fi if test "x${tcl_cv_flag__largefile_source64}" = "xyes" ; then cat >>confdefs.h <<\_ACEOF #define _LARGEFILE_SOURCE64 1 _ACEOF tcl_flags="$tcl_flags _LARGEFILE_SOURCE64" fi if test "x${tcl_flags}" = "x" ; then echo "$as_me:$LINENO: result: none" >&5 echo "${ECHO_T}none" >&6 else echo "$as_me:$LINENO: result: ${tcl_flags}" >&5 echo "${ECHO_T}${tcl_flags}" >&6 fi echo "$as_me:$LINENO: checking for 64-bit integer type" >&5 echo $ECHO_N "checking for 64-bit integer type... $ECHO_C" >&6 if test "${tcl_cv_type_64bit+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else tcl_cv_type_64bit=none # See if the compiler knows natively about __int64 cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ int main () { __int64 value = (__int64) 0; ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then tcl_type_64bit=__int64 else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 tcl_type_64bit="long long" fi rm -f conftest.err conftest.$ac_objext conftest.$ac_ext # See if we should use long anyway Note that we substitute in the # type that is our current guess for a 64-bit type inside this check # program, so it should be modified only carefully... cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ int main () { switch (0) { case 1: case (sizeof(${tcl_type_64bit})==sizeof(long)): ; } ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then tcl_cv_type_64bit=${tcl_type_64bit} else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 fi rm -f conftest.err conftest.$ac_objext conftest.$ac_ext fi if test "${tcl_cv_type_64bit}" = none ; then cat >>confdefs.h <<\_ACEOF #define TCL_WIDE_INT_IS_LONG 1 _ACEOF echo "$as_me:$LINENO: result: using long" >&5 echo "${ECHO_T}using long" >&6 elif test "${tcl_cv_type_64bit}" = "__int64" \ -a "${TEA_PLATFORM}" = "windows" ; then # We actually want to use the default tcl.h checks in this # case to handle both TCL_WIDE_INT_TYPE and TCL_LL_MODIFIER* echo "$as_me:$LINENO: result: using Tcl header defaults" >&5 echo "${ECHO_T}using Tcl header defaults" >&6 else cat >>confdefs.h <<_ACEOF #define TCL_WIDE_INT_TYPE ${tcl_cv_type_64bit} _ACEOF echo "$as_me:$LINENO: result: ${tcl_cv_type_64bit}" >&5 echo "${ECHO_T}${tcl_cv_type_64bit}" >&6 # Now check for auxiliary declarations echo "$as_me:$LINENO: checking for struct dirent64" >&5 echo $ECHO_N "checking for struct dirent64... $ECHO_C" >&6 if test "${tcl_cv_struct_dirent64+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include #include int main () { struct dirent64 p; ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then tcl_cv_struct_dirent64=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 tcl_cv_struct_dirent64=no fi rm -f conftest.err conftest.$ac_objext conftest.$ac_ext fi echo "$as_me:$LINENO: result: $tcl_cv_struct_dirent64" >&5 echo "${ECHO_T}$tcl_cv_struct_dirent64" >&6 if test "x${tcl_cv_struct_dirent64}" = "xyes" ; then cat >>confdefs.h <<\_ACEOF #define HAVE_STRUCT_DIRENT64 1 _ACEOF fi echo "$as_me:$LINENO: checking for struct stat64" >&5 echo $ECHO_N "checking for struct stat64... $ECHO_C" >&6 if test "${tcl_cv_struct_stat64+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include int main () { struct stat64 p; ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then tcl_cv_struct_stat64=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 tcl_cv_struct_stat64=no fi rm -f conftest.err conftest.$ac_objext conftest.$ac_ext fi echo "$as_me:$LINENO: result: $tcl_cv_struct_stat64" >&5 echo "${ECHO_T}$tcl_cv_struct_stat64" >&6 if test "x${tcl_cv_struct_stat64}" = "xyes" ; then cat >>confdefs.h <<\_ACEOF #define HAVE_STRUCT_STAT64 1 _ACEOF fi for ac_func in open64 lseek64 do as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh` echo "$as_me:$LINENO: checking for $ac_func" >&5 echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6 if eval "test \"\${$as_ac_var+set}\" = set"; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ /* Define $ac_func to an innocuous variant, in case declares $ac_func. For example, HP-UX 11i declares gettimeofday. */ #define $ac_func innocuous_$ac_func /* System header to define __stub macros and hopefully few prototypes, which can conflict with char $ac_func (); below. Prefer to if __STDC__ is defined, since exists even on freestanding compilers. */ #ifdef __STDC__ # include #else # include #endif #undef $ac_func /* Override any gcc2 internal prototype to avoid an error. */ #ifdef __cplusplus extern "C" { #endif /* We use char because int might match the return type of a gcc2 builtin and then its argument prototype would still apply. */ char $ac_func (); /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ #if defined (__stub_$ac_func) || defined (__stub___$ac_func) choke me #else char (*f) () = $ac_func; #endif #ifdef __cplusplus } #endif int main () { return f != $ac_func; ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest$ac_exeext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then eval "$as_ac_var=yes" else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 eval "$as_ac_var=no" fi rm -f conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5 echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6 if test `eval echo '${'$as_ac_var'}'` = yes; then cat >>confdefs.h <<_ACEOF #define `echo "HAVE_$ac_func" | $as_tr_cpp` 1 _ACEOF fi done echo "$as_me:$LINENO: checking for off64_t" >&5 echo $ECHO_N "checking for off64_t... $ECHO_C" >&6 if test "${tcl_cv_type_off64_t+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include int main () { off64_t offset; ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then tcl_cv_type_off64_t=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 tcl_cv_type_off64_t=no fi rm -f conftest.err conftest.$ac_objext conftest.$ac_ext fi if test "x${tcl_cv_type_off64_t}" = "xyes" && \ test "x${ac_cv_func_lseek64}" = "xyes" && \ test "x${ac_cv_func_open64}" = "xyes" ; then cat >>confdefs.h <<\_ACEOF #define HAVE_TYPE_OFF64_T 1 _ACEOF echo "$as_me:$LINENO: result: yes" >&5 echo "${ECHO_T}yes" >&6 else echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6 fi fi #-------------------------------------------------------------------- # Set the default compiler switches based on the --enable-symbols option. #-------------------------------------------------------------------- echo "$as_me:$LINENO: checking for build with symbols" >&5 echo $ECHO_N "checking for build with symbols... $ECHO_C" >&6 # Check whether --enable-symbols or --disable-symbols was given. if test "${enable_symbols+set}" = set; then enableval="$enable_symbols" tcl_ok=$enableval else tcl_ok=no fi; DBGX="" if test "$tcl_ok" = "no"; then CFLAGS_DEFAULT="${CFLAGS_OPTIMIZE}" LDFLAGS_DEFAULT="${LDFLAGS_OPTIMIZE}" echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6 else CFLAGS_DEFAULT="${CFLAGS_DEBUG}" LDFLAGS_DEFAULT="${LDFLAGS_DEBUG}" if test "$tcl_ok" = "yes"; then echo "$as_me:$LINENO: result: yes (standard debugging)" >&5 echo "${ECHO_T}yes (standard debugging)" >&6 fi fi if test "${TEA_PLATFORM}" != "windows" ; then LDFLAGS_DEFAULT="${LDFLAGS}" fi if test "$tcl_ok" = "mem" -o "$tcl_ok" = "all"; then cat >>confdefs.h <<\_ACEOF #define TCL_MEM_DEBUG 1 _ACEOF fi if test "$tcl_ok" != "yes" -a "$tcl_ok" != "no"; then if test "$tcl_ok" = "all"; then echo "$as_me:$LINENO: result: enabled symbols mem debugging" >&5 echo "${ECHO_T}enabled symbols mem debugging" >&6 else echo "$as_me:$LINENO: result: enabled $tcl_ok debugging" >&5 echo "${ECHO_T}enabled $tcl_ok debugging" >&6 fi fi #-------------------------------------------------------------------- # Everyone should be linking against the Tcl stub library. If you # can't for some reason, remove this definition. If you aren't using # stubs, you also need to modify the SHLIB_LD_LIBS setting below to # link against the non-stubbed Tcl library. Add Tk too if necessary. #-------------------------------------------------------------------- cat >>confdefs.h <<\_ACEOF #define USE_TCL_STUBS 1 _ACEOF cat >>confdefs.h <<\_ACEOF #define USE_TK_STUBS 1 _ACEOF #-------------------------------------------------------------------- # This macro generates a line to use when building a library. It # depends on values set by the TEA_ENABLE_SHARED, TEA_ENABLE_SYMBOLS, # and TEA_LOAD_TCLCONFIG macros above. #-------------------------------------------------------------------- if test "${TEA_PLATFORM}" = "windows" -a "$GCC" != "yes"; then MAKE_STATIC_LIB="\${STLIB_LD} -out:\$@ \$(PKG_OBJECTS)" MAKE_SHARED_LIB="\${SHLIB_LD} \${SHLIB_LD_LIBS} \${LDFLAGS_DEFAULT} -out:\$@ \$(PKG_OBJECTS)" MAKE_STUB_LIB="\${STLIB_LD} -out:\$@ \$(PKG_STUB_OBJECTS)" else MAKE_STATIC_LIB="\${STLIB_LD} \$@ \$(PKG_OBJECTS)" MAKE_SHARED_LIB="\${SHLIB_LD} -o \$@ \$(PKG_OBJECTS) \${SHLIB_LD_LIBS}" MAKE_STUB_LIB="\${STLIB_LD} \$@ \$(PKG_STUB_OBJECTS)" fi if test "${SHARED_BUILD}" = "1" ; then MAKE_LIB="${MAKE_SHARED_LIB} " else MAKE_LIB="${MAKE_STATIC_LIB} " fi #-------------------------------------------------------------------- # Shared libraries and static libraries have different names. # Use the double eval to make sure any variables in the suffix is # substituted. (@@@ Might not be necessary anymore) #-------------------------------------------------------------------- if test "${TEA_PLATFORM}" = "windows" ; then if test "${SHARED_BUILD}" = "1" ; then # We force the unresolved linking of symbols that are really in # the private libraries of Tcl and Tk. SHLIB_LD_LIBS="${SHLIB_LD_LIBS} \"`${CYGPATH} ${TCL_BIN_DIR}/${TCL_STUB_LIB_FILE}`\"" if test x"${TK_BIN_DIR}" != x ; then SHLIB_LD_LIBS="${SHLIB_LD_LIBS} \"`${CYGPATH} ${TK_BIN_DIR}/${TK_STUB_LIB_FILE}`\"" fi eval eval "PKG_LIB_FILE=${PACKAGE_NAME}${SHARED_LIB_SUFFIX}" else eval eval "PKG_LIB_FILE=${PACKAGE_NAME}${UNSHARED_LIB_SUFFIX}" fi # Some packages build their own stubs libraries eval eval "PKG_STUB_LIB_FILE=${PACKAGE_NAME}stub${UNSHARED_LIB_SUFFIX}" # These aren't needed on Windows (either MSVC or gcc) RANLIB=: RANLIB_STUB=: else RANLIB_STUB="${RANLIB}" if test "${SHARED_BUILD}" = "1" ; then SHLIB_LD_LIBS="${SHLIB_LD_LIBS} ${TCL_STUB_LIB_SPEC}" if test x"${TK_BIN_DIR}" != x ; then SHLIB_LD_LIBS="${SHLIB_LD_LIBS} ${TK_STUB_LIB_SPEC}" fi eval eval "PKG_LIB_FILE=lib${PACKAGE_NAME}${SHARED_LIB_SUFFIX}" RANLIB=: else eval eval "PKG_LIB_FILE=lib${PACKAGE_NAME}${UNSHARED_LIB_SUFFIX}" fi # Some packages build their own stubs libraries eval eval "PKG_STUB_LIB_FILE=lib${PACKAGE_NAME}stub${UNSHARED_LIB_SUFFIX}" fi # These are escaped so that only CFLAGS is picked up at configure time. # The other values will be substituted at make time. CFLAGS="${CFLAGS} \${CFLAGS_DEFAULT} \${CFLAGS_WARNING}" if test "${SHARED_BUILD}" = "1" ; then CFLAGS="${CFLAGS} \${SHLIB_CFLAGS}" fi #-------------------------------------------------------------------- # Determine the name of the tclsh and/or wish executables in the # Tcl and Tk build directories or the location they were installed # into. These paths are used to support running test cases only, # the Makefile should not be making use of these paths to generate # a pkgIndex.tcl file or anything else at extension build time. #-------------------------------------------------------------------- echo "$as_me:$LINENO: checking for tclsh" >&5 echo $ECHO_N "checking for tclsh... $ECHO_C" >&6 if test -f "${TCL_BIN_DIR}/Makefile" ; then # tclConfig.sh is in Tcl build directory if test "${TEA_PLATFORM}" = "windows"; then TCLSH_PROG="${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}${TCL_DBGX}${EXEEXT}" else TCLSH_PROG="${TCL_BIN_DIR}/tclsh" fi else # tclConfig.sh is in install location if test "${TEA_PLATFORM}" = "windows"; then TCLSH_PROG="tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}${TCL_DBGX}${EXEEXT}" else TCLSH_PROG="tclsh${TCL_MAJOR_VERSION}.${TCL_MINOR_VERSION}${TCL_DBGX}" fi list="`ls -d ${TCL_BIN_DIR}/../bin 2>/dev/null` \ `ls -d ${TCL_BIN_DIR}/.. 2>/dev/null` \ `ls -d ${TCL_PREFIX}/bin 2>/dev/null`" for i in $list ; do if test -f "$i/${TCLSH_PROG}" ; then REAL_TCL_BIN_DIR="`cd "$i"; pwd`" break fi done TCLSH_PROG="${REAL_TCL_BIN_DIR}/${TCLSH_PROG}" fi echo "$as_me:$LINENO: result: ${TCLSH_PROG}" >&5 echo "${ECHO_T}${TCLSH_PROG}" >&6 echo "$as_me:$LINENO: checking for wish" >&5 echo $ECHO_N "checking for wish... $ECHO_C" >&6 if test -f "${TK_BIN_DIR}/Makefile" ; then # tkConfig.sh is in Tk build directory if test "${TEA_PLATFORM}" = "windows"; then WISH_PROG="${TK_BIN_DIR}/wish${TK_MAJOR_VERSION}${TK_MINOR_VERSION}${TK_DBGX}${EXEEXT}" else WISH_PROG="${TK_BIN_DIR}/wish" fi else # tkConfig.sh is in install location if test "${TEA_PLATFORM}" = "windows"; then WISH_PROG="wish${TK_MAJOR_VERSION}${TK_MINOR_VERSION}${TK_DBGX}${EXEEXT}" else WISH_PROG="wish${TK_MAJOR_VERSION}.${TK_MINOR_VERSION}${TK_DBGX}" fi list="`ls -d ${TK_BIN_DIR}/../bin 2>/dev/null` \ `ls -d ${TK_BIN_DIR}/.. 2>/dev/null` \ `ls -d ${TK_PREFIX}/bin 2>/dev/null`" for i in $list ; do if test -f "$i/${WISH_PROG}" ; then REAL_TK_BIN_DIR="`cd "$i"; pwd`" break fi done WISH_PROG="${REAL_TK_BIN_DIR}/${WISH_PROG}" fi echo "$as_me:$LINENO: result: ${WISH_PROG}" >&5 echo "${ECHO_T}${WISH_PROG}" >&6 #-------------------------------------------------------------------- # Finally, substitute all of the various values into the Makefile. # You may alternatively have a special pkgIndex.tcl.in or other files # which require substituting th AC variables in. Include these here. #-------------------------------------------------------------------- ac_config_files="$ac_config_files Makefile" cat >confcache <<\_ACEOF # This file is a shell script that caches the results of configure # tests run on this system so they can be shared between configure # scripts and configure runs, see configure's option --config-cache. # It is not useful on other systems. If it contains results you don't # want to keep, you may remove or edit it. # # config.status only pays attention to the cache file if you give it # the --recheck option to rerun configure. # # `ac_cv_env_foo' variables (set or unset) will be overridden when # loading this file, other *unset* `ac_cv_foo' will be assigned the # following values. _ACEOF # The following way of writing the cache mishandles newlines in values, # but we know of no workaround that is simple, portable, and efficient. # So, don't put newlines in cache variables' values. # Ultrix sh set writes to stderr and can't be redirected directly, # and sets the high bit in the cache file unless we assign to the vars. { (set) 2>&1 | case `(ac_space=' '; set | grep ac_space) 2>&1` in *ac_space=\ *) # `set' does not quote correctly, so add quotes (double-quote # substitution turns \\\\ into \\, and sed turns \\ into \). sed -n \ "s/'/'\\\\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" ;; *) # `set' quotes correctly as required by POSIX, so do not add quotes. sed -n \ "s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1=\\2/p" ;; esac; } | sed ' t clear : clear s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ t end /^ac_cv_env/!s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ : end' >>confcache if diff $cache_file confcache >/dev/null 2>&1; then :; else if test -w $cache_file; then test "x$cache_file" != "x/dev/null" && echo "updating cache $cache_file" cat confcache >$cache_file else echo "not updating unwritable cache $cache_file" fi fi rm -f confcache test "x$prefix" = xNONE && prefix=$ac_default_prefix # Let make expand exec_prefix. test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' # VPATH may cause trouble with some makes, so we remove $(srcdir), # ${srcdir} and @srcdir@ from VPATH if srcdir is ".", strip leading and # trailing colons and then remove the whole line if VPATH becomes empty # (actually we leave an empty line to preserve line numbers). if test "x$srcdir" = x.; then ac_vpsub='/^[ ]*VPATH[ ]*=/{ s/:*\$(srcdir):*/:/; s/:*\${srcdir}:*/:/; s/:*@srcdir@:*/:/; s/^\([^=]*=[ ]*\):*/\1/; s/:*$//; s/^[^=]*=[ ]*$//; }' fi # Transform confdefs.h into DEFS. # Protect against shell expansion while executing Makefile rules. # Protect against Makefile macro expansion. # # If the first sed substitution is executed (which looks for macros that # take arguments), then we branch to the quote section. Otherwise, # look for a macro that doesn't take arguments. cat >confdef2opt.sed <<\_ACEOF t clear : clear s,^[ ]*#[ ]*define[ ][ ]*\([^ (][^ (]*([^)]*)\)[ ]*\(.*\),-D\1=\2,g t quote s,^[ ]*#[ ]*define[ ][ ]*\([^ ][^ ]*\)[ ]*\(.*\),-D\1=\2,g t quote d : quote s,[ `~#$^&*(){}\\|;'"<>?],\\&,g s,\[,\\&,g s,\],\\&,g s,\$,$$,g p _ACEOF # We use echo to avoid assuming a particular line-breaking character. # The extra dot is to prevent the shell from consuming trailing # line-breaks from the sub-command output. A line-break within # single-quotes doesn't work because, if this script is created in a # platform that uses two characters for line-breaks (e.g., DOS), tr # would break. ac_LF_and_DOT=`echo; echo .` DEFS=`sed -n -f confdef2opt.sed confdefs.h | tr "$ac_LF_and_DOT" ' .'` rm -f confdef2opt.sed ac_libobjs= ac_ltlibobjs= for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue # 1. Remove the extension, and $U if already installed. ac_i=`echo "$ac_i" | sed 's/\$U\././;s/\.o$//;s/\.obj$//'` # 2. Add them. ac_libobjs="$ac_libobjs $ac_i\$U.$ac_objext" ac_ltlibobjs="$ac_ltlibobjs $ac_i"'$U.lo' done LIBOBJS=$ac_libobjs LTLIBOBJS=$ac_ltlibobjs : ${CONFIG_STATUS=./config.status} ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files $CONFIG_STATUS" { echo "$as_me:$LINENO: creating $CONFIG_STATUS" >&5 echo "$as_me: creating $CONFIG_STATUS" >&6;} cat >$CONFIG_STATUS <<_ACEOF #! $SHELL # Generated by $as_me. # Run this file to recreate the current configuration. # Compiler output produced by configure, useful for debugging # configure, is in config.log if it exists. debug=false ac_cs_recheck=false ac_cs_silent=false SHELL=\${CONFIG_SHELL-$SHELL} _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF ## --------------------- ## ## M4sh Initialization. ## ## --------------------- ## # 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+"$@"}'='"$@"' elif test -n "${BASH_VERSION+set}" && (set -o posix) >/dev/null 2>&1; then set -o posix fi DUALCASE=1; export DUALCASE # for MKS sh # Support unset when possible. if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then as_unset=unset else as_unset=false fi # Work around bugs in pre-3.0 UWIN ksh. $as_unset ENV MAIL MAILPATH PS1='$ ' PS2='> ' PS4='+ ' # NLS nuisances. for as_var in \ LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION \ LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \ LC_TELEPHONE LC_TIME do if (set +x; test -z "`(eval $as_var=C; export $as_var) 2>&1`"); then eval $as_var=C; export $as_var else $as_unset $as_var fi done # Required to use basename. if expr a : '\(a\)' >/dev/null 2>&1; then as_expr=expr else as_expr=false fi if (basename /) >/dev/null 2>&1 && test "X`basename / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi # Name of the executable. as_me=`$as_basename "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)$' \| \ . : '\(.\)' 2>/dev/null || echo X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/; q; } /^X\/\(\/\/\)$/{ s//\1/; q; } /^X\/\(\/\).*/{ s//\1/; q; } s/.*/./; q'` # PATH needs CR, and LINENO needs CR and PATH. # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then echo "#! /bin/sh" >conf$$.sh echo "exit 0" >>conf$$.sh chmod +x conf$$.sh if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then PATH_SEPARATOR=';' else PATH_SEPARATOR=: fi rm -f conf$$.sh fi as_lineno_1=$LINENO as_lineno_2=$LINENO as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null` test "x$as_lineno_1" != "x$as_lineno_2" && test "x$as_lineno_3" = "x$as_lineno_2" || { # Find who we are. Look in the path if we contain no path at all # relative or not. case $0 in *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break done ;; esac # We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then { { echo "$as_me:$LINENO: error: cannot find myself; rerun with an absolute path" >&5 echo "$as_me: error: cannot find myself; rerun with an absolute path" >&2;} { (exit 1); exit 1; }; } fi case $CONFIG_SHELL in '') as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for as_base in sh bash ksh sh5; do case $as_dir in /*) if ("$as_dir/$as_base" -c ' as_lineno_1=$LINENO as_lineno_2=$LINENO as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null` test "x$as_lineno_1" != "x$as_lineno_2" && test "x$as_lineno_3" = "x$as_lineno_2" ') 2>/dev/null; then $as_unset BASH_ENV || test "${BASH_ENV+set}" != set || { BASH_ENV=; export BASH_ENV; } $as_unset ENV || test "${ENV+set}" != set || { ENV=; export ENV; } CONFIG_SHELL=$as_dir/$as_base export CONFIG_SHELL exec "$CONFIG_SHELL" "$0" ${1+"$@"} fi;; esac done done ;; esac # Create $as_me.lineno as a copy of $as_myself, but with $LINENO # uniformly replaced by the line number. The first 'sed' inserts a # line-number line before each line; the second 'sed' does the real # work. The second script uses 'N' to pair each line-number line # with the numbered line, and appends trailing '-' during # substitution so that $LINENO is not a special case at line end. # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the # second 'sed' script. Blame Lee E. McMahon for sed's syntax. :-) sed '=' <$as_myself | sed ' N s,$,-, : loop s,^\(['$as_cr_digits']*\)\(.*\)[$]LINENO\([^'$as_cr_alnum'_]\),\1\2\1\3, t loop s,-$,, s,^['$as_cr_digits']*\n,, ' >$as_me.lineno && chmod +x $as_me.lineno || { { echo "$as_me:$LINENO: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&5 echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2;} { (exit 1); exit 1; }; } # Don't try to exec as it changes $[0], causing all sort of problems # (the dirname of $[0] is not the place where we might find the # original and so on. Autoconf is especially sensible to this). . ./$as_me.lineno # Exit status is that of the last command. exit } case `echo "testing\c"; echo 1,2,3`,`echo -n testing; echo 1,2,3` in *c*,-n*) ECHO_N= ECHO_C=' ' ECHO_T=' ' ;; *c*,* ) ECHO_N=-n ECHO_C= ECHO_T= ;; *) ECHO_N= ECHO_C='\c' ECHO_T= ;; esac if expr a : '\(a\)' >/dev/null 2>&1; then as_expr=expr else as_expr=false fi rm -f conf$$ conf$$.exe conf$$.file echo >conf$$.file if ln -s conf$$.file conf$$ 2>/dev/null; then # We could just check for DJGPP; but this test a) works b) is more generic # and c) will remain valid once DJGPP supports symlinks (DJGPP 2.04). if test -f conf$$.exe; then # Don't use ln at all; we don't have any links as_ln_s='cp -p' else as_ln_s='ln -s' fi elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -p' fi rm -f conf$$ conf$$.exe conf$$.file if mkdir -p . 2>/dev/null; then as_mkdir_p=: else test -d ./-p && rmdir ./-p as_mkdir_p=false fi as_executable_p="test -f" # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" # IFS # We need space, tab and new line, in precisely that order. as_nl=' ' IFS=" $as_nl" # CDPATH. $as_unset CDPATH exec 6>&1 # Open the log real soon, to keep \$[0] and so on meaningful, and to # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. Logging --version etc. is OK. exec 5>>config.log { echo sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX ## Running $as_me. ## _ASBOX } >&5 cat >&5 <<_CSEOF This file was extended by Tkhtml $as_me 3.0, which was generated by GNU Autoconf 2.59. Invocation command line was CONFIG_FILES = $CONFIG_FILES CONFIG_HEADERS = $CONFIG_HEADERS CONFIG_LINKS = $CONFIG_LINKS CONFIG_COMMANDS = $CONFIG_COMMANDS $ $0 $@ _CSEOF echo "on `(hostname || uname -n) 2>/dev/null | sed 1q`" >&5 echo >&5 _ACEOF # Files that config.status was made for. if test -n "$ac_config_files"; then echo "config_files=\"$ac_config_files\"" >>$CONFIG_STATUS fi if test -n "$ac_config_headers"; then echo "config_headers=\"$ac_config_headers\"" >>$CONFIG_STATUS fi if test -n "$ac_config_links"; then echo "config_links=\"$ac_config_links\"" >>$CONFIG_STATUS fi if test -n "$ac_config_commands"; then echo "config_commands=\"$ac_config_commands\"" >>$CONFIG_STATUS fi cat >>$CONFIG_STATUS <<\_ACEOF ac_cs_usage="\ \`$as_me' instantiates files from templates according to the current configuration. Usage: $0 [OPTIONS] [FILE]... -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 --recheck update $as_me by reconfiguring in the same conditions --file=FILE[:TEMPLATE] instantiate the configuration file FILE Configuration files: $config_files Report bugs to ." _ACEOF cat >>$CONFIG_STATUS <<_ACEOF ac_cs_version="\\ Tkhtml config.status 3.0 configured by $0, generated by GNU Autoconf 2.59, with options \\"`echo "$ac_configure_args" | sed 's/[\\""\`\$]/\\\\&/g'`\\" Copyright (C) 2003 Free Software Foundation, Inc. This config.status script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it." srcdir=$srcdir INSTALL="$INSTALL" _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF # If no file are specified by the user, then we need to provide default # value. By we need to know if files were specified by the user. ac_need_defaults=: while test $# != 0 do case $1 in --*=*) ac_option=`expr "x$1" : 'x\([^=]*\)='` ac_optarg=`expr "x$1" : 'x[^=]*=\(.*\)'` ac_shift=: ;; -*) ac_option=$1 ac_optarg=$2 ac_shift=shift ;; *) # This is not an option, so the user has probably given explicit # arguments. ac_option=$1 ac_need_defaults=false;; esac case $ac_option in # Handling of the options. _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) ac_cs_recheck=: ;; --version | --vers* | -V ) echo "$ac_cs_version"; exit 0 ;; --he | --h) # Conflict between --help and --header { { echo "$as_me:$LINENO: error: ambiguous option: $1 Try \`$0 --help' for more information." >&5 echo "$as_me: error: ambiguous option: $1 Try \`$0 --help' for more information." >&2;} { (exit 1); exit 1; }; };; --help | --hel | -h ) echo "$ac_cs_usage"; exit 0 ;; --debug | --d* | -d ) debug=: ;; --file | --fil | --fi | --f ) $ac_shift CONFIG_FILES="$CONFIG_FILES $ac_optarg" ac_need_defaults=false;; --header | --heade | --head | --hea ) $ac_shift CONFIG_HEADERS="$CONFIG_HEADERS $ac_optarg" ac_need_defaults=false;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil | --si | --s) ac_cs_silent=: ;; # This is an error. -*) { { echo "$as_me:$LINENO: error: unrecognized option: $1 Try \`$0 --help' for more information." >&5 echo "$as_me: error: unrecognized option: $1 Try \`$0 --help' for more information." >&2;} { (exit 1); exit 1; }; } ;; *) ac_config_targets="$ac_config_targets $1" ;; esac shift done ac_configure_extra_args= if $ac_cs_silent; then exec 6>/dev/null ac_configure_extra_args="$ac_configure_extra_args --silent" fi _ACEOF cat >>$CONFIG_STATUS <<_ACEOF if \$ac_cs_recheck; then echo "running $SHELL $0 " $ac_configure_args \$ac_configure_extra_args " --no-create --no-recursion" >&6 exec $SHELL $0 $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion fi _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF for ac_config_target in $ac_config_targets do case "$ac_config_target" in # Handling of arguments. "Makefile" ) CONFIG_FILES="$CONFIG_FILES Makefile" ;; *) { { echo "$as_me:$LINENO: error: invalid argument: $ac_config_target" >&5 echo "$as_me: error: invalid argument: $ac_config_target" >&2;} { (exit 1); exit 1; }; };; esac done # If the user did not use the arguments to specify the items to instantiate, # then the envvar interface is used. Set only those that are not. # We use the long form for the default assignment because of an extremely # bizarre bug on SunOS 4.1.3. if $ac_need_defaults; then test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files fi # Have a temporary directory for convenience. Make it in the build tree # simply because there is no reason to put it here, and in addition, # creating and moving files from /tmp can sometimes cause problems. # Create a temporary directory, and hook for its removal unless debugging. $debug || { trap 'exit_status=$?; rm -rf $tmp && exit $exit_status' 0 trap '{ (exit 1); exit 1; }' 1 2 13 15 } # Create a (secure) tmp directory for tmp files. { tmp=`(umask 077 && mktemp -d -q "./confstatXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" } || { tmp=./confstat$$-$RANDOM (umask 077 && mkdir $tmp) } || { echo "$me: cannot create a temporary directory in ." >&2 { (exit 1); exit 1; } } _ACEOF cat >>$CONFIG_STATUS <<_ACEOF # # CONFIG_FILES section. # # No need to generate the scripts if there are no CONFIG_FILES. # This happens for instance when ./config.status config.h if test -n "\$CONFIG_FILES"; then # Protect against being on the right side of a sed subst in config.status. sed 's/,@/@@/; s/@,/@@/; s/,;t t\$/@;t t/; /@;t t\$/s/[\\\\&,]/\\\\&/g; s/@@/,@/; s/@@/@,/; s/@;t t\$/,;t t/' >\$tmp/subs.sed <<\\CEOF s,@SHELL@,$SHELL,;t t s,@PATH_SEPARATOR@,$PATH_SEPARATOR,;t t s,@PACKAGE_NAME@,$PACKAGE_NAME,;t t s,@PACKAGE_TARNAME@,$PACKAGE_TARNAME,;t t s,@PACKAGE_VERSION@,$PACKAGE_VERSION,;t t s,@PACKAGE_STRING@,$PACKAGE_STRING,;t t s,@PACKAGE_BUGREPORT@,$PACKAGE_BUGREPORT,;t t s,@exec_prefix@,$exec_prefix,;t t s,@prefix@,$prefix,;t t s,@program_transform_name@,$program_transform_name,;t t s,@bindir@,$bindir,;t t s,@sbindir@,$sbindir,;t t s,@libexecdir@,$libexecdir,;t t s,@datadir@,$datadir,;t t s,@sysconfdir@,$sysconfdir,;t t s,@sharedstatedir@,$sharedstatedir,;t t s,@localstatedir@,$localstatedir,;t t s,@libdir@,$libdir,;t t s,@includedir@,$includedir,;t t s,@oldincludedir@,$oldincludedir,;t t s,@infodir@,$infodir,;t t s,@mandir@,$mandir,;t t s,@build_alias@,$build_alias,;t t s,@host_alias@,$host_alias,;t t s,@target_alias@,$target_alias,;t t s,@DEFS@,$DEFS,;t t s,@ECHO_C@,$ECHO_C,;t t s,@ECHO_N@,$ECHO_N,;t t s,@ECHO_T@,$ECHO_T,;t t s,@LIBS@,$LIBS,;t t s,@CYGPATH@,$CYGPATH,;t t s,@EXEEXT@,$EXEEXT,;t t s,@PKG_LIB_FILE@,$PKG_LIB_FILE,;t t s,@PKG_STUB_LIB_FILE@,$PKG_STUB_LIB_FILE,;t t s,@PKG_STUB_SOURCES@,$PKG_STUB_SOURCES,;t t s,@PKG_STUB_OBJECTS@,$PKG_STUB_OBJECTS,;t t s,@PKG_TCL_SOURCES@,$PKG_TCL_SOURCES,;t t s,@PKG_HEADERS@,$PKG_HEADERS,;t t s,@PKG_INCLUDES@,$PKG_INCLUDES,;t t s,@PKG_LIBS@,$PKG_LIBS,;t t s,@PKG_CFLAGS@,$PKG_CFLAGS,;t t s,@TCL_VERSION@,$TCL_VERSION,;t t s,@TCL_BIN_DIR@,$TCL_BIN_DIR,;t t s,@TCL_SRC_DIR@,$TCL_SRC_DIR,;t t s,@TCL_LIB_FILE@,$TCL_LIB_FILE,;t t s,@TCL_LIB_FLAG@,$TCL_LIB_FLAG,;t t s,@TCL_LIB_SPEC@,$TCL_LIB_SPEC,;t t s,@TCL_STUB_LIB_FILE@,$TCL_STUB_LIB_FILE,;t t s,@TCL_STUB_LIB_FLAG@,$TCL_STUB_LIB_FLAG,;t t s,@TCL_STUB_LIB_SPEC@,$TCL_STUB_LIB_SPEC,;t t s,@TCL_LIBS@,$TCL_LIBS,;t t s,@TCL_DEFS@,$TCL_DEFS,;t t s,@TCL_EXTRA_CFLAGS@,$TCL_EXTRA_CFLAGS,;t t s,@TCL_LD_FLAGS@,$TCL_LD_FLAGS,;t t s,@TCL_SHLIB_LD_LIBS@,$TCL_SHLIB_LD_LIBS,;t t s,@TK_VERSION@,$TK_VERSION,;t t s,@TK_BIN_DIR@,$TK_BIN_DIR,;t t s,@TK_SRC_DIR@,$TK_SRC_DIR,;t t s,@TK_LIB_FILE@,$TK_LIB_FILE,;t t s,@TK_LIB_FLAG@,$TK_LIB_FLAG,;t t s,@TK_LIB_SPEC@,$TK_LIB_SPEC,;t t s,@TK_STUB_LIB_FILE@,$TK_STUB_LIB_FILE,;t t s,@TK_STUB_LIB_FLAG@,$TK_STUB_LIB_FLAG,;t t s,@TK_STUB_LIB_SPEC@,$TK_STUB_LIB_SPEC,;t t s,@TK_LIBS@,$TK_LIBS,;t t s,@TK_XINCLUDES@,$TK_XINCLUDES,;t t s,@CC@,$CC,;t t s,@CFLAGS@,$CFLAGS,;t t s,@LDFLAGS@,$LDFLAGS,;t t s,@CPPFLAGS@,$CPPFLAGS,;t t s,@ac_ct_CC@,$ac_ct_CC,;t t s,@OBJEXT@,$OBJEXT,;t t s,@CPP@,$CPP,;t t s,@INSTALL_PROGRAM@,$INSTALL_PROGRAM,;t t s,@INSTALL_SCRIPT@,$INSTALL_SCRIPT,;t t s,@INSTALL_DATA@,$INSTALL_DATA,;t t s,@SET_MAKE@,$SET_MAKE,;t t s,@RANLIB@,$RANLIB,;t t s,@ac_ct_RANLIB@,$ac_ct_RANLIB,;t t s,@EGREP@,$EGREP,;t t s,@MATH_LIBS@,$MATH_LIBS,;t t s,@PKG_SOURCES@,$PKG_SOURCES,;t t s,@PKG_OBJECTS@,$PKG_OBJECTS,;t t s,@CLEANFILES@,$CLEANFILES,;t t s,@TCL_INCLUDES@,$TCL_INCLUDES,;t t s,@TK_INCLUDES@,$TK_INCLUDES,;t t s,@TCL_THREADS@,$TCL_THREADS,;t t s,@SHARED_BUILD@,$SHARED_BUILD,;t t s,@AR@,$AR,;t t s,@CELIB_DIR@,$CELIB_DIR,;t t s,@LIBOBJS@,$LIBOBJS,;t t s,@DL_LIBS@,$DL_LIBS,;t t s,@CFLAGS_DEBUG@,$CFLAGS_DEBUG,;t t s,@CFLAGS_OPTIMIZE@,$CFLAGS_OPTIMIZE,;t t s,@CFLAGS_WARNING@,$CFLAGS_WARNING,;t t s,@STLIB_LD@,$STLIB_LD,;t t s,@SHLIB_LD@,$SHLIB_LD,;t t s,@SHLIB_LD_LIBS@,$SHLIB_LD_LIBS,;t t s,@SHLIB_CFLAGS@,$SHLIB_CFLAGS,;t t s,@LD_LIBRARY_PATH_VAR@,$LD_LIBRARY_PATH_VAR,;t t s,@TCL_DBGX@,$TCL_DBGX,;t t s,@CFLAGS_DEFAULT@,$CFLAGS_DEFAULT,;t t s,@LDFLAGS_DEFAULT@,$LDFLAGS_DEFAULT,;t t s,@MAKE_LIB@,$MAKE_LIB,;t t s,@MAKE_SHARED_LIB@,$MAKE_SHARED_LIB,;t t s,@MAKE_STATIC_LIB@,$MAKE_STATIC_LIB,;t t s,@MAKE_STUB_LIB@,$MAKE_STUB_LIB,;t t s,@RANLIB_STUB@,$RANLIB_STUB,;t t s,@TCLSH_PROG@,$TCLSH_PROG,;t t s,@WISH_PROG@,$WISH_PROG,;t t s,@LTLIBOBJS@,$LTLIBOBJS,;t t CEOF _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF # Split the substitutions into bite-sized pieces for seds with # small command number limits, like on Digital OSF/1 and HP-UX. ac_max_sed_lines=48 ac_sed_frag=1 # Number of current file. ac_beg=1 # First line for current file. ac_end=$ac_max_sed_lines # Line after last line for current file. ac_more_lines=: ac_sed_cmds= while $ac_more_lines; do if test $ac_beg -gt 1; then sed "1,${ac_beg}d; ${ac_end}q" $tmp/subs.sed >$tmp/subs.frag else sed "${ac_end}q" $tmp/subs.sed >$tmp/subs.frag fi if test ! -s $tmp/subs.frag; then ac_more_lines=false else # The purpose of the label and of the branching condition is to # speed up the sed processing (if there are no `@' at all, there # is no need to browse any of the substitutions). # These are the two extra sed commands mentioned above. (echo ':t /@[a-zA-Z_][a-zA-Z_0-9]*@/!b' && cat $tmp/subs.frag) >$tmp/subs-$ac_sed_frag.sed if test -z "$ac_sed_cmds"; then ac_sed_cmds="sed -f $tmp/subs-$ac_sed_frag.sed" else ac_sed_cmds="$ac_sed_cmds | sed -f $tmp/subs-$ac_sed_frag.sed" fi ac_sed_frag=`expr $ac_sed_frag + 1` ac_beg=$ac_end ac_end=`expr $ac_end + $ac_max_sed_lines` fi done if test -z "$ac_sed_cmds"; then ac_sed_cmds=cat fi fi # test -n "$CONFIG_FILES" _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF for ac_file in : $CONFIG_FILES; do test "x$ac_file" = x: && continue # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in". case $ac_file in - | *:- | *:-:* ) # input from stdin cat >$tmp/stdin ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'` ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;; *:* ) ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'` ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;; * ) ac_file_in=$ac_file.in ;; esac # Compute @srcdir@, @top_srcdir@, and @INSTALL@ for subdirectories. ac_dir=`(dirname "$ac_file") 2>/dev/null || $as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$ac_file" : 'X\(//\)[^/]' \| \ X"$ac_file" : 'X\(//\)$' \| \ X"$ac_file" : 'X\(/\)' \| \ . : '\(.\)' 2>/dev/null || echo X"$ac_file" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } /^X\(\/\/\)[^/].*/{ s//\1/; q; } /^X\(\/\/\)$/{ s//\1/; q; } /^X\(\/\).*/{ s//\1/; q; } s/.*/./; q'` { if $as_mkdir_p; then mkdir -p "$ac_dir" else as_dir="$ac_dir" as_dirs= while test ! -d "$as_dir"; do as_dirs="$as_dir $as_dirs" as_dir=`(dirname "$as_dir") 2>/dev/null || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| \ . : '\(.\)' 2>/dev/null || echo X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } /^X\(\/\/\)[^/].*/{ s//\1/; q; } /^X\(\/\/\)$/{ s//\1/; q; } /^X\(\/\).*/{ s//\1/; q; } s/.*/./; q'` done test ! -n "$as_dirs" || mkdir $as_dirs fi || { { echo "$as_me:$LINENO: error: cannot create directory \"$ac_dir\"" >&5 echo "$as_me: error: cannot create directory \"$ac_dir\"" >&2;} { (exit 1); exit 1; }; }; } ac_builddir=. if test "$ac_dir" != .; then ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'` # A "../" for each directory in $ac_dir_suffix. ac_top_builddir=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,../,g'` else ac_dir_suffix= ac_top_builddir= fi case $srcdir in .) # No --srcdir option. We are building in place. ac_srcdir=. if test -z "$ac_top_builddir"; then ac_top_srcdir=. else ac_top_srcdir=`echo $ac_top_builddir | sed 's,/$,,'` fi ;; [\\/]* | ?:[\\/]* ) # Absolute path. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ;; *) # Relative path. ac_srcdir=$ac_top_builddir$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_builddir$srcdir ;; esac # Do not use `cd foo && pwd` to compute absolute paths, because # the directories may not exist. case `pwd` in .) ac_abs_builddir="$ac_dir";; *) case "$ac_dir" in .) ac_abs_builddir=`pwd`;; [\\/]* | ?:[\\/]* ) ac_abs_builddir="$ac_dir";; *) ac_abs_builddir=`pwd`/"$ac_dir";; esac;; esac case $ac_abs_builddir in .) ac_abs_top_builddir=${ac_top_builddir}.;; *) case ${ac_top_builddir}. in .) ac_abs_top_builddir=$ac_abs_builddir;; [\\/]* | ?:[\\/]* ) ac_abs_top_builddir=${ac_top_builddir}.;; *) ac_abs_top_builddir=$ac_abs_builddir/${ac_top_builddir}.;; esac;; esac case $ac_abs_builddir in .) ac_abs_srcdir=$ac_srcdir;; *) case $ac_srcdir in .) ac_abs_srcdir=$ac_abs_builddir;; [\\/]* | ?:[\\/]* ) ac_abs_srcdir=$ac_srcdir;; *) ac_abs_srcdir=$ac_abs_builddir/$ac_srcdir;; esac;; esac case $ac_abs_builddir in .) ac_abs_top_srcdir=$ac_top_srcdir;; *) case $ac_top_srcdir in .) ac_abs_top_srcdir=$ac_abs_builddir;; [\\/]* | ?:[\\/]* ) ac_abs_top_srcdir=$ac_top_srcdir;; *) ac_abs_top_srcdir=$ac_abs_builddir/$ac_top_srcdir;; esac;; esac case $INSTALL in [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;; *) ac_INSTALL=$ac_top_builddir$INSTALL ;; esac if test x"$ac_file" != x-; then { echo "$as_me:$LINENO: creating $ac_file" >&5 echo "$as_me: creating $ac_file" >&6;} rm -f "$ac_file" fi # Let's still pretend it is `configure' which instantiates (i.e., don't # use $as_me), people would be surprised to read: # /* config.h. Generated by config.status. */ if test x"$ac_file" = x-; then configure_input= else configure_input="$ac_file. " fi configure_input=$configure_input"Generated from `echo $ac_file_in | sed 's,.*/,,'` by configure." # First look for the input files in the build tree, otherwise in the # src tree. ac_file_inputs=`IFS=: for f in $ac_file_in; do case $f in -) echo $tmp/stdin ;; [\\/$]*) # Absolute (can't be DOS-style, as IFS=:) test -f "$f" || { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5 echo "$as_me: error: cannot find input file: $f" >&2;} { (exit 1); exit 1; }; } echo "$f";; *) # Relative if test -f "$f"; then # Build tree echo "$f" elif test -f "$srcdir/$f"; then # Source tree echo "$srcdir/$f" else # /dev/null tree { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5 echo "$as_me: error: cannot find input file: $f" >&2;} { (exit 1); exit 1; }; } fi;; esac done` || { (exit 1); exit 1; } _ACEOF cat >>$CONFIG_STATUS <<_ACEOF sed "$ac_vpsub $extrasub _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF :t /@[a-zA-Z_][a-zA-Z_0-9]*@/!b s,@configure_input@,$configure_input,;t t s,@srcdir@,$ac_srcdir,;t t s,@abs_srcdir@,$ac_abs_srcdir,;t t s,@top_srcdir@,$ac_top_srcdir,;t t s,@abs_top_srcdir@,$ac_abs_top_srcdir,;t t s,@builddir@,$ac_builddir,;t t s,@abs_builddir@,$ac_abs_builddir,;t t s,@top_builddir@,$ac_top_builddir,;t t s,@abs_top_builddir@,$ac_abs_top_builddir,;t t s,@INSTALL@,$ac_INSTALL,;t t " $ac_file_inputs | (eval "$ac_sed_cmds") >$tmp/out rm -f $tmp/stdin if test x"$ac_file" != x-; then mv $tmp/out $ac_file else cat $tmp/out rm -f $tmp/out fi done _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF { (exit 0); exit 0; } _ACEOF chmod +x $CONFIG_STATUS ac_clean_files=$ac_clean_files_save # configure is writing to config.log, and then calls config.status. # config.status does its own redirection, appending to config.log. # Unfortunately, on DOS this fails, as config.log is still kept open # by configure, so config.status won't be able to write to it; its # output is simply discarded. So we exec the FD to /dev/null, # effectively closing config.log, so it can be properly (re)opened and # appended to by config.status. When coming back to configure, we # need to make the FD available again. if test "$no_create" != yes; then ac_cs_success=: ac_config_status_args= test "$silent" = yes && ac_config_status_args="$ac_config_status_args --quiet" exec 5>/dev/null $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false exec 5>>config.log # Use ||, not &&, to avoid exiting from the if with $? = 1, which # would make configure fail if this is the last instruction. $ac_cs_success || { (exit 1); exit 1; } fi tkHTML-4ee7aaa953d6cb59/configure.in000064400000000000000000000200711151224263100164260ustar00nobodynobody#!/bin/bash -norc dnl This file is an input file used by the GNU "autoconf" program to dnl generate the file "configure", which is run during Tcl installation dnl to configure the system for the local environment. # # RCS: @(#) $Id: configure.in,v 1.31 2007/10/26 09:31:15 danielk1977 Exp $ #----------------------------------------------------------------------- # Sample configure.in for Tcl Extensions. The only places you should # need to modify this file are marked by the string __CHANGE__ #----------------------------------------------------------------------- #----------------------------------------------------------------------- # __CHANGE__ # Set your package name and version numbers here. # # This initializes the environment with PACKAGE_NAME and PACKAGE_VERSION # set as provided. These will also be added as -D defs in your Makefile # so you can encode the package version directly into the source files. #----------------------------------------------------------------------- AC_INIT([Tkhtml], [3.0]) #-------------------------------------------------------------------- # Call TEA_INIT as the first TEA_ macro to set up initial vars. # This will define a ${TEA_PLATFORM} variable == "unix" or "windows" # as well as PKG_LIB_FILE and PKG_STUB_LIB_FILE. #-------------------------------------------------------------------- TEA_INIT([3.5]) AC_CONFIG_AUX_DIR(tclconfig) #-------------------------------------------------------------------- # Load the tclConfig.sh file #-------------------------------------------------------------------- TEA_PATH_TCLCONFIG TEA_LOAD_TCLCONFIG #-------------------------------------------------------------------- # Load the tkConfig.sh file if necessary (Tk extension) #-------------------------------------------------------------------- TEA_PATH_TKCONFIG TEA_LOAD_TKCONFIG #----------------------------------------------------------------------- # Handle the --prefix=... option by defaulting to what Tcl gave. # Must be called after TEA_LOAD_TCLCONFIG and before TEA_SETUP_COMPILER. #----------------------------------------------------------------------- TEA_PREFIX #----------------------------------------------------------------------- # Standard compiler checks. # This sets up CC by using the CC env var, or looks for gcc otherwise. # This also calls AC_PROG_CC, AC_PROG_INSTALL and a few others to create # the basic setup necessary to compile executables. #----------------------------------------------------------------------- TEA_SETUP_COMPILER #----------------------------------------------------------------------- # __CHANGE__ # Specify the C source files to compile in TEA_ADD_SOURCES, # public headers that need to be installed in TEA_ADD_HEADERS, # stub library C source files to compile in TEA_ADD_STUB_SOURCES, # and runtime Tcl library files in TEA_ADD_TCL_SOURCES. # This defines PKG(_STUB)_SOURCES, PKG(_STUB)_OBJECTS, PKG_HEADERS # and PKG_TCL_SOURCES. #----------------------------------------------------------------------- TEA_ADD_SOURCES([css.c]) TEA_ADD_SOURCES([cssdynamic.c]) TEA_ADD_SOURCES([cssparser.c]) TEA_ADD_SOURCES([csssearch.c]) TEA_ADD_SOURCES([htmldraw.c]) TEA_ADD_SOURCES([htmlfloat.c]) TEA_ADD_SOURCES([htmlhash.c]) TEA_ADD_SOURCES([htmlimage.c]) TEA_ADD_SOURCES([htmlinline.c]) TEA_ADD_SOURCES([htmllayout.c]) TEA_ADD_SOURCES([htmlparse.c]) TEA_ADD_SOURCES([htmlprop.c]) TEA_ADD_SOURCES([htmlstyle.c]) TEA_ADD_SOURCES([htmltagdb.c]) TEA_ADD_SOURCES([htmltable.c]) TEA_ADD_SOURCES([htmltcl.c]) TEA_ADD_SOURCES([htmltree.c]) TEA_ADD_SOURCES([swproc.c]) TEA_ADD_SOURCES([restrack.c]) TEA_ADD_SOURCES([htmldecode.c]) TEA_ADD_SOURCES([htmltext.c]) TEA_ADD_SOURCES([htmlutil.c]) TEA_ADD_HEADERS([]) TEA_ADD_INCLUDES([]) TEA_ADD_LIBS([]) TEA_ADD_CFLAGS([]) TEA_ADD_STUB_SOURCES([]) TEA_ADD_TCL_SOURCES([]) #-------------------------------------------------------------------- # __CHANGE__ # A few miscellaneous platform-specific items: # # Define a special symbol for Windows (BUILD_sample in this case) so # that we create the export library with the dll. # # Windows creates a few extra files that need to be cleaned up. # You can add more files to clean if your extension creates any extra # files. # # TEA_ADD_* any platform specific compiler/build info here. #-------------------------------------------------------------------- if test "${TEA_PLATFORM}" = "windows" ; then AC_DEFINE(BUILD_sample, 1, [Build windows export dll]) CLEANFILES="pkgIndex.tcl *.lib *.dll *.exp *.ilk *.pdb vc*.pch" #TEA_ADD_SOURCES([win/winFile.c]) #TEA_ADD_INCLUDES([-I\"$(${CYGPATH} ${srcdir}/win)\"]) # TEA_ADD_LIBS([-lopengl32 -lglu32 -lgdi32]) else CLEANFILES="pkgIndex.tcl" #TEA_ADD_SOURCES([unix/unixFile.c]) #TEA_ADD_LIBS([-lsuperfly]) # TEA_ADD_LIBS([-lGL -lGLU]) fi AC_SUBST(CLEANFILES) #-------------------------------------------------------------------- # __CHANGE__ # Choose which headers you need. Extension authors should try very # hard to only rely on the Tcl public header files. Internal headers # contain private data structures and are subject to change without # notice. # This MUST be called after TEA_LOAD_TCLCONFIG / TEA_LOAD_TKCONFIG #-------------------------------------------------------------------- TEA_PUBLIC_TCL_HEADERS #TEA_PRIVATE_TCL_HEADERS TEA_PUBLIC_TK_HEADERS #TEA_PRIVATE_TK_HEADERS TEA_PATH_X #-------------------------------------------------------------------- # Check whether --enable-threads or --disable-threads was given. # This auto-enables if Tcl was compiled threaded. #-------------------------------------------------------------------- TEA_ENABLE_THREADS #-------------------------------------------------------------------- # The statement below defines a collection of symbols related to # building as a shared library instead of a static library. #-------------------------------------------------------------------- TEA_ENABLE_SHARED #-------------------------------------------------------------------- # This macro figures out what flags to use with the compiler/linker # when building shared/static debug/optimized objects. This information # can be taken from the tclConfig.sh file, but this figures it all out. #-------------------------------------------------------------------- TEA_CONFIG_CFLAGS #-------------------------------------------------------------------- # Set the default compiler switches based on the --enable-symbols option. #-------------------------------------------------------------------- TEA_ENABLE_SYMBOLS #-------------------------------------------------------------------- # Everyone should be linking against the Tcl stub library. If you # can't for some reason, remove this definition. If you aren't using # stubs, you also need to modify the SHLIB_LD_LIBS setting below to # link against the non-stubbed Tcl library. Add Tk too if necessary. #-------------------------------------------------------------------- AC_DEFINE(USE_TCL_STUBS, 1, [Use Tcl stubs]) AC_DEFINE(USE_TK_STUBS, 1, [Use Tk stubs]) #-------------------------------------------------------------------- # This macro generates a line to use when building a library. It # depends on values set by the TEA_ENABLE_SHARED, TEA_ENABLE_SYMBOLS, # and TEA_LOAD_TCLCONFIG macros above. #-------------------------------------------------------------------- TEA_MAKE_LIB #-------------------------------------------------------------------- # Determine the name of the tclsh and/or wish executables in the # Tcl and Tk build directories or the location they were installed # into. These paths are used to support running test cases only, # the Makefile should not be making use of these paths to generate # a pkgIndex.tcl file or anything else at extension build time. #-------------------------------------------------------------------- TEA_PROG_TCLSH TEA_PROG_WISH #-------------------------------------------------------------------- # Finally, substitute all of the various values into the Makefile. # You may alternatively have a special pkgIndex.tcl.in or other files # which require substituting th AC variables in. Include these here. #-------------------------------------------------------------------- AC_OUTPUT([Makefile]) tkHTML-4ee7aaa953d6cb59/doc000075500000000000000000000000001151224263100146035ustar00nobodynobodytkHTML-4ee7aaa953d6cb59/doc/browser.man000064400000000000000000000015631151224263100170470ustar00nobodynobody[TH ::hv3::browser n] [Section Name] ::hv3::browser - Web browser widget. [Section Synopsis] ::hv3::browser pathName ?options? [Section Standard Options] [Code { }] See the options(n) manual entry for details on the standard options. [Section Widget-Specific Options] [Option enablejavascript { If set to true and the Tclsee package can be loaded, javascript is enabled in the browser widget. The default value is false. }] [Option unsafe { This boolean option determines whether or not the javascript interpreter has access to the function window.tcl(). Because this function allows javascript programs embedded in documents to evaluate Tcl scripts in the widget's intepreter, any document loaded while this option is set should be from a trusted source. The default value is false. }] [Section Description] [Section Widget Command] tkHTML-4ee7aaa953d6cb59/doc/html.man000064400000000000000000001061711151224263100163310ustar00nobodynobody [TH tkhtml n] [Section Name] tkhtml - Widget to render html documents. [Section Synopsis] html pathName ?options? [Section Standard Options] [Code { -height -width -xscrollcommand -xscrollincrement -yscrollcommand -yscrollincrement }] See the options(n) manual entry for details on the standard options. [Section Widget-Specific Options] [Option defaultstyle { This option is used to set the default style-sheet for the widget. The option value should be the entire text of the default style-sheet. The default stylesheet defines things that are "built-in" to the document - for example the behaviour of

or tags in html. The idea behind making it flexible is to allow Tkhtml to display anything that looks roughly like an XML document. But this will not work at the moment because of other assumptions the implementation makes about the set of valid tags. Currently, only valid HTML tags are recognized. The Tkhtml package adds the [SQ ::tkhtml::htmlstyle] command to the interpreter it is loaded into. Invoking this command returns a CSS document suitable for use with Tkhml as a default stylesheet for HTML documents. If the "-quirks" option is passed to [SQ ::tkhtml::htmlstyle] then the returned document includes some extra rules used when rendering legacy documents. If the value of the -defaultstyle option is changed, the new value does not take effect until after the next call to the widget [SQ reset] method. The default value of this option is the same as the string returned by the [SQ ::tkhtml::htmlstyle] command. }] [Option fontscale { This option is set to a floating point number, default 1.0. After CSS algorithms are used to determine a font size, it is multiplied by the value of this option. Setting this to a value other than 1.0 breaks standards compliance. }] [Option fonttable { This option must be set to a list of 7 integers. The first integer must be greater than 0 and each subsequent integer must be greater than or equal to its predecessor. The seven integers define the sizes of the Tk fonts (in points) used when a CSS formatted document requests font-size 'xx-small', 'x-small', 'small', 'medium', 'large', 'x-large' or 'xx-large', respectively. The default value is {8 9 10 11 13 15 17}. }] [Option forcefontmetrics { This is a boolean option. If true, the font-metrics returned by Tk are overridden with calculated values based on the font requested. This improves CSS compatibility, but on some systems may cause problems. The default is true. }] [Option forcewidth { When determining the layout of a document, Tkhtml3 (and all other HTML/CSS engines) require as an input the width of the containing block for the whole document. For web-browsers, this is usually the width of the viewport in which the document will be displayed. If this option is true or the widget window is not mapped, Tkhtml3 uses the value of the -width option as the initial containing block width. Otherwise, the width of the widget window is used. The default value is false. }] [Option imagecache { This boolean option (default true) determines whether or not Tkhtml3 caches the images returned to it by the -imagecmd callback script. If true, all images are cached until the next time the [SQ reset] sub-command is invoked. If false, images are discarded as soon as they are not in use. For simple applications, or applications that retrieve images from local sources, false is usually a better value for this option (since it may save memory). However for web-browser applications where the background images of elements may be modified by mouseover events and so on, true is a better choice. }] [Option imagecmd { As well as for replacing entire document nodes (i.e. ), images are used in several other contexts in CSS formatted documents, for example as list markers or backgrounds. If the -imagecmd option is not set to an empty string (the default), then each time an image URI is encountered in the document, it is appended to the -imagecmd script and the resulting list evaluated. The command should return either an empty string, the name of a Tk image, or a list of exactly two elements, the name of a Tk image and a script. If the result is an empty string, then no image can be displayed. If the result is a Tk image name, then the image is displayed in the widget. When the image is no longer required, it is deleted. If the result of the command is a list containing a Tk image name and a script, then instead of deleting the image when it is no longer required, the script is evaluated. If the size or content of the image are modified while it is in use the widget display is updated automatically. }] [Option mode { This option may be set to "quirks", "standards" or "almost standards", to set the rendering engine mode. The default value is "standards". TODO: List the differences between the three modes in Tkhtml. }] [Option parsemode { This option may be set to "html", "xhtml" or "xml", to set the parser mode. The default value is "html". In "html" mode, the parser attempts to mimic the tag-soup approach inherited by modern web-browsers from the bad old days. Explicit XML style self-closing tags (i.e. closing a markup tag with "/>" instead of ">") are not handled specially. Unknown tags are ignored. "xhtml" mode is the same as "html" mode except that explicit self-closing tags are recognized. "xml" mode is the same as "xhtml" mode except that unknown tag names and XML CDATA sections are recognized. }] [Option shrink { This boolean option governs the way the widgets requested width and height are calculated. If it is set to false (the default), then the requested width and height are set by the -width and -height options as per usual. If this option is set to true, then the widgets requested width and height are determined by the current document. Each time the document layout is calculated, the widgets requested height and width are set to the size of the document layout. If the widget is unmapped when the layout is calculated, then the value of the -width option is used to determine the width of the initial containing block for the layout. Otherwise, the current window width is used. }] [Option zoom { This option may be set to any floating point number. Before the document layout is calculated, all lengths and sizes specified in the HTML document or CSS style configuration, implicit or explicit, are multiplied by this value. The default value is 1.0. }] [Option logcmd { This option is used for debugging the widget. It is not part of the official interface and may be modified or removed at any time. Don't worry about it. }] [Option timercmd { This option is used for debugging the widget. It is not part of the official interface and may be modified or removed at any time. Don't worry about it. }] [Option layoutcache { This option is used for debugging the widget. It is not part of the official interface and may be modified or removed at any time. Don't worry about it. If this boolean option is set to true, then Tkhtml caches layout information to improve performance when the layout of a document must be recomputed. This can happen in a variety of situations, for example when extra text is appended to the document, a new style is applied to the document, a dynamic CSS selector (i.e. :hover) is activated, the widget window is resized, or when the size of an embedded image or Tk window changes. Layout caching consumes no extra memory or significant processing cycles, so in an ideal world there is no real reason to turn it off. But it can be a source of layout bugs, hence this option. The default value is true. }] [Section Description] The [SQ html] command creates a new window (given by the pathName argument) and makes it into an html widget. The html command returns its pathName argument. At the time this command is invoked, there must not exist a window named pathName, but pathName's parent must exist. [Section Widget Command] The [SQ html] command creates a new Tcl command whose name is pathName. This command may be used to invoke various operations on the widget as follows: [Subcommand { pathName bbox _nodeHandle_ If node nodeHandle generates content, this command returns a list of four integers that define the bounding-box of the generated content, relative to the top-left hand corner of the rendered document. The first two integers are the x and y coordinates of the top-left corner of the bounding-box, the later two are the x and y coordinates of the bottom-right corner of the same box. If the node does not generate content, then an empty string is returned. }] [Subcommand { pathName cget _option_ Returns the current value of the configuration option given by option. Option may have any of the values accepted by the [SQ html] command. }] [Subcommand { pathName configure ?_option_? ?_value_? Query or modify the configuration options of the widget. If no option is specified, returns a list describing all of the available options for pathName (see Tk_ConfigureInfo for information on the format of this list). If option is specified with no value, then the command returns a list describing the one named option (this list will be identical to the corresponding sublist of the value returned if no option is specified). If one or more option-value pairs are specified, then the command modifies the given widget option(s) to have the given value(s); in this case the command returns an empty string. Option may have any of the values accepted by the [SQ html] command. }] [Subcommand { pathName fragment _html-text_ TODO: Document this command. }] [Subcommand -4 { pathName handler node _tag_ _script_ pathName handler attribute _tag_ _script_ pathName handler script _tag_ _script_ pathName handler parse _tag_ _script_ This command is used to define "handler" scripts - Tcl callback scripts that are invoked by the widget when document elements of specified types are encountered. The widget supports two types of handler scripts: "node" and "script". For a "node" handler script, whenever a document element having the specified tag type (e.g. "p" or "link") is encountered during parsing, then the node handle for the node is appended to script and the resulting list evaluated as a Tcl command. See the section "NODE COMMAND" for details of how a node handle may be used to query and manipulate a document node. A node handler is called only after the subtree rooted at the node has been completely parsed. If the handler script is a "script" handler, whenever a document node of type tag is parsed, two arguments are appended to the specified _script_ before it is evaluated. The first argument is a key-value list (suitable for passing to the [SQ array set] command containing the HTML attributes that were part of the element declaration. The second argument is the literal text that appears between the start and end tags of the element. Elements for which a "script" handler is evaluated are not included in the parsed form of the HTML document. Instead, the result of the script handler evaluation is substituted into the document and parsed. For example, to handle the following embedded javascript: [Code { }] a script handler that returns the string "

A paragraph

" must be configured for nodes of type "SCRIPT". Unlike node or script handlers, a "parse" handler may be associated with a specific opening tag, a closing tag or with text tags (by specifying an empty string as the tag type). Whenever such a tag is encountered the parse handler script is invoked with two arguments, the node handle for the created node and the character offset of the in the parsed document. For a closing tag (i.e. "/form") an empty string is passed instead of a node handle. TODO: Describe "attribute" handlers. TODO: The offset values passed to parse handler scripts currently have problems. See http://tkhtml.tcl.tk/cvstrac/tktview?tn=126 Handler callbacks are always made from within [SQ pathName parse] commands. The callback for a given node is made as soon as the node is completely parsed. This can happen because an implicit or explicit closing tag is parsed, or because there is no more document data and the -final switch was passed to the [SQ pathName parse] command. TODO: Return values of handler scripts? If an exception occurs in a handler script? }] [Subcommand { pathName image This command returns the name of a new Tk image containing the rendered document. Where Tk widgets would be mapped in a live display, the image contains blank space. The returned image should be deleted when the script has finished with it, for example: [Code { set img \[.html image] # ... Use $img ... image delete $img }] This command is included mainly for automated testing and should be used with care, as large documents can result in very large images that take a long time to create and use vast amounts of memory. Currently this command is not available on windows. On that platform an empty string is always returned. }] [Subcommand { pathName node ? ?-index? _x_ _y_? This command is used to retrieve one or more document node handles from the current document. If the x and y parameters are omitted, then the handle returned is the root-node of the document, or an empty string if the document has no root-node (i.e. an empty document). If the x and y arguments are present, then a list of node handles is returned. The list contains one handle for each node that generates content currently located at viewport coordinates (x, y). Usually this is only a single node, but floating boxes and other overlapped content can cause this command to return more than one node. If no content is located at the specified coordinates or the widget window is not mapped, then an empty string is returned. If the -index option is specified along with the x and y coordinates, then instead of a list of node handles, a list of two elements is returned. The first element of the list is the node-handle associated with the generated text closest to the specified (x, y) coordinates. The second list value is a byte (not character) offset into the text obtainable by [SQ nodeHandle text] for the character closest to coordinates (x, y). The index may be used with the [SQ pathName tag] commands. The document node can be queried and manipulated using the interface described in the "NODE COMMAND" section. }] [Subcommand { pathName parse ?-final? _html-text_ Append extra text to the end of the (possibly empty) document currently stored by the widget. If the -final option is present, this indicates that the supplied text is the last of the document. Any subsequent call to [SQ pathName parse] before a call to [SQ pathName reset] will raise an error. If the -final option is not passed to [SQ pathName parse] along with the final part of the document text, node handler scripts for any elements closed implicitly by the end of the document will not be executed. It is not an error to specify an empty string for the _html-text_ argument. }] [Subcommand { pathName preload _uri_ This command is only useful if the -imagecache option is set to true and an -imagecmd script is defined. It causes the widget to invoke the -imagecmd script to retrieve the image at URI _uri_. Assuming -imagecache is true, the returned image is then stored in the image-cache. This command may be useful when implementing scripting environments that support "preloading" of images. }] [Subcommand { pathName reset This is used to clear the internal contents of the widget prior to parsing a new document. The widget is reset such that the document tree is empty (as if no calls to [SQ pathName parse] had ever been made) and no stylesheets except the default stylesheet are loaded (as if no invocations of [SQ pathName style] had occured). }] [Subcommand { pathName search _selector_ The _selector_ argument passed to this command must be a valid CSS selector, for example "h1" or "a[SQ href]". This command returns a list of node-handles corresponding to the set of document nodes that match the supplied selector. }] [Subcommand { pathName style ?_options_? _stylesheet-text_ Add a stylesheet to the widgets internal configuration. The stylesheet-text argument should contain the text of a complete stylesheet. Incremental parsing of stylesheets is not supported, although of course multiple stylesheets may be added to a single widget. The following options are supported: [Code { Option Default Value -------------------------------------- -id "author" -importcmd
Filter:

BOOKMARKS:

To delete individual bookmarks or entire folders, drag to the top of the page (i.e. over the "Filter:" or "New Bookmark" controls). A single level of undelete is available.

tkHTML-4ee7aaa953d6cb59/hv/bugreport.html000064400000000000000000000117551151224263100174420ustar00nobodynobody

Report a bug in Hv3

View bug report guidelines

Quick Bug Report

Bug Report Guidelines

Please report the bugs you observe in Hv3. If a web-page is rendered incorrectly or some javascript features doesn't function correctly, that's a bug. If an irritating error dialog pops up, that's a bug. If Hv3 crashes, that's definitely a bug.

At this stage in the project, obtaining bug reports is very important. Don't worry about submitting duplicates or accidentally reporting a non-bug. Such reports take mere seconds to close and cause nobody any inconveniance. Be as brief as you like - typing something like "the page is busted because the menu is rendered wrong" is often all that is required.

If you include a contact e-mail address, nobody but the Hv3 developers will see it. And we'll (probably) send you an e-mail when the bug is fixed. Or if the bug is complex we might mail you for clarification. Whether or not you include an e-mail address, your help in bringing Hv3 bugs to our attention will be greatly appreciated.

If in doubt, report it!

Details

The Hv3/Tkhtml3 project uses cvstrac to manage source code, bug-reports and user contributed wiki pages. Access the cvstrac system here:

http://tkhtml.tcl.tk/cvstrac/

There are two ways to submit a bug into the system. The first is to add the bug directly into cvstrac via the web-interface by visiting the following link:

http://tkhtml.tcl.tk/cvstrac/tktnew

The second method is to submit the "Quick Bug Report" form above.

tkHTML-4ee7aaa953d6cb59/hv/combobox.tcl000064400000000000000000001756101151224263100170600ustar00nobodynobody# Copyright (c) 1998-2003, Bryan Oakley # All Rights Reservered # # Bryan Oakley # oakley@bardo.clearlight.com # # combobox v2.3 August 16, 2003 # # a combobox / dropdown listbox (pick your favorite name) widget # written in pure tcl # # this code is freely distributable without restriction, but is # provided as-is with no warranty expressed or implied. # # thanks to the following people who provided beta test support or # patches to the code (in no particular order): # # Scott Beasley Alexandre Ferrieux Todd Helfter # Matt Gushee Laurent Duperval John Jackson # Fred Rapp Christopher Nelson # Eric Galluzzo Jean-Francois Moine Oliver Bienert # # A special thanks to Martin M. Hunt who provided several good ideas, # and always with a patch to implement them. Jean-Francois Moine, # Todd Helfter and John Jackson were also kind enough to send in some # code patches. # # ... and many others over the years. package require Tk 8.0 package provide combobox 2.3 namespace eval ::combobox { # this is the public interface namespace export combobox # these contain references to available options variable widgetOptions # these contain references to available commands and subcommands variable widgetCommands variable scanCommands variable listCommands } # ::combobox::combobox -- # # This is the command that gets exported. It creates a new # combobox widget. # # Arguments: # # w path of new widget to create # args additional option/value pairs (eg: -background white, etc.) # # Results: # # It creates the widget and sets up all of the default bindings # # Returns: # # The name of the newly create widget proc ::combobox::combobox {w args} { variable widgetOptions variable widgetCommands variable scanCommands variable listCommands # perform a one time initialization if {![info exists widgetOptions]} { Init } # build it... eval Build $w $args # set some bindings... SetBindings $w # and we are done! return $w } # ::combobox::Init -- # # Initialize the namespace variables. This should only be called # once, immediately prior to creating the first instance of the # widget # # Arguments: # # none # # Results: # # All state variables are set to their default values; all of # the option database entries will exist. # # Returns: # # empty string proc ::combobox::Init {} { variable widgetOptions variable widgetCommands variable scanCommands variable listCommands variable defaultEntryCursor array set widgetOptions [list \ -background {background Background} \ -bd -borderwidth \ -bg -background \ -borderwidth {borderWidth BorderWidth} \ -buttonbackground {buttonBackground Background} \ -command {command Command} \ -commandstate {commandState State} \ -cursor {cursor Cursor} \ -disabledbackground {disabledBackground DisabledBackground} \ -disabledforeground {disabledForeground DisabledForeground} \ -dropdownwidth {dropdownWidth DropdownWidth} \ -editable {editable Editable} \ -elementborderwidth {elementBorderWidth BorderWidth} \ -fg -foreground \ -font {font Font} \ -foreground {foreground Foreground} \ -height {height Height} \ -highlightbackground {highlightBackground HighlightBackground} \ -highlightcolor {highlightColor HighlightColor} \ -highlightthickness {highlightThickness HighlightThickness} \ -image {image Image} \ -listvar {listVariable Variable} \ -maxheight {maxHeight Height} \ -opencommand {opencommand Command} \ -relief {relief Relief} \ -selectbackground {selectBackground Foreground} \ -selectborderwidth {selectBorderWidth BorderWidth} \ -selectforeground {selectForeground Background} \ -state {state State} \ -takefocus {takeFocus TakeFocus} \ -textvariable {textVariable Variable} \ -value {value Value} \ -width {width Width} \ -xscrollcommand {xScrollCommand ScrollCommand} \ ] set widgetCommands [list \ bbox cget configure curselection \ delete get icursor index \ insert list scan selection \ xview select toggle open \ close subwidget \ ] set listCommands [list \ delete get \ index insert size \ ] set scanCommands [list mark dragto] # why check for the Tk package? This lets us be sourced into # an interpreter that doesn't have Tk loaded, such as the slave # interpreter used by pkg_mkIndex. In theory it should have no # side effects when run if {[lsearch -exact [package names] "Tk"] != -1} { ################################################################## #- this initializes the option database. Kinda gross, but it works #- (I think). ################################################################## # the image used for the button... if {$::tcl_platform(platform) == "windows"} { image create bitmap ::combobox::bimage -data { #define down_arrow_width 12 #define down_arrow_height 12 static char down_arrow_bits[] = { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0xfc,0xf1,0xf8,0xf0,0x70,0xf0,0x20,0xf0, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00; } } } else { image create bitmap ::combobox::bimage -data { #define down_arrow_width 15 #define down_arrow_height 15 static char down_arrow_bits[] = { 0x00,0x80,0x00,0x80,0x00,0x80,0x00,0x80, 0x00,0x80,0xf8,0x8f,0xf0,0x87,0xe0,0x83, 0xc0,0x81,0x80,0x80,0x00,0x80,0x00,0x80, 0x00,0x80,0x00,0x80,0x00,0x80 } } } # compute a widget name we can use to create a temporary widget set tmpWidget ".__tmp__" set count 0 while {[winfo exists $tmpWidget] == 1} { set tmpWidget ".__tmp__$count" incr count } # get the scrollbar width. Because we try to be clever and draw our # own button instead of using a tk widget, we need to know what size # button to create. This little hack tells us the width of a scroll # bar. # # NB: we need to be sure and pick a window that doesn't already # exist... scrollbar $tmpWidget set sb_width [winfo reqwidth $tmpWidget] set bbg [$tmpWidget cget -background] destroy $tmpWidget # steal options from the entry widget # we want darn near all options, so we'll go ahead and do # them all. No harm done in adding the one or two that we # don't use. entry $tmpWidget foreach foo [$tmpWidget configure] { # the cursor option is special, so we'll save it in # a special way if {[lindex $foo 0] == "-cursor"} { set defaultEntryCursor [lindex $foo 4] } if {[llength $foo] == 5} { set option [lindex $foo 1] set value [lindex $foo 4] option add *Combobox.$option $value widgetDefault # these options also apply to the dropdown listbox if {[string compare $option "foreground"] == 0 \ || [string compare $option "background"] == 0 \ || [string compare $option "font"] == 0} { option add *Combobox*ComboboxListbox.$option $value \ widgetDefault } } } destroy $tmpWidget # these are unique to us... option add *Combobox.elementBorderWidth 1 widgetDefault option add *Combobox.buttonBackground $bbg widgetDefault option add *Combobox.dropdownWidth {} widgetDefault option add *Combobox.openCommand {} widgetDefault option add *Combobox.cursor {} widgetDefault option add *Combobox.commandState normal widgetDefault option add *Combobox.editable 1 widgetDefault option add *Combobox.maxHeight 10 widgetDefault option add *Combobox.height 0 } # set class bindings SetClassBindings } # ::combobox::SetClassBindings -- # # Sets up the default bindings for the widget class # # this proc exists since it's The Right Thing To Do, but # I haven't had the time to figure out how to do all the # binding stuff on a class level. The main problem is that # the entry widget must have focus for the insertion cursor # to be visible. So, I either have to have the entry widget # have the Combobox bindtag, or do some fancy juggling of # events or some such. What a pain. # # Arguments: # # none # # Returns: # # empty string proc ::combobox::SetClassBindings {} { # make sure we clean up after ourselves... bind Combobox [list ::combobox::DestroyHandler %W] # this will (hopefully) close (and lose the grab on) the # listbox if the user clicks anywhere outside of it. Note # that on Windows, you can click on some other app and # the listbox will still be there, because tcl won't see # that button click set this {[::combobox::convert %W -W]} bind Combobox "$this close" bind Combobox "$this close" # this helps (but doesn't fully solve) focus issues. The general # idea is, whenever the frame gets focus it gets passed on to # the entry widget bind Combobox {::combobox::tkTabToWindow \ [::combobox::convert %W -W].entry} # this closes the listbox if we get hidden bind Combobox {[::combobox::convert %W -W] close} return "" } # ::combobox::SetBindings -- # # here's where we do most of the binding foo. I think there's probably # a few bindings I ought to add that I just haven't thought # about... # # I'm not convinced these are the proper bindings. Ideally all # bindings should be on "Combobox", but because of my juggling of # bindtags I'm not convinced thats what I want to do. But, it all # seems to work, its just not as robust as it could be. # # Arguments: # # w widget pathname # # Returns: # # empty string proc ::combobox::SetBindings {w} { upvar ::combobox::${w}::widgets widgets upvar ::combobox::${w}::options options # juggle the bindtags. The basic idea here is to associate the # widget name with the entry widget, so if a user does a bind # on the combobox it will get handled properly since it is # the entry widget that has keyboard focus. bindtags $widgets(entry) \ [concat $widgets(this) [bindtags $widgets(entry)]] bindtags $widgets(button) \ [concat $widgets(this) [bindtags $widgets(button)]] # override the default bindings for tab and shift-tab. The # focus procs take a widget as their only parameter and we # want to make sure the right window gets used (for shift- # tab we want it to appear as if the event was generated # on the frame rather than the entry. bind $widgets(entry) \ "::combobox::tkTabToWindow \[tk_focusNext $widgets(entry)\]; break" bind $widgets(entry) \ "::combobox::tkTabToWindow \[tk_focusPrev $widgets(this)\]; break" # this makes our "button" (which is actually a label) # do the right thing bind $widgets(button) [list $widgets(this) toggle] # this lets the autoscan of the listbox work, even if they # move the cursor over the entry widget. bind $widgets(entry) "break" bind $widgets(listbox) \ "::combobox::Select [list $widgets(this)] \ \[$widgets(listbox) nearest %y\]; break" bind $widgets(vsb) {continue} bind $widgets(vsb) {continue} bind $widgets(listbox) { %W selection clear 0 end %W activate @%x,%y %W selection anchor @%x,%y %W selection set @%x,%y @%x,%y # need to do a yview if the cursor goes off the top # or bottom of the window... (or do we?) } # these events need to be passed from the entry widget # to the listbox, or otherwise need some sort of special # handling. foreach event [list \ <1> \ ] { bind $widgets(entry) $event \ [list ::combobox::HandleEvent $widgets(this) $event] } # like the other events, needs to be passed from # the entry widget to the listbox. However, in this case we # need to add an additional parameter catch { bind $widgets(entry) \ [list ::combobox::HandleEvent $widgets(this) %D] } } # ::combobox::Build -- # # This does all of the work necessary to create the basic # combobox. # # Arguments: # # w widget name # args additional option/value pairs # # Results: # # Creates a new widget with the given name. Also creates a new # namespace patterened after the widget name, as a child namespace # to ::combobox # # Returns: # # the name of the widget proc ::combobox::Build {w args } { variable widgetOptions if {[winfo exists $w]} { error "window name \"$w\" already exists" } # create the namespace for this instance, and define a few # variables namespace eval ::combobox::$w { variable ignoreTrace 0 variable oldFocus {} variable oldGrab {} variable oldValue {} variable options variable this variable widgets set widgets(foo) foo ;# coerce into an array set options(foo) foo ;# coerce into an array unset widgets(foo) unset options(foo) } # import the widgets and options arrays into this proc so # we don't have to use fully qualified names, which is a # pain. upvar ::combobox::${w}::widgets widgets upvar ::combobox::${w}::options options # this is our widget -- a frame of class Combobox. Naturally, # it will contain other widgets. We create it here because # we need it in order to set some default options. set widgets(this) [frame $w -class Combobox -takefocus 0] set widgets(entry) [entry $w.entry -takefocus 1] set widgets(button) [label $w.button -takefocus 0] # this defines all of the default options. We get the # values from the option database. Note that if an array # value is a list of length one it is an alias to another # option, so we just ignore it foreach name [array names widgetOptions] { if {[llength $widgetOptions($name)] == 1} continue set optName [lindex $widgetOptions($name) 0] set optClass [lindex $widgetOptions($name) 1] set value [option get $w $optName $optClass] set options($name) $value } # a couple options aren't available in earlier versions of # tcl, so we'll set them to sane values. For that matter, if # they exist but are empty, set them to sane values. if {[string length $options(-disabledforeground)] == 0} { set options(-disabledforeground) $options(-foreground) } if {[string length $options(-disabledbackground)] == 0} { set options(-disabledbackground) $options(-background) } # if -value is set to null, we'll remove it from our # local array. The assumption is, if the user sets it from # the option database, they will set it to something other # than null (since it's impossible to determine the difference # between a null value and no value at all). if {[info exists options(-value)] \ && [string length $options(-value)] == 0} { unset options(-value) } # we will later rename the frame's widget proc to be our # own custom widget proc. We need to keep track of this # new name, so we'll define and store it here... set widgets(frame) ::combobox::${w}::$w # gotta do this sooner or later. Might as well do it now pack $widgets(button) -side right -fill y -expand no pack $widgets(entry) -side left -fill both -expand yes # I should probably do this in a catch, but for now it's # good enough... What it does, obviously, is put all of # the option/values pairs into an array. Make them easier # to handle later on... array set options $args # now, the dropdown list... the same renaming nonsense # must go on here as well... set widgets(dropdown) [toplevel $w.top] set widgets(listbox) [listbox $w.top.list] set widgets(vsb) [scrollbar $w.top.vsb] pack $widgets(listbox) -side left -fill both -expand y # fine tune the widgets based on the options (and a few # arbitrary values...) # NB: we are going to use the frame to handle the relief # of the widget as a whole, so the entry widget will be # flat. This makes the button which drops down the list # to appear "inside" the entry widget. $widgets(vsb) configure \ -borderwidth 1 \ -command "$widgets(listbox) yview" \ -highlightthickness 0 $widgets(button) configure \ -background $options(-buttonbackground) \ -highlightthickness 0 \ -borderwidth $options(-elementborderwidth) \ -relief raised \ -width [expr {[winfo reqwidth $widgets(vsb)] - 2}] $widgets(entry) configure \ -borderwidth 0 \ -relief flat \ -highlightthickness 0 $widgets(dropdown) configure \ -borderwidth $options(-elementborderwidth) \ -relief sunken $widgets(listbox) configure \ -selectmode browse \ -background [$widgets(entry) cget -bg] \ -yscrollcommand "$widgets(vsb) set" \ -exportselection false \ -borderwidth 0 # trace variable ::combobox::${w}::entryTextVariable w \ # [list ::combobox::EntryTrace $w] # do some window management foo on the dropdown window wm overrideredirect $widgets(dropdown) 1 wm transient $widgets(dropdown) [winfo toplevel $w] wm group $widgets(dropdown) [winfo parent $w] wm resizable $widgets(dropdown) 0 0 wm withdraw $widgets(dropdown) # this moves the original frame widget proc into our # namespace and gives it a handy name rename ::$w $widgets(frame) # now, create our widget proc. Obviously (?) it goes in # the global namespace. All combobox widgets will actually # share the same widget proc to cut down on the amount of # bloat. proc ::$w {command args} \ "eval ::combobox::WidgetProc $w \$command \$args" # ok, the thing exists... let's do a bit more configuration. if {[catch "::combobox::Configure [list $widgets(this)] [array get options]" error]} { catch {destroy $w} error "internal error: $error" } return "" } # ::combobox::HandleEvent -- # # this proc handles events from the entry widget that we want # handled specially (typically, to allow navigation of the list # even though the focus is in the entry widget) # # Arguments: # # w widget pathname # event a string representing the event (not necessarily an # actual event) # args additional arguments required by particular events proc ::combobox::HandleEvent {w event args} { upvar ::combobox::${w}::widgets widgets upvar ::combobox::${w}::options options upvar ::combobox::${w}::oldValue oldValue # for all of these events, if we have a special action we'll # do that and do a "return -code break" to keep additional # bindings from firing. Otherwise we'll let the event fall # on through. switch $event { "" { if {[winfo ismapped $widgets(dropdown)]} { set D [lindex $args 0] # the '120' number in the following expression has # it's genesis in the tk bind manpage, which suggests # that the smallest value of %D for mousewheel events # will be 120. The intent is to scroll one line at a time. $widgets(listbox) yview scroll [expr {-($D/120)}] units } } "" { # if the widget is editable, clear the selection. # this makes it more obvious what will happen if the # user presses (and helps our code know what # to do if the user presses return) if {$options(-editable)} { $widgets(listbox) see 0 $widgets(listbox) selection clear 0 end $widgets(listbox) selection anchor 0 $widgets(listbox) activate 0 } } "" { set oldValue [$widgets(entry) get] } "" { if {![winfo ismapped $widgets(dropdown)]} { # did the value change? set newValue [$widgets(entry) get] if {$oldValue != $newValue} { CallCommand $widgets(this) $newValue } } } "<1>" { set editable [::combobox::GetBoolean $options(-editable)] if {!$editable} { if {[winfo ismapped $widgets(dropdown)]} { $widgets(this) close return -code break; } else { if {$options(-state) != "disabled"} { $widgets(this) open return -code break; } } } } "" { if {$options(-state) != "disabled"} { $widgets(this) toggle return -code break; } } "" { if {[winfo ismapped $widgets(dropdown)]} { ::combobox::Find $widgets(this) 0 return -code break; } else { ::combobox::SetValue $widgets(this) [$widgets(this) get] } } "" { # $widgets(entry) delete 0 end # $widgets(entry) insert 0 $oldValue if {[winfo ismapped $widgets(dropdown)]} { $widgets(this) close return -code break; } } "" { # did the value change? set newValue [$widgets(entry) get] if {$oldValue != $newValue} { CallCommand $widgets(this) $newValue } if {[winfo ismapped $widgets(dropdown)]} { ::combobox::Select $widgets(this) \ [$widgets(listbox) curselection] return -code break; } } "" { $widgets(listbox) yview scroll 1 pages set index [$widgets(listbox) index @0,0] $widgets(listbox) see $index $widgets(listbox) activate $index $widgets(listbox) selection clear 0 end $widgets(listbox) selection anchor $index $widgets(listbox) selection set $index } "" { $widgets(listbox) yview scroll -1 pages set index [$widgets(listbox) index @0,0] $widgets(listbox) activate $index $widgets(listbox) see $index $widgets(listbox) selection clear 0 end $widgets(listbox) selection anchor $index $widgets(listbox) selection set $index } "" { if {[winfo ismapped $widgets(dropdown)]} { ::combobox::tkListboxUpDown $widgets(listbox) 1 return -code break; } else { if {$options(-state) != "disabled"} { $widgets(this) open return -code break; } } } "" { if {[winfo ismapped $widgets(dropdown)]} { ::combobox::tkListboxUpDown $widgets(listbox) -1 return -code break; } else { if {$options(-state) != "disabled"} { $widgets(this) open return -code break; } } } } return "" } # ::combobox::DestroyHandler {w} -- # # Cleans up after a combobox widget is destroyed # # Arguments: # # w widget pathname # # Results: # # The namespace that was created for the widget is deleted, # and the widget proc is removed. proc ::combobox::DestroyHandler {w} { catch { # if the widget actually being destroyed is of class Combobox, # remove the namespace and associated proc. if {[string compare [winfo class $w] "Combobox"] == 0} { # delete the namespace and the proc which represents # our widget namespace delete ::combobox::$w rename $w {} } } return "" } # ::combobox::Find # # finds something in the listbox that matches the pattern in the # entry widget and selects it # # N.B. I'm not convinced this is working the way it ought to. It # works, but is the behavior what is expected? I've also got a gut # feeling that there's a better way to do this, but I'm too lazy to # figure it out... # # Arguments: # # w widget pathname # exact boolean; if true an exact match is desired # # Returns: # # Empty string proc ::combobox::Find {w {exact 0}} { upvar ::combobox::${w}::widgets widgets upvar ::combobox::${w}::options options ## *sigh* this logic is rather gross and convoluted. Surely ## there is a more simple, straight-forward way to implement ## all this. As the saying goes, I lack the time to make it ## shorter... # use what is already in the entry widget as a pattern set pattern [$widgets(entry) get] if {[string length $pattern] == 0} { # clear the current selection $widgets(listbox) see 0 $widgets(listbox) selection clear 0 end $widgets(listbox) selection anchor 0 $widgets(listbox) activate 0 return } # we're going to be searching this list... set list [$widgets(listbox) get 0 end] # if we are doing an exact match, try to find, # well, an exact match set exactMatch -1 if {$exact} { set exactMatch [lsearch -exact $list $pattern] } # search for it. We'll try to be clever and not only # search for a match for what they typed, but a match for # something close to what they typed. We'll keep removing one # character at a time from the pattern until we find a match # of some sort. set index -1 while {$index == -1 && [string length $pattern]} { set index [lsearch -glob $list "$pattern*"] if {$index == -1} { regsub {.$} $pattern {} pattern } } # this is the item that most closely matches... set thisItem [lindex $list $index] # did we find a match? If so, do some additional munging... if {$index != -1} { # we need to find the part of the first item that is # unique WRT the second... I know there's probably a # simpler way to do this... set nextIndex [expr {$index + 1}] set nextItem [lindex $list $nextIndex] # we don't really need to do much if the next # item doesn't match our pattern... if {[string match $pattern* $nextItem]} { # ok, the next item matches our pattern, too # now the trick is to find the first character # where they *don't* match... set marker [string length $pattern] while {$marker <= [string length $pattern]} { set a [string index $thisItem $marker] set b [string index $nextItem $marker] if {[string compare $a $b] == 0} { append pattern $a incr marker } else { break } } } else { set marker [string length $pattern] } } else { set marker end set index 0 } # ok, we know the pattern and what part is unique; # update the entry widget and listbox appropriately if {$exact && $exactMatch == -1} { # this means we didn't find an exact match $widgets(listbox) selection clear 0 end $widgets(listbox) see $index } elseif {!$exact} { # this means we found something, but it isn't an exact # match. If we find something that *is* an exact match we # don't need to do the following, since it would merely # be replacing the data in the entry widget with itself set oldstate [$widgets(entry) cget -state] $widgets(entry) configure -state normal $widgets(entry) delete 0 end $widgets(entry) insert end $thisItem $widgets(entry) selection clear $widgets(entry) selection range $marker end $widgets(listbox) activate $index $widgets(listbox) selection clear 0 end $widgets(listbox) selection anchor $index $widgets(listbox) selection set $index $widgets(listbox) see $index $widgets(entry) configure -state $oldstate } } # ::combobox::Select -- # # selects an item from the list and sets the value of the combobox # to that value # # Arguments: # # w widget pathname # index listbox index of item to be selected # # Returns: # # empty string proc ::combobox::Select {w index} { upvar ::combobox::${w}::widgets widgets upvar ::combobox::${w}::options options # the catch is because I'm sloppy -- presumably, the only time # an error will be caught is if there is no selection. if {![catch {set data [$widgets(listbox) get [lindex $index 0]]}]} { ::combobox::SetValue $widgets(this) $data $widgets(listbox) selection clear 0 end $widgets(listbox) selection anchor $index $widgets(listbox) selection set $index } $widgets(entry) selection range 0 end $widgets(entry) icursor end $widgets(this) close return "" } # ::combobox::HandleScrollbar -- # # causes the scrollbar of the dropdown list to appear or disappear # based on the contents of the dropdown listbox # # Arguments: # # w widget pathname # action the action to perform on the scrollbar # # Returns: # # an empty string proc ::combobox::HandleScrollbar {w {action "unknown"}} { upvar ::combobox::${w}::widgets widgets upvar ::combobox::${w}::options options if {$options(-height) == 0} { set hlimit $options(-maxheight) } else { set hlimit $options(-height) } switch $action { "grow" { if {$hlimit > 0 && [$widgets(listbox) size] > $hlimit} { pack forget $widgets(listbox) pack $widgets(vsb) -side right -fill y -expand n pack $widgets(listbox) -side left -fill both -expand y } } "shrink" { if {$hlimit > 0 && [$widgets(listbox) size] <= $hlimit} { pack forget $widgets(vsb) } } "crop" { # this means the window was cropped and we definitely # need a scrollbar no matter what the user wants pack forget $widgets(listbox) pack $widgets(vsb) -side right -fill y -expand n pack $widgets(listbox) -side left -fill both -expand y } default { if {$hlimit > 0 && [$widgets(listbox) size] > $hlimit} { pack forget $widgets(listbox) pack $widgets(vsb) -side right -fill y -expand n pack $widgets(listbox) -side left -fill both -expand y } else { pack forget $widgets(vsb) } } } return "" } # ::combobox::ComputeGeometry -- # # computes the geometry of the dropdown list based on the size of the # combobox... # # Arguments: # # w widget pathname # # Returns: # # the desired geometry of the listbox proc ::combobox::ComputeGeometry {w} { upvar ::combobox::${w}::widgets widgets upvar ::combobox::${w}::options options if {$options(-height) == 0 && $options(-maxheight) != "0"} { # if this is the case, count the items and see if # it exceeds our maxheight. If so, set the listbox # size to maxheight... set nitems [$widgets(listbox) size] if {$nitems > $options(-maxheight)} { # tweak the height of the listbox $widgets(listbox) configure -height $options(-maxheight) } else { # un-tweak the height of the listbox $widgets(listbox) configure -height 0 } update idletasks } # compute height and width of the dropdown list set bd [$widgets(dropdown) cget -borderwidth] set height [expr {[winfo reqheight $widgets(dropdown)] + $bd + $bd}] if {[string length $options(-dropdownwidth)] == 0 || $options(-dropdownwidth) == 0} { set width [winfo width $widgets(this)] } else { set m [font measure [$widgets(listbox) cget -font] "m"] set width [expr {$options(-dropdownwidth) * $m}] } # figure out where to place it on the screen, trying to take into # account we may be running under some virtual window manager set screenWidth [winfo screenwidth $widgets(this)] set screenHeight [winfo screenheight $widgets(this)] set rootx [winfo rootx $widgets(this)] set rooty [winfo rooty $widgets(this)] set vrootx [winfo vrootx $widgets(this)] set vrooty [winfo vrooty $widgets(this)] # the x coordinate is simply the rootx of our widget, adjusted for # the virtual window. We won't worry about whether the window will # be offscreen to the left or right -- we want the illusion that it # is part of the entry widget, so if part of the entry widget is off- # screen, so will the list. If you want to change the behavior, # simply change the if statement... (and be sure to update this # comment!) set x [expr {$rootx + $vrootx}] if {0} { set rightEdge [expr {$x + $width}] if {$rightEdge > $screenWidth} { set x [expr {$screenWidth - $width}] } if {$x < 0} {set x 0} } # the y coordinate is the rooty plus vrooty offset plus # the height of the static part of the widget plus 1 for a # tiny bit of visual separation... set y [expr {$rooty + $vrooty + [winfo reqheight $widgets(this)] + 1}] set bottomEdge [expr {$y + $height}] if {$bottomEdge >= $screenHeight} { # ok. Fine. Pop it up above the entry widget isntead of # below. set y [expr {($rooty - $height - 1) + $vrooty}] if {$y < 0} { # this means it extends beyond our screen. How annoying. # Now we'll try to be real clever and either pop it up or # down, depending on which way gives us the biggest list. # then, we'll trim the list to fit and force the use of # a scrollbar # (sadly, for windows users this measurement doesn't # take into consideration the height of the taskbar, # but don't blame me -- there isn't any way to detect # it or figure out its dimensions. The same probably # applies to any window manager with some magic windows # glued to the top or bottom of the screen) if {$rooty > [expr {$screenHeight / 2}]} { # we are in the lower half of the screen -- # pop it up. Y is zero; that parts easy. The height # is simply the y coordinate of our widget, minus # a pixel for some visual separation. The y coordinate # will be the topof the screen. set y 1 set height [expr {$rooty - 1 - $y}] } else { # we are in the upper half of the screen -- # pop it down set y [expr {$rooty + $vrooty + \ [winfo reqheight $widgets(this)] + 1}] set height [expr {$screenHeight - $y}] } # force a scrollbar HandleScrollbar $widgets(this) crop } } if {$y < 0} { # hmmm. Bummer. set y 0 set height $screenheight } set geometry [format "=%dx%d+%d+%d" $width $height $x $y] return $geometry } # ::combobox::DoInternalWidgetCommand -- # # perform an internal widget command, then mung any error results # to look like it came from our megawidget. A lot of work just to # give the illusion that our megawidget is an atomic widget # # Arguments: # # w widget pathname # subwidget pathname of the subwidget # command subwidget command to be executed # args arguments to the command # # Returns: # # The result of the subwidget command, or an error proc ::combobox::DoInternalWidgetCommand {w subwidget command args} { upvar ::combobox::${w}::widgets widgets upvar ::combobox::${w}::options options set subcommand $command set command [concat $widgets($subwidget) $command $args] if {[catch $command result]} { # replace the subwidget name with the megawidget name regsub $widgets($subwidget) $result $widgets(this) result # replace specific instances of the subwidget command # with our megawidget command switch $subwidget,$subcommand { listbox,index {regsub "index" $result "list index" result} listbox,insert {regsub "insert" $result "list insert" result} listbox,delete {regsub "delete" $result "list delete" result} listbox,get {regsub "get" $result "list get" result} listbox,size {regsub "size" $result "list size" result} } error $result } else { return $result } } # ::combobox::WidgetProc -- # # This gets uses as the widgetproc for an combobox widget. # Notice where the widget is created and you'll see that the # actual widget proc merely evals this proc with all of the # arguments intact. # # Note that some widget commands are defined "inline" (ie: # within this proc), and some do most of their work in # separate procs. This is merely because sometimes it was # easier to do it one way or the other. # # Arguments: # # w widget pathname # command widget subcommand # args additional arguments; varies with the subcommand # # Results: # # Performs the requested widget command proc ::combobox::WidgetProc {w command args} { upvar ::combobox::${w}::widgets widgets upvar ::combobox::${w}::options options upvar ::combobox::${w}::oldFocus oldFocus upvar ::combobox::${w}::oldFocus oldGrab set command [::combobox::Canonize $w command $command] # this is just shorthand notation... set doWidgetCommand \ [list ::combobox::DoInternalWidgetCommand $widgets(this)] if {$command == "list"} { # ok, the next argument is a list command; we'll # rip it from args and append it to command to # create a unique internal command # # NB: because of the sloppy way we are doing this, # we'll also let the user enter our secret command # directly (eg: listinsert, listdelete), but we # won't document that fact set command "list-[lindex $args 0]" set args [lrange $args 1 end] } set result "" # many of these commands are just synonyms for specific # commands in one of the subwidgets. We'll get them out # of the way first, then do the custom commands. switch $command { bbox - delete - get - icursor - index - insert - scan - selection - xview { set result [eval $doWidgetCommand entry $command $args] } list-get {set result [eval $doWidgetCommand listbox get $args]} list-index {set result [eval $doWidgetCommand listbox index $args]} list-size {set result [eval $doWidgetCommand listbox size $args]} select { if {[llength $args] == 1} { set index [lindex $args 0] set result [Select $widgets(this) $index] } else { error "usage: $w select index" } } subwidget { set knownWidgets [list button entry listbox dropdown vsb] if {[llength $args] == 0} { return $knownWidgets } set name [lindex $args 0] if {[lsearch $knownWidgets $name] != -1} { set result $widgets($name) } else { error "unknown subwidget $name" } } curselection { set result [eval $doWidgetCommand listbox curselection] } list-insert { eval $doWidgetCommand listbox insert $args set result [HandleScrollbar $w "grow"] } list-delete { eval $doWidgetCommand listbox delete $args set result [HandleScrollbar $w "shrink"] } toggle { # ignore this command if the widget is disabled... if {$options(-state) == "disabled"} return # pops down the list if it is not, hides it # if it is... if {[winfo ismapped $widgets(dropdown)]} { set result [$widgets(this) close] } else { set result [$widgets(this) open] } } open { # if this is an editable combobox, the focus should # be set to the entry widget if {$options(-editable)} { focus $widgets(entry) $widgets(entry) select range 0 end $widgets(entry) icursor end } # if we are disabled, we won't allow this to happen if {$options(-state) == "disabled"} { return 0 } # if there is a -opencommand, execute it now if {[string length $options(-opencommand)] > 0} { # hmmm... should I do a catch, or just let the normal # error handling handle any errors? For now, the latter... uplevel \#0 $options(-opencommand) } # compute the geometry of the window to pop up, and set # it, and force the window manager to take notice # (even if it is not presently visible). # # this isn't strictly necessary if the window is already # mapped, but we'll go ahead and set the geometry here # since its harmless and *may* actually reset the geometry # to something better in some weird case. set geometry [::combobox::ComputeGeometry $widgets(this)] wm geometry $widgets(dropdown) $geometry update idletasks # if we are already open, there's nothing else to do if {[winfo ismapped $widgets(dropdown)]} { return 0 } # save the widget that currently has the focus; we'll restore # the focus there when we're done set oldFocus [focus] # ok, tweak the visual appearance of things and # make the list pop up $widgets(button) configure -relief sunken wm deiconify $widgets(dropdown) update idletasks raise $widgets(dropdown) # force focus to the entry widget so we can handle keypress # events for traversal focus -force $widgets(entry) # select something by default, but only if its an # exact match... ::combobox::Find $widgets(this) 1 # save the current grab state for the display containing # this widget. We'll restore it when we close the dropdown # list set status "none" set grab [grab current $widgets(this)] if {$grab != ""} {set status [grab status $grab]} set oldGrab [list $grab $status] unset grab status # *gasp* do a global grab!!! Mom always told me not to # do things like this, but sometimes a man's gotta do # what a man's gotta do. grab -global $widgets(this) # fake the listbox into thinking it has focus. This is # necessary to get scanning initialized properly in the # listbox. event generate $widgets(listbox) return 1 } close { # if we are already closed, don't do anything... if {![winfo ismapped $widgets(dropdown)]} { return 0 } # restore the focus and grab, but ignore any errors... # we're going to be paranoid and release the grab before # trying to set any other grab because we really really # really want to make sure the grab is released. catch {focus $oldFocus} result catch {grab release $widgets(this)} catch { set status [lindex $oldGrab 1] if {$status == "global"} { grab -global [lindex $oldGrab 0] } elseif {$status == "local"} { grab [lindex $oldGrab 0] } unset status } # hides the listbox $widgets(button) configure -relief raised wm withdraw $widgets(dropdown) # select the data in the entry widget. Not sure # why, other than observation seems to suggest that's # what windows widgets do. set editable [::combobox::GetBoolean $options(-editable)] if {$editable} { $widgets(entry) selection range 0 end $widgets(button) configure -relief raised } # magic tcl stuff (see tk.tcl in the distribution # lib directory) ::combobox::tkCancelRepeat return 1 } cget { if {[llength $args] != 1} { error "wrong # args: should be $w cget option" } set opt [::combobox::Canonize $w option [lindex $args 0]] if {$opt == "-value"} { set result [$widgets(entry) get] } else { set result $options($opt) } } configure { set result [eval ::combobox::Configure {$w} $args] } default { error "bad option \"$command\"" } } return $result } # ::combobox::Configure -- # # Implements the "configure" widget subcommand # # Arguments: # # w widget pathname # args zero or more option/value pairs (or a single option) # # Results: # # Performs typcial "configure" type requests on the widget proc ::combobox::Configure {w args} { variable widgetOptions variable defaultEntryCursor upvar ::combobox::${w}::widgets widgets upvar ::combobox::${w}::options options if {[llength $args] == 0} { # hmmm. User must be wanting all configuration information # note that if the value of an array element is of length # one it is an alias, which needs to be handled slightly # differently set results {} foreach opt [lsort [array names widgetOptions]] { if {[llength $widgetOptions($opt)] == 1} { set alias $widgetOptions($opt) set optName $widgetOptions($alias) lappend results [list $opt $optName] } else { set optName [lindex $widgetOptions($opt) 0] set optClass [lindex $widgetOptions($opt) 1] set default [option get $w $optName $optClass] if {[info exists options($opt)]} { lappend results [list $opt $optName $optClass \ $default $options($opt)] } else { lappend results [list $opt $optName $optClass \ $default ""] } } } return $results } # one argument means we are looking for configuration # information on a single option if {[llength $args] == 1} { set opt [::combobox::Canonize $w option [lindex $args 0]] set optName [lindex $widgetOptions($opt) 0] set optClass [lindex $widgetOptions($opt) 1] set default [option get $w $optName $optClass] set results [list $opt $optName $optClass \ $default $options($opt)] return $results } # if we have an odd number of values, bail. if {[expr {[llength $args]%2}] == 1} { # hmmm. An odd number of elements in args error "value for \"[lindex $args end]\" missing" } # Great. An even number of options. Let's make sure they # are all valid before we do anything. Note that Canonize # will generate an error if it finds a bogus option; otherwise # it returns the canonical option name foreach {name value} $args { set name [::combobox::Canonize $w option $name] set opts($name) $value } # process all of the configuration options # some (actually, most) options require us to # do something, like change the attributes of # a widget or two. Here's where we do that... # # note that the handling of disabledforeground and # disabledbackground is a little wonky. First, we have # to deal with backwards compatibility (ie: tk 8.3 and below # didn't have such options for the entry widget), and # we have to deal with the fact we might want to disable # the entry widget but use the normal foreground/background # for when the combobox is not disabled, but not editable either. set updateVisual 0 foreach option [array names opts] { set newValue $opts($option) if {[info exists options($option)]} { set oldValue $options($option) } switch -- $option { -buttonbackground { $widgets(button) configure -background $newValue } -background { set updateVisual 1 set options($option) $newValue } -borderwidth { $widgets(frame) configure -borderwidth $newValue set options($option) $newValue } -command { # nothing else to do... set options($option) $newValue } -commandstate { # do some value checking... if {$newValue != "normal" && $newValue != "disabled"} { set options($option) $oldValue set message "bad state value \"$newValue\";" append message " must be normal or disabled" error $message } set options($option) $newValue } -cursor { $widgets(frame) configure -cursor $newValue $widgets(entry) configure -cursor $newValue $widgets(listbox) configure -cursor $newValue set options($option) $newValue } -disabledforeground { set updateVisual 1 set options($option) $newValue } -disabledbackground { set updateVisual 1 set options($option) $newValue } -dropdownwidth { set options($option) $newValue } -editable { set updateVisual 1 if {$newValue} { # it's editable... $widgets(entry) configure \ -state normal \ -cursor $defaultEntryCursor } else { $widgets(entry) configure \ -state disabled \ -cursor $options(-cursor) } set options($option) $newValue } -elementborderwidth { $widgets(button) configure -borderwidth $newValue $widgets(vsb) configure -borderwidth $newValue $widgets(dropdown) configure -borderwidth $newValue set options($option) $newValue } -font { $widgets(entry) configure -font $newValue $widgets(listbox) configure -font $newValue set options($option) $newValue } -foreground { set updateVisual 1 set options($option) $newValue } -height { $widgets(listbox) configure -height $newValue HandleScrollbar $w set options($option) $newValue } -highlightbackground { $widgets(frame) configure -highlightbackground $newValue set options($option) $newValue } -highlightcolor { $widgets(frame) configure -highlightcolor $newValue set options($option) $newValue } -highlightthickness { $widgets(frame) configure -highlightthickness $newValue set options($option) $newValue } -image { if {[string length $newValue] > 0} { puts "old button width: [$widgets(button) cget -width]" $widgets(button) configure \ -image $newValue \ -width [expr {[image width $newValue] + 2}] puts "new button width: [$widgets(button) cget -width]" } else { $widgets(button) configure -image ::combobox::bimage } set options($option) $newValue } -listvar { if {[catch {$widgets(listbox) cget -listvar}]} { return -code error \ "-listvar not supported with this version of tk" } $widgets(listbox) configure -listvar $newValue set options($option) $newValue } -maxheight { # ComputeGeometry may dork with the actual height # of the listbox, so let's undork it $widgets(listbox) configure -height $options(-height) HandleScrollbar $w set options($option) $newValue } -opencommand { # nothing else to do... set options($option) $newValue } -relief { $widgets(frame) configure -relief $newValue set options($option) $newValue } -selectbackground { $widgets(entry) configure -selectbackground $newValue $widgets(listbox) configure -selectbackground $newValue set options($option) $newValue } -selectborderwidth { $widgets(entry) configure -selectborderwidth $newValue $widgets(listbox) configure -selectborderwidth $newValue set options($option) $newValue } -selectforeground { $widgets(entry) configure -selectforeground $newValue $widgets(listbox) configure -selectforeground $newValue set options($option) $newValue } -state { if {$newValue == "normal"} { set updateVisual 1 # it's enabled set editable [::combobox::GetBoolean \ $options(-editable)] if {$editable} { $widgets(entry) configure -state normal $widgets(entry) configure -takefocus 1 } # note that $widgets(button) is actually a label, # not a button. And being able to disable labels # wasn't possible until tk 8.3. (makes me wonder # why I chose to use a label, but that answer is # lost to antiquity) if {[info patchlevel] >= 8.3} { $widgets(button) configure -state normal } } elseif {$newValue == "disabled"} { set updateVisual 1 # it's disabled $widgets(entry) configure -state disabled $widgets(entry) configure -takefocus 0 # note that $widgets(button) is actually a label, # not a button. And being able to disable labels # wasn't possible until tk 8.3. (makes me wonder # why I chose to use a label, but that answer is # lost to antiquity) if {$::tcl_version >= 8.3} { $widgets(button) configure -state disabled } } else { set options($option) $oldValue set message "bad state value \"$newValue\";" append message " must be normal or disabled" error $message } set options($option) $newValue } -takefocus { $widgets(entry) configure -takefocus $newValue set options($option) $newValue } -textvariable { $widgets(entry) configure -textvariable $newValue set options($option) $newValue } -value { ::combobox::SetValue $widgets(this) $newValue set options($option) $newValue } -width { $widgets(entry) configure -width $newValue $widgets(listbox) configure -width $newValue set options($option) $newValue } -xscrollcommand { $widgets(entry) configure -xscrollcommand $newValue set options($option) $newValue } } if {$updateVisual} {UpdateVisualAttributes $w} } } # ::combobox::UpdateVisualAttributes -- # # sets the visual attributes (foreground, background mostly) # based on the current state of the widget (normal/disabled, # editable/non-editable) # # why a proc for such a simple thing? Well, in addition to the # various states of the widget, we also have to consider the # version of tk being used -- versions from 8.4 and beyond have # the notion of disabled foreground/background options for various # widgets. All of the permutations can get nasty, so we encapsulate # it all in one spot. # # note also that we don't handle all visual attributes here; just # the ones that depend on the state of the widget. The rest are # handled on a case by case basis # # Arguments: # w widget pathname # # Returns: # empty string proc ::combobox::UpdateVisualAttributes {w} { upvar ::combobox::${w}::widgets widgets upvar ::combobox::${w}::options options if {$options(-state) == "normal"} { set foreground $options(-foreground) set background $options(-background) } elseif {$options(-state) == "disabled"} { set foreground $options(-disabledforeground) set background $options(-disabledbackground) } $widgets(entry) configure -foreground $foreground -background $background $widgets(listbox) configure -foreground $foreground -background $background $widgets(button) configure -foreground $foreground # $widgets(vsb) configure -background $background -troughcolor $background $widgets(frame) configure -background $background # we need to set the disabled colors in case our widget is disabled. # We could actually check for disabled-ness, but we also need to # check whether we're enabled but not editable, in which case the # entry widget is disabled but we still want the enabled colors. It's # easier just to set everything and be done with it. if {$::tcl_version >= 8.4} { $widgets(entry) configure \ -disabledforeground $foreground \ -disabledbackground $background $widgets(button) configure -disabledforeground $foreground $widgets(listbox) configure -disabledforeground $foreground } } # ::combobox::SetValue -- # # sets the value of the combobox and calls the -command, # if defined # # Arguments: # # w widget pathname # newValue the new value of the combobox # # Returns # # Empty string proc ::combobox::SetValue {w newValue} { upvar ::combobox::${w}::widgets widgets upvar ::combobox::${w}::options options upvar ::combobox::${w}::ignoreTrace ignoreTrace upvar ::combobox::${w}::oldValue oldValue if {[info exists options(-textvariable)] \ && [string length $options(-textvariable)] > 0} { set variable ::$options(-textvariable) set $variable $newValue } else { set oldstate [$widgets(entry) cget -state] $widgets(entry) configure -state normal $widgets(entry) delete 0 end $widgets(entry) insert 0 $newValue $widgets(entry) configure -state $oldstate } # set our internal textvariable; this will cause any public # textvariable (ie: defined by the user) to be updated as # well # set ::combobox::${w}::entryTextVariable $newValue # redefine our concept of the "old value". Do it before running # any associated command so we can be sure it happens even # if the command somehow fails. set oldValue $newValue # call the associated command. The proc will handle whether or # not to actually call it, and with what args CallCommand $w $newValue return "" } # ::combobox::CallCommand -- # # calls the associated command, if any, appending the new # value to the command to be called. # # Arguments: # # w widget pathname # newValue the new value of the combobox # # Returns # # empty string proc ::combobox::CallCommand {w newValue} { upvar ::combobox::${w}::widgets widgets upvar ::combobox::${w}::options options # call the associated command, if defined and -commandstate is # set to "normal" if {$options(-commandstate) == "normal" && \ [string length $options(-command)] > 0} { set args [list $widgets(this) $newValue] uplevel \#0 $options(-command) $args } } # ::combobox::GetBoolean -- # # returns the value of a (presumably) boolean string (ie: it should # do the right thing if the string is "yes", "no", "true", 1, etc # # Arguments: # # value value to be converted # errorValue a default value to be returned in case of an error # # Returns: # # a 1 or zero, or the value of errorValue if the string isn't # a proper boolean value proc ::combobox::GetBoolean {value {errorValue 1}} { if {[catch {expr {([string trim $value])?1:0}} res]} { return $errorValue } else { return $res } } # ::combobox::convert -- # # public routine to convert %x, %y and %W binding substitutions. # Given an x, y and or %W value relative to a given widget, this # routine will convert the values to be relative to the combobox # widget. For example, it could be used in a binding like this: # # bind .combobox {doSomething [::combobox::convert %W -x %x]} # # Note that this procedure is *not* exported, but is intended for # public use. It is not exported because the name could easily # clash with existing commands. # # Arguments: # # w a widget path; typically the actual result of a %W # substitution in a binding. It should be either a # combobox widget or one of its subwidgets # # args should one or more of the following arguments or # pairs of arguments: # # -x will convert the value ; typically will # be the result of a %x substitution # -y will convert the value ; typically will # be the result of a %y substitution # -W (or -w) will return the name of the combobox widget # which is the parent of $w # # Returns: # # a list of the requested values. For example, a single -w will # result in a list of one items, the name of the combobox widget. # Supplying "-x 10 -y 20 -W" (in any order) will return a list of # three values: the converted x and y values, and the name of # the combobox widget. proc ::combobox::convert {w args} { set result {} if {![winfo exists $w]} { error "window \"$w\" doesn't exist" } while {[llength $args] > 0} { set option [lindex $args 0] set args [lrange $args 1 end] switch -exact -- $option { -x { set value [lindex $args 0] set args [lrange $args 1 end] set win $w while {[winfo class $win] != "Combobox"} { incr value [winfo x $win] set win [winfo parent $win] if {$win == "."} break } lappend result $value } -y { set value [lindex $args 0] set args [lrange $args 1 end] set win $w while {[winfo class $win] != "Combobox"} { incr value [winfo y $win] set win [winfo parent $win] if {$win == "."} break } lappend result $value } -w - -W { set win $w while {[winfo class $win] != "Combobox"} { set win [winfo parent $win] if {$win == "."} break; } lappend result $win } } } return $result } # ::combobox::Canonize -- # # takes a (possibly abbreviated) option or command name and either # returns the canonical name or an error # # Arguments: # # w widget pathname # object type of object to canonize; must be one of "command", # "option", "scan command" or "list command" # opt the option (or command) to be canonized # # Returns: # # Returns either the canonical form of an option or command, # or raises an error if the option or command is unknown or # ambiguous. proc ::combobox::Canonize {w object opt} { variable widgetOptions variable columnOptions variable widgetCommands variable listCommands variable scanCommands switch $object { command { if {[lsearch -exact $widgetCommands $opt] >= 0} { return $opt } # command names aren't stored in an array, and there # isn't a way to get all the matches in a list, so # we'll stuff the commands in a temporary array so # we can use [array names] set list $widgetCommands foreach element $list { set tmp($element) "" } set matches [array names tmp ${opt}*] } {list command} { if {[lsearch -exact $listCommands $opt] >= 0} { return $opt } # command names aren't stored in an array, and there # isn't a way to get all the matches in a list, so # we'll stuff the commands in a temporary array so # we can use [array names] set list $listCommands foreach element $list { set tmp($element) "" } set matches [array names tmp ${opt}*] } {scan command} { if {[lsearch -exact $scanCommands $opt] >= 0} { return $opt } # command names aren't stored in an array, and there # isn't a way to get all the matches in a list, so # we'll stuff the commands in a temporary array so # we can use [array names] set list $scanCommands foreach element $list { set tmp($element) "" } set matches [array names tmp ${opt}*] } option { if {[info exists widgetOptions($opt)] \ && [llength $widgetOptions($opt)] == 2} { return $opt } set list [array names widgetOptions] set matches [array names widgetOptions ${opt}*] } } if {[llength $matches] == 0} { set choices [HumanizeList $list] error "unknown $object \"$opt\"; must be one of $choices" } elseif {[llength $matches] == 1} { set opt [lindex $matches 0] # deal with option aliases switch $object { option { set opt [lindex $matches 0] if {[llength $widgetOptions($opt)] == 1} { set opt $widgetOptions($opt) } } } return $opt } else { set choices [HumanizeList $list] error "ambiguous $object \"$opt\"; must be one of $choices" } } # ::combobox::HumanizeList -- # # Returns a human-readable form of a list by separating items # by columns, but separating the last two elements with "or" # (eg: foo, bar or baz) # # Arguments: # # list a valid tcl list # # Results: # # A string which as all of the elements joined with ", " or # the word " or " proc ::combobox::HumanizeList {list} { if {[llength $list] == 1} { return [lindex $list 0] } else { set list [lsort $list] set secondToLast [expr {[llength $list] -2}] set most [lrange $list 0 $secondToLast] set last [lindex $list end] return "[join $most {, }] or $last" } } # This is some backwards-compatibility code to handle TIP 44 # (http://purl.org/tcl/tip/44.html). For all private tk commands # used by this widget, we'll make duplicates of the procs in the # combobox namespace. # # I'm not entirely convinced this is the right thing to do. I probably # shouldn't even be using the private commands. Then again, maybe the # private commands really should be public. Oh well; it works so it # must be OK... foreach command {TabToWindow CancelRepeat ListboxUpDown} { if {[llength [info commands ::combobox::tk$command]] == 1} break; set tmp [info commands tk$command] set proc ::combobox::tk$command if {[llength [info commands tk$command]] == 1} { set command [namespace which [lindex $tmp 0]] proc $proc {args} "uplevel $command \$args" } else { if {[llength [info commands ::tk::$command]] == 1} { proc $proc {args} "uplevel ::tk::$command \$args" } } } # end of combobox.tcl tkHTML-4ee7aaa953d6cb59/hv/hv.tcl000064400000000000000000000216521151224263100156610ustar00nobodynobody# # This script implements the "hv" application. Type "hv FILE" to # view FILE as HTML. # # This application is used for testing the HTML widget. It can # also server as an example of how to use the HTML widget. # # @(#) $Id: hv.tcl,v 1.31 2003/01/28 09:43:23 hkoba Exp $ # wm title . {HTML File Viewer} wm iconname . {HV} # Make sure the html widget is loaded into # our interpreter # if {[info command html]==""} { if {[catch {package require Tkhtml} error]} { foreach f { ./libTkhtml*.so ../libTkhtml*.so /usr/lib/libTkhtml*.so /usr/local/lib/libTkhtml*.so ./tkhtml.dll } { if {[set f [lindex [glob -nocomplain $f] end]] != ""} { if {[catch {load $f Tkhtml}]==0} break } } } } # The HtmlTraceMask only works if the widget was compiled with # the -DDEBUG=1 command-line option. "file" is the name of the # first HTML file to be loaded. # set HtmlTraceMask 0 set file {} foreach a $argv { if {[regexp {^debug=} $a]} { scan $a "debug=0x%x" HtmlTraceMask } else { set file $a } } # These images are used in place of GIFs or of form elements # image create photo biggray -data { R0lGODdhPAA+APAAALi4uAAAACwAAAAAPAA+AAACQISPqcvtD6OctNqLs968+w+G4kiW5omm 6sq27gvH8kzX9o3n+s73/g8MCofEovGITCqXzKbzCY1Kp9Sq9YrNFgsAO/// } image create photo smgray -data { R0lGODdhOAAYAPAAALi4uAAAACwAAAAAOAAYAAACI4SPqcvtD6OctNqLs968+w+G4kiW5omm 6sq27gvH8kzX9m0VADv/ } image create photo nogifbig -data { R0lGODdhJAAkAPEAAACQkADQ0PgAAAAAACwAAAAAJAAkAAACmISPqcsQD6OcdJqKM71PeK15 AsSJH0iZY1CqqKSurfsGsex08XuTuU7L9HywHWZILAaVJssvgoREk5PolFo1XrHZ29IZ8oo0 HKEYVDYbyc/jFhz2otvdcyZdF68qeKh2DZd3AtS0QWcDSDgWKJXY+MXS9qY4+JA2+Vho+YPp FzSjiTIEWslDQ1rDhPOY2sXVOgeb2kBbu1AAADv/ } image create photo nogifsm -data { R0lGODdhEAAQAPEAAACQkADQ0PgAAAAAACwAAAAAEAAQAAACNISPacHtD4IQz80QJ60as25d 3idKZdR0IIOm2ta0Lhw/Lz2S1JqvK8ozbTKlEIVYceWSjwIAO/// } # Construct the main window # frame .mbar -bd 2 -relief raised pack .mbar -side top -fill x menubutton .mbar.file -text File -underline 0 -menu .mbar.file.m pack .mbar.file -side left -padx 5 set m [menu .mbar.file.m] $m add command -label Open -underline 0 -command Load $m add command -label Refresh -underline 0 -command Refresh $m add separator $m add command -label Exit -underline 1 -command exit menubutton .mbar.view -text View -underline 0 -menu .mbar.view.m pack .mbar.view -side left -padx 5 set m [menu .mbar.view.m] set underlineHyper 0 $m add checkbutton -label {Underline Hyperlinks} -variable underlineHyper trace variable underlineHyper w ChangeUnderline proc ChangeUnderline args { global underlineHyper .h.h config -underlinehyperlinks $underlineHyper } set showTableStruct 0 $m add checkbutton -label {Show Table Structure} -variable showTableStruct trace variable showTableStruct w ShowTableStruct proc ShowTableStruct args { global showTableStruct HtmlTraceMask if {$showTableStruct} { set HtmlTraceMask [expr {$HtmlTraceMask|0x8}] .h.h config -tablerelief flat } else { set HtmlTraceMask [expr {$HtmlTraceMask&~0x8}] .h.h config -tablerelief raised } Refresh } set showImages 1 $m add checkbutton -label {Show Images} -variable showImages trace variable showImages w Refresh # Construct the main HTML viewer # frame .h pack .h -side top -fill both -expand 1 html .h.h \ -yscrollcommand {.h.vsb set} \ -xscrollcommand {.f2.hsb set} \ -padx 5 \ -pady 9 \ -formcommand FormCmd \ -imagecommand ImageCmd \ -scriptcommand ScriptCmd \ -appletcommand AppletCmd \ -underlinehyperlinks 0 \ -bg white -tablerelief raised # If the tracemask is not 0, then draw the outline of all # tables as a blank line, not a 3D relief. # if {$HtmlTraceMask} { .h.h config -tablerelief flat } # A font chooser routine. # # .h.h config -fontcommand pickFont proc pickFont {size attrs} { puts "FontCmd: $size $attrs" set a [expr {-1<[lsearch $attrs fixed]?{courier}:{charter}}] set b [expr {-1<[lsearch $attrs italic]?{italic}:{roman}}] set c [expr {-1<[lsearch $attrs bold]?{bold}:{normal}}] set d [expr {int(12*pow(1.2,$size-4))}] list $a $d $b $c } # This routine is called for each form element # proc FormCmd {n cmd style args} { # puts "FormCmd: $n $cmd $args" switch $cmd { select - textarea - input { set w [lindex $args 0] label $w -image nogifsm } } } # This routine is called for every markup # # proc ImageCmd {args} { # puts "image: $args" # set fn [lindex $args 0] # if {[catch {image create photo -file $fn} img]} { # return nogifsm # } else { # global Images # set Images($img) 1 # return $img # } #} proc ImageCmd {args} { global OldImages Images showImages if {!$showImages} { return smgray } set fn [lindex $args 0] if {[info exists OldImages($fn)]} { set Images($fn) $OldImages($fn) unset OldImages($fn) return $Images($fn) } if {[catch {image create photo -file $fn} img]} { return smgray } if {[image width $img]*[image height $img]>20000} { global BigImages set b [image create photo -width [image width $img] \ -height [image height $img]] set BigImages($b) $img set img $b after idle "MoveBigImage $b" } set Images($fn) $img return $img } proc MoveBigImage b { global BigImages if {![info exists BigImages($b)]} return $b copy $BigImages($b) image delete $BigImages($b) unset BigImages($b) update } # This routine is called for every , or whatever closing tag matches * the tag that opened the script node. */ int rc; HtmlCallbackRestyle(pTree, pTree->state.pCurrent); assert(pTree->eWriteState == HTML_WRITE_NONE); pTree->eWriteState = HTML_WRITE_INHANDLER; pTree->iWriteInsert = n; rc = executeScript(pTree, pScript, pAttr, zScript, nScript); assert( pTree->eWriteState == HTML_WRITE_INHANDLER || pTree->eWriteState == HTML_WRITE_INHANDLERWAIT || pTree->eWriteState == HTML_WRITE_INHANDLERRESET ); switch (pTree->eWriteState) { case HTML_WRITE_INHANDLER: pTree->eWriteState = HTML_WRITE_NONE; break; case HTML_WRITE_INHANDLERWAIT: pTree->eWriteState = HTML_WRITE_WAIT; break; case HTML_WRITE_INHANDLERRESET: pTree->eWriteState = HTML_WRITE_NONE; return 0; } z = Tcl_GetString(pTree->pDocument); HtmlFree(pAttr); isTrimStart = 0; if (pTree->eWriteState == HTML_WRITE_WAIT) { goto incomplete; } } } } } incomplete: if (!zText && pTree->eWriteState != HTML_WRITE_INHANDLERRESET) { pTree->nParsed = n; } return n; } /************************** End HTML Tokenizer Code ***************************/ static int tokenizeWrapper(pTree, isFin, xAddText, xAddElement, xAddClosing) HtmlTree *pTree; /* The HTML widget doing the parsing */ int isFin; void (*xAddText)(HtmlTree *, HtmlTextNode *, int); void (*xAddElement)(HtmlTree *, int, const char *, HtmlAttributes *, int); void (*xAddClosing)(HtmlTree *, int, const char *, int); { int rc; HtmlNode *pCurrent = pTree->state.pCurrent; assert(pTree->eWriteState == HTML_WRITE_NONE); HtmlCheckRestylePoint(pTree); HtmlCallbackRestyle(pTree, pCurrent ? pCurrent : pTree->pRoot); HtmlCallbackLayout(pTree, pCurrent); rc = HtmlTokenize(pTree, 0, isFin, xAddText, xAddElement, xAddClosing); if (pTree->isParseFinished && pTree->eWriteState==HTML_WRITE_NONE) { HtmlFinishNodeHandlers(pTree); } if (pTree->eWriteState != HTML_WRITE_INHANDLERRESET) { pCurrent = pTree->state.pCurrent; HtmlCallbackRestyle(pTree, pCurrent ? pCurrent : pTree->pRoot); /* The theory is that the above calls to CallbackRestyle() ensure that * any nodes added to the tree by HtmlTokenize() are styled in the next * idle callback. This call, which is a no-op in -DNDEBUG builds, * checks if that is true. * * TODO. Each time an element is added to a foster-tree in htmltree.c * it calls HtmlCheckRestylePoint(). This is inefficient. But otherwise * the following assert() fails (HtmlCheckRestylePoint() is a complex * assert() function). */ HtmlCheckRestylePoint(pTree); } return rc; } /* *--------------------------------------------------------------------------- * * HtmlTokenizerAppend -- * * Append text to the tokenizer engine. * * Results: * None. * * Side effects: * This routine (actually the Tokenize() subroutine that is called * by this routine) may invoke a callback procedure which could delete * the HTML widget. * *--------------------------------------------------------------------------- */ void HtmlTokenizerAppend(pTree, zText, nText, isFinal) HtmlTree *pTree; const char *zText; int nText; int isFinal; { /* TODO: Add a flag to prevent recursive calls to this routine. */ const char *z = zText; int n = nText; /* Tcl_DString utf8; */ if (!pTree->pDocument) { pTree->pDocument = Tcl_NewObj(); Tcl_IncrRefCount(pTree->pDocument); assert(!Tcl_IsShared(pTree->pDocument)); } assert(!Tcl_IsShared(pTree->pDocument)); Tcl_AppendToObj(pTree->pDocument, z, n); if (pTree->eWriteState == HTML_WRITE_NONE) { tokenizeWrapper(pTree, isFinal, HtmlTreeAddText, HtmlTreeAddElement, HtmlTreeAddClosingTag ); } } /* *--------------------------------------------------------------------------- * * HtmlMarkupArg -- * * Lookup an argument in the given markup with the name given. * Return a pointer to its value, or the given default * value if it doesn't appear. * * Results: * None. * * Side effects: * None. * *--------------------------------------------------------------------------- */ char * HtmlMarkupArg(pAttr, zTag, zDefault) HtmlAttributes *pAttr; const char *zTag; char *zDefault; { int i; if (pAttr) { for (i = 0; i < pAttr->nAttr; i++) { if (strcmp(pAttr->a[i].zName, zTag) == 0) { return pAttr->a[i].zValue; } } } return zDefault; } /* *--------------------------------------------------------------------------- * * HtmlWriteWait -- * * $widget write wait * * Results: * None. * * Side effects: * None. * *--------------------------------------------------------------------------- */ int HtmlWriteWait(pTree) HtmlTree *pTree; { if (pTree->eWriteState != HTML_WRITE_INHANDLER) { char *zErr = "Cannot call [write wait] here"; Tcl_SetResult(pTree->interp, zErr, TCL_STATIC); return TCL_ERROR; } pTree->eWriteState = HTML_WRITE_INHANDLERWAIT; return TCL_OK; } /* *--------------------------------------------------------------------------- * * HtmlWriteText -- * * $widget write text HTML * * Results: * None. * * Side effects: * None. * *--------------------------------------------------------------------------- */ int HtmlWriteText(pTree, pText) HtmlTree *pTree; Tcl_Obj *pText; { int iInsert = pTree->iWriteInsert; Tcl_Obj *pDocument = pTree->pDocument; Tcl_Obj *pHead; Tcl_Obj *pTail; if (pTree->eWriteState == HTML_WRITE_NONE) { char *zErr = "Cannot call [write text] here"; Tcl_SetResult(pTree->interp, zErr, TCL_STATIC); return TCL_ERROR; } pHead = Tcl_NewStringObj(Tcl_GetString(pDocument), iInsert); pTail = Tcl_NewStringObj(&(Tcl_GetString(pDocument)[iInsert]), -1); Tcl_IncrRefCount(pHead); Tcl_AppendObjToObj(pHead, pText); Tcl_GetStringFromObj(pHead, &pTree->iWriteInsert); Tcl_AppendObjToObj(pHead, pTail); Tcl_DecrRefCount(pDocument); pTree->pDocument = pHead; return TCL_OK; } /* *--------------------------------------------------------------------------- * * HtmlWriteContinue -- * * $widget write continue * * Results: * None. * * Side effects: * None. * *--------------------------------------------------------------------------- */ int HtmlWriteContinue(pTree) HtmlTree *pTree; { int eState = pTree->eWriteState; if (eState != HTML_WRITE_WAIT && eState != HTML_WRITE_INHANDLERWAIT) { char *zErr = "Cannot call [write continue] here"; Tcl_SetResult(pTree->interp, zErr, TCL_STATIC); return TCL_ERROR; } switch (eState) { case HTML_WRITE_WAIT: { pTree->eWriteState = HTML_WRITE_NONE; tokenizeWrapper(pTree, pTree->isParseFinished, HtmlTreeAddText, HtmlTreeAddElement, HtmlTreeAddClosingTag ); break; } case HTML_WRITE_INHANDLERWAIT: pTree->eWriteState = HTML_WRITE_INHANDLER; break; } return TCL_OK; } tkHTML-4ee7aaa953d6cb59/src/htmlprop.c000064400000000000000000003327161151224263100167310ustar00nobodynobody /* * htmlprop.c --- * * This file implements the mapping between HTML attributes and CSS * properties. * *-------------------------------------------------------------------------- * Copyright (c) 2005 Eolas Technologies Inc. * All rights reserved. * * This Open Source project was made possible through the financial support * of Eolas Technologies Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ static const char rcsid[] = "$Id: htmlprop.c,v 1.135 2007/12/05 10:11:12 danielk1977 Exp $"; #include "html.h" #include #include #include #include /* #define ACCEPT_UNITLESS_LENGTHS */ #define LOG if (p->pTree->options.logcmd && p->pNode) /* * The properties table. This data structure describes the way in * which each individual property should be handled in the following * use cases: * * HtmlNodeGetProperty() - Format property value as string * HtmlNodeProperties() - Format property value as string * * HtmlComputedValuesCompare() - Compare property values and determine if * relayout or repainting is required by the * changes. * HtmlComputedValuesInit() - Initialise property value. * * HtmlComputedValuesRelease() - Delete ref to property value. * HtmlComputedValuesSet() - Set property value. */ enum PropertyValueType { ENUM, COLOR, LENGTH, IMAGE, BORDERWIDTH, COUNTERLIST, CUSTOM, AUTOINTEGER }; typedef struct PropertyDef PropertyDef; struct PropertyDef { enum PropertyValueType eType; int eProp; int iOffset; int mask; int iDefault; /* For LENGTH and BORDERWIDTH */ int setsizemask; /* If eType==LENGTH, mask for SetSize() */ int (*xSet)(HtmlComputedValuesCreator *, CssProperty *); Tcl_Obj *(*xObj)(HtmlComputedValues *); int isInherit; /* True to inherit by default */ int isNolayout; /* Can be changed without relayout */ }; #define PROPDEF(w, x, y) { \ w, CSS_PROPERTY_ ## x, Tk_Offset(HtmlComputedValues, y), 0 \ } #define PROPDEFM(w, x, y, z) { \ w, CSS_PROPERTY_ ## x, Tk_Offset(HtmlComputedValues, y), \ PROP_MASK_ ## x, z \ } static PropertyDef propdef[] = { PROPDEF(ENUM, BACKGROUND_ATTACHMENT, eBackgroundAttachment), PROPDEF(ENUM, BACKGROUND_REPEAT, eBackgroundRepeat), PROPDEF(ENUM, BORDER_BOTTOM_STYLE, eBorderBottomStyle), PROPDEF(ENUM, BORDER_LEFT_STYLE, eBorderLeftStyle), PROPDEF(ENUM, BORDER_RIGHT_STYLE, eBorderRightStyle), PROPDEF(ENUM, BORDER_TOP_STYLE, eBorderTopStyle), PROPDEF(ENUM, CLEAR, eClear), PROPDEF(ENUM, CURSOR, eCursor), PROPDEF(ENUM, DISPLAY, eDisplay), PROPDEF(ENUM, FLOAT, eFloat), PROPDEF(ENUM, LIST_STYLE_POSITION, eListStylePosition), PROPDEF(ENUM, LIST_STYLE_TYPE, eListStyleType), PROPDEF(ENUM, OUTLINE_STYLE, eOutlineStyle), PROPDEF(ENUM, OVERFLOW, eOverflow), PROPDEF(ENUM, POSITION, ePosition), PROPDEF(ENUM, TEXT_ALIGN, eTextAlign), PROPDEF(ENUM, TEXT_DECORATION, eTextDecoration), PROPDEF(ENUM, WHITE_SPACE, eWhitespace), PROPDEF(ENUM, BORDER_COLLAPSE, eBorderCollapse), PROPDEF(ENUM, DIRECTION, eDirection), PROPDEF(ENUM, CAPTION_SIDE, eCaptionSide), PROPDEF(ENUM, EMPTY_CELLS, eEmptyCells), PROPDEF(ENUM, FONT_VARIANT, eFontVariant), PROPDEF(ENUM, TABLE_LAYOUT, eTableLayout), PROPDEF(ENUM, TEXT_TRANSFORM, eTextTransform), PROPDEF(ENUM, UNICODE_BIDI, eUnicodeBidi), PROPDEF(ENUM, VISIBILITY, eVisibility), /* Note: The CSS2 property 'border-spacing' can be set to * either a single or pair of length values. Only a single * value is supported at the moment, which is enough to support * the html 4.01 cellspacing attribute. */ PROPDEFM(LENGTH, BORDER_SPACING, iBorderSpacing, 0), PROPDEFM(LENGTH, BACKGROUND_POSITION_X, iBackgroundPositionX, 0), PROPDEFM(LENGTH, BACKGROUND_POSITION_Y, iBackgroundPositionY, 0), PROPDEFM(LENGTH, BOTTOM, position.iBottom, PIXELVAL_AUTO), PROPDEFM(LENGTH, HEIGHT, iHeight, PIXELVAL_AUTO), PROPDEFM(LENGTH, LEFT, position.iLeft, PIXELVAL_AUTO), PROPDEFM(LENGTH, MARGIN_BOTTOM, margin.iBottom, 0), PROPDEFM(LENGTH, MARGIN_LEFT, margin.iLeft, 0), PROPDEFM(LENGTH, MARGIN_RIGHT, margin.iRight, 0), PROPDEFM(LENGTH, MARGIN_TOP, margin.iTop, 0), PROPDEFM(LENGTH, MAX_HEIGHT, iMaxHeight, PIXELVAL_NONE), PROPDEFM(LENGTH, MAX_WIDTH, iMaxWidth, PIXELVAL_NONE), PROPDEFM(LENGTH, MIN_HEIGHT, iMinHeight, 0), PROPDEFM(LENGTH, MIN_WIDTH, iMinWidth, 0), PROPDEFM(LENGTH, PADDING_BOTTOM, padding.iBottom, 0), PROPDEFM(LENGTH, PADDING_LEFT, padding.iLeft, 0), PROPDEFM(LENGTH, PADDING_RIGHT, padding.iRight, 0), PROPDEFM(LENGTH, PADDING_TOP, padding.iTop, 0), PROPDEFM(LENGTH, RIGHT, position.iRight, PIXELVAL_AUTO), PROPDEFM(LENGTH, TEXT_INDENT, iTextIndent, 0), PROPDEFM(LENGTH, TOP, position.iTop, PIXELVAL_AUTO), PROPDEFM(LENGTH, WIDTH, iWidth, PIXELVAL_AUTO), PROPDEFM(LENGTH, WORD_SPACING, iWordSpacing, PIXELVAL_NORMAL), PROPDEFM(LENGTH, LETTER_SPACING, iLetterSpacing, PIXELVAL_NORMAL), PROPDEF(COLOR, BACKGROUND_COLOR, cBackgroundColor), PROPDEF(COLOR, COLOR, cColor), PROPDEF(COLOR, BORDER_TOP_COLOR, cBorderTopColor), PROPDEF(COLOR, BORDER_RIGHT_COLOR, cBorderRightColor), PROPDEF(COLOR, BORDER_LEFT_COLOR, cBorderLeftColor), PROPDEF(COLOR, BORDER_BOTTOM_COLOR, cBorderBottomColor), PROPDEF(COLOR, OUTLINE_COLOR, cOutlineColor), PROPDEF(IMAGE, _TKHTML_REPLACEMENT_IMAGE, imReplacementImage), PROPDEF(IMAGE, BACKGROUND_IMAGE, imBackgroundImage), PROPDEF(IMAGE, LIST_STYLE_IMAGE, imListStyleImage), PROPDEFM(BORDERWIDTH, BORDER_TOP_WIDTH, border.iTop, 2), PROPDEFM(BORDERWIDTH, BORDER_LEFT_WIDTH, border.iLeft, 2), PROPDEFM(BORDERWIDTH, BORDER_RIGHT_WIDTH, border.iRight, 2), PROPDEFM(BORDERWIDTH, BORDER_BOTTOM_WIDTH, border.iBottom, 2), PROPDEFM(BORDERWIDTH, OUTLINE_WIDTH, iOutlineWidth, 2), PROPDEF(AUTOINTEGER, Z_INDEX, iZIndex), PROPDEF(AUTOINTEGER, _TKHTML_ORDERED_LIST_START, iOrderedListStart), PROPDEF(AUTOINTEGER, _TKHTML_ORDERED_LIST_VALUE, iOrderedListValue), PROPDEF(CUSTOM, VERTICAL_ALIGN, iVerticalAlign), PROPDEF(CUSTOM, LINE_HEIGHT, iLineHeight), PROPDEF(CUSTOM, FONT_SIZE, fFont), PROPDEF(CUSTOM, FONT_WEIGHT, fFont), PROPDEF(CUSTOM, FONT_FAMILY, fFont), PROPDEF(CUSTOM, FONT_STYLE, fFont), PROPDEF(CUSTOM, CONTENT, fFont), PROPDEF(COUNTERLIST, COUNTER_INCREMENT, clCounterIncrement), PROPDEF(COUNTERLIST, COUNTER_RESET, clCounterReset), }; #define SZ_AUTO 0x00000001 #define SZ_INHERIT 0x00000002 #define SZ_NONE 0x00000004 #define SZ_PERCENT 0x00000008 #define SZ_NEGATIVE 0x00000010 #define SZ_NORMAL 0x00000020 #define SZMASKDEF(x, y) { CSS_PROPERTY_ ## x, y } struct SizemaskDef { int eProp; int mask; } sizemskdef[] = { SZMASKDEF(BORDER_SPACING, 0), SZMASKDEF(BACKGROUND_POSITION_X, SZ_INHERIT|SZ_PERCENT|SZ_NEGATIVE), SZMASKDEF(BACKGROUND_POSITION_Y, SZ_INHERIT|SZ_PERCENT|SZ_NEGATIVE), SZMASKDEF(BOTTOM, SZ_INHERIT|SZ_PERCENT|SZ_AUTO|SZ_NEGATIVE), SZMASKDEF(HEIGHT, SZ_INHERIT|SZ_PERCENT|SZ_AUTO), SZMASKDEF(LEFT, SZ_INHERIT|SZ_PERCENT|SZ_AUTO|SZ_NEGATIVE), SZMASKDEF(MARGIN_BOTTOM, SZ_INHERIT|SZ_PERCENT|SZ_AUTO|SZ_NEGATIVE), SZMASKDEF(MARGIN_LEFT, SZ_INHERIT|SZ_PERCENT|SZ_AUTO|SZ_NEGATIVE), SZMASKDEF(MARGIN_RIGHT, SZ_INHERIT|SZ_PERCENT|SZ_AUTO|SZ_NEGATIVE), SZMASKDEF(MARGIN_TOP, SZ_INHERIT|SZ_PERCENT|SZ_AUTO|SZ_NEGATIVE), SZMASKDEF(MAX_HEIGHT, SZ_INHERIT|SZ_PERCENT|SZ_NONE), SZMASKDEF(MAX_WIDTH, SZ_INHERIT|SZ_PERCENT|SZ_NONE), SZMASKDEF(MIN_HEIGHT, SZ_INHERIT|SZ_PERCENT), SZMASKDEF(MIN_WIDTH, SZ_INHERIT|SZ_PERCENT), SZMASKDEF(PADDING_BOTTOM, SZ_INHERIT|SZ_PERCENT), SZMASKDEF(PADDING_LEFT, SZ_INHERIT|SZ_PERCENT), SZMASKDEF(PADDING_RIGHT, SZ_INHERIT|SZ_PERCENT), SZMASKDEF(PADDING_TOP, SZ_INHERIT|SZ_PERCENT), SZMASKDEF(RIGHT, SZ_INHERIT|SZ_PERCENT|SZ_AUTO|SZ_NEGATIVE), SZMASKDEF(TEXT_INDENT, SZ_INHERIT|SZ_PERCENT|SZ_NEGATIVE), SZMASKDEF(TOP, SZ_INHERIT|SZ_PERCENT|SZ_AUTO|SZ_NEGATIVE), SZMASKDEF(WIDTH, SZ_INHERIT|SZ_PERCENT|SZ_AUTO), SZMASKDEF(LETTER_SPACING, SZ_INHERIT|SZ_NORMAL|SZ_NEGATIVE), SZMASKDEF(WORD_SPACING, SZ_INHERIT|SZ_NORMAL|SZ_NEGATIVE), }; static int propertyValuesSetFontSize(HtmlComputedValuesCreator*,CssProperty*); static int propertyValuesSetLineHeight(HtmlComputedValuesCreator*,CssProperty*); static int propertyValuesSetVerticalAlign(HtmlComputedValuesCreator*,CssProperty*); static int propertyValuesSetFontStyle(HtmlComputedValuesCreator*,CssProperty*); static int propertyValuesSetFontFamily(HtmlComputedValuesCreator*,CssProperty*); static int propertyValuesSetFontWeight(HtmlComputedValuesCreator*,CssProperty*); static int propertyValuesSetContent(HtmlComputedValuesCreator*,CssProperty*); static int propertyValuesSetAutoInteger(HtmlComputedValuesCreator*,CssProperty*,int *); static Tcl_Obj *propertyValuesObjFontSize(HtmlComputedValues*); static Tcl_Obj *propertyValuesObjLineHeight(HtmlComputedValues*); static Tcl_Obj *propertyValuesObjVerticalAlign(HtmlComputedValues*); static Tcl_Obj *propertyValuesObjFontStyle(HtmlComputedValues*); static Tcl_Obj *propertyValuesObjFontFamily(HtmlComputedValues*); static Tcl_Obj *propertyValuesObjFontWeight(HtmlComputedValues*); static Tcl_Obj *propertyValuesObjContent(HtmlComputedValues*); #define CUSTOMDEF(x, y) {x, propertyValuesSet ## y, propertyValuesObj ## y} static struct CustomDef { int eProp; int (*xSet)(HtmlComputedValuesCreator *, CssProperty *); Tcl_Obj *(*xObj)(HtmlComputedValues *); } customdef[] = { CUSTOMDEF(CSS_PROPERTY_VERTICAL_ALIGN, VerticalAlign), CUSTOMDEF(CSS_PROPERTY_LINE_HEIGHT, LineHeight), CUSTOMDEF(CSS_PROPERTY_FONT_SIZE, FontSize), CUSTOMDEF(CSS_PROPERTY_FONT_WEIGHT, FontWeight), CUSTOMDEF(CSS_PROPERTY_FONT_STYLE, FontStyle), CUSTOMDEF(CSS_PROPERTY_FONT_FAMILY, FontFamily), CUSTOMDEF(CSS_PROPERTY_CONTENT, Content), }; static int inheritlist[] = { CSS_PROPERTY_LIST_STYLE_TYPE, CSS_PROPERTY_WHITE_SPACE, CSS_PROPERTY_TEXT_ALIGN, CSS_PROPERTY_COLOR, CSS_PROPERTY_BORDER_SPACING, CSS_PROPERTY_LINE_HEIGHT, CSS_PROPERTY_FONT_SIZE, CSS_PROPERTY_FONT_STYLE, CSS_PROPERTY_FONT_WEIGHT, CSS_PROPERTY_FONT_FAMILY, CSS_PROPERTY_TEXT_INDENT, CSS_PROPERTY_BORDER_COLLAPSE, CSS_PROPERTY_CAPTION_SIDE, CSS_PROPERTY_DIRECTION, CSS_PROPERTY_EMPTY_CELLS, CSS_PROPERTY_FONT_VARIANT, CSS_PROPERTY_LETTER_SPACING, CSS_PROPERTY_LIST_STYLE_IMAGE, CSS_PROPERTY_LIST_STYLE_TYPE, CSS_PROPERTY_LIST_STYLE_POSITION, CSS_PROPERTY_TEXT_TRANSFORM, CSS_PROPERTY_VISIBILITY, CSS_PROPERTY_WORD_SPACING, CSS_PROPERTY_CURSOR, CSS_PROPERTY_QUOTES }; static int nolayoutlist[] = { CSS_PROPERTY_TEXT_DECORATION, CSS_PROPERTY_BACKGROUND_ATTACHMENT, CSS_PROPERTY_BACKGROUND_REPEAT, CSS_PROPERTY_VISIBILITY, CSS_PROPERTY_BACKGROUND_POSITION_X, CSS_PROPERTY_BACKGROUND_POSITION_Y }; /* *--------------------------------------------------------------------------- * * getPropertyDef -- * * Results: * * Side effects: * This function is not threadsafe. * *--------------------------------------------------------------------------- */ static PropertyDef *getPropertyDef(int eProp){ static int isInit = 0; static PropertyDef *a[CSS_PROPERTY_MAX_PROPERTY+1]; assert(eProp >= 0); assert(eProp <= CSS_PROPERTY_MAX_PROPERTY); if (0 == isInit) { int i; memset(a, 0, (CSS_PROPERTY_MAX_PROPERTY+1) * sizeof(PropertyDef *)); for (i = 0; i < sizeof(propdef)/sizeof(PropertyDef); i++){ int eCss = propdef[i].eProp; assert(eCss >= 0 && eCss <= CSS_PROPERTY_MAX_PROPERTY); a[eCss] = &propdef[i]; } for (i = 0; i < sizeof(sizemskdef)/sizeof(struct SizemaskDef); i++){ a[sizemskdef[i].eProp]->setsizemask = sizemskdef[i].mask; } for (i = 0; i < sizeof(customdef)/sizeof(struct CustomDef); i++){ a[customdef[i].eProp]->xSet = customdef[i].xSet; a[customdef[i].eProp]->xObj = customdef[i].xObj; } for (i = 0; i < sizeof(inheritlist)/sizeof(int); i++){ if (a[inheritlist[i]]) { a[inheritlist[i]]->isInherit = 1; } } for (i = 0; i < sizeof(nolayoutlist)/sizeof(int); i++){ if (a[nolayoutlist[i]]) { a[nolayoutlist[i]]->isNolayout = 1; } } isInit = 1; } return a[eProp]; } /* *--------------------------------------------------------------------------- * * HtmlPropertyToString -- * * Return a pointer to a string representation of the CSS specified * value contained in argument pProp. *pzFree is set to the value * of a pointer (possibly NULL) that should be passed to HtmlFree(0, ) * when the returned string is no longer required. Example: * * char *zFree; * char *zString; * * zString = propertyToString(pProp, &zFree); * // Use zString for something (i.e. print to stdout) * HtmlFree(0, zFree); * * Results: * Pointer to string representation of property pProp. * * Side effects: * None. * *--------------------------------------------------------------------------- */ char * HtmlPropertyToString(pProp, pzFree) CssProperty *pProp; char **pzFree; { char *zRet = (char *)HtmlCssPropertyGetString(pProp); *pzFree = 0; if (!zRet) { if ( pProp->eType == CSS_TYPE_TCL || pProp->eType == CSS_TYPE_URL || pProp->eType == CSS_TYPE_ATTR ) { int nBytes = strlen(pProp->v.zVal) + 7; zRet = HtmlAlloc("HtmlPropertyToString()", nBytes); sprintf(zRet, "%s(%s)", (pProp->eType==CSS_TYPE_TCL)?"tcl": (pProp->eType==CSS_TYPE_URL)?"url": "attr", pProp->v.zVal ); } else if (pProp->eType == CSS_TYPE_LIST) { return "List"; } else { char *zSym = 0; char *zFunc = 0; switch (pProp->eType) { case CSS_TYPE_EM: zSym = "em"; break; case CSS_TYPE_PX: zSym = "px"; break; case CSS_TYPE_PT: zSym = "pt"; break; case CSS_TYPE_PC: zSym = "pc"; break; case CSS_TYPE_EX: zSym = "ex"; break; case CSS_TYPE_PERCENT: zSym = "%"; break; case CSS_TYPE_FLOAT: zSym = ""; break; case CSS_TYPE_CENTIMETER: zSym = "cm"; break; case CSS_TYPE_INCH: zSym = "in"; break; case CSS_TYPE_MILLIMETER: zSym = "mm"; break; case CSS_TYPE_ATTR: zFunc = "attr"; break; case CSS_TYPE_COUNTER: zFunc = "counter"; break; case CSS_TYPE_COUNTERS: zFunc = "counters"; break; default: assert(!"Unknown CssProperty.eType value"); } if (zSym) { zRet = HtmlAlloc("HtmlPropertyToString()", 128); sprintf(zRet, "%.2f%s", pProp->v.rVal, zSym); } else if (zFunc) { zRet = HtmlAlloc("HtmlPropertyToString()", strlen(zFunc) + strlen(pProp->v.zVal) + 3 ); sprintf(zRet, "%s(%s)", zFunc, pProp->v.zVal); } } *pzFree = zRet; } return zRet; } /* *--------------------------------------------------------------------------- * * pixelsToPoints -- * * Convert a pixel length to points (1/72 of an inch). * * Note: An "inch" is an anachronism still in use in some of the more * stubborn countries. It is equivalent to approximately 25.4 * millimeters. * * Results: * Integer length in points. * * Side effects: * None. * *--------------------------------------------------------------------------- */ static float pixelsToPoints(p, pixels) HtmlComputedValuesCreator *p; int pixels; { double mm; Tcl_Obj *pObj = Tcl_NewIntObj(pixels); Tcl_IncrRefCount(pObj); Tk_GetMMFromObj(p->pTree->interp, p->pTree->tkwin, pObj, &mm); Tcl_DecrRefCount(pObj); return (mm * 72.0 / 25.4); } /* *--------------------------------------------------------------------------- * * physicalToPixels -- * * This function is a wrapper around Tk_GetPixels(), used to convert * physical units to pixels. The first argument is the layout-context. * The second argument is the distance in terms of the physical unit * being converted from. The third argument determines the unit type, * as follows: * * Character Unit * ------------------------------ * 'c' Centimeters * 'i' Inches * 'm' Millimeters * 'p' Points (1 point = 1/72 inches) * * The value returned is the distance in pixels. * * Results: * None. * * Side effects: * None. * *--------------------------------------------------------------------------- */ static int physicalToPixels(p, rVal, type) HtmlComputedValuesCreator *p; double rVal; char type; { char zBuf[64]; int pixels; sprintf(zBuf, "%f%c", rVal, type); Tk_GetPixels(p->pTree->interp, p->pTree->tkwin, zBuf, &pixels); return pixels; } /* *--------------------------------------------------------------------------- * * propertyValuesSetFontStyle -- * * Keywords 'italic' and 'oblique' map to a Tk italic font. Keyword * 'normal' maps to a non-italic font. Any other property value is * rejected as a type-mismatch. * * Results: * 0 if value is successfully set. 1 if the value of *pProp is not a valid * a value for the 'font-style' property. * * Side effects: * *--------------------------------------------------------------------------- */ static int propertyValuesSetFontStyle(p, pProp) HtmlComputedValuesCreator *p; CssProperty *pProp; { int eType = pProp->eType; if (eType == CSS_CONST_INHERIT) { int i = HtmlNodeComputedValues(p->pParent)->fFont->pKey->isItalic;; p->fontKey.isItalic = i; }else if (eType == CSS_CONST_ITALIC || eType == CSS_CONST_OBLIQUE) { p->fontKey.isItalic = 1; } else if (eType == CSS_CONST_NORMAL) { p->fontKey.isItalic = 0; } else { return 1; } return 0; } static int propertyValuesSetEnum(HtmlComputedValuesCreator *, unsigned char*, unsigned char *, CssProperty *); static int contentCounter(pTree, pProp, zOut, nOut) HtmlTree *pTree; CssProperty *pProp; char *zOut; int nOut; { const char *zCounter; int nCounter; const char *zStyle; int nStyle; CssProperty *pCounter; int iValue; unsigned char eStyle = CSS_CONST_DECIMAL; zCounter = HtmlCssGetNextCommaListItem(pProp->v.zVal, -1, &nCounter); zStyle = HtmlCssGetNextCommaListItem(&zCounter[nCounter], -1, &nStyle); pCounter = HtmlCssStringToProperty(zCounter, nCounter); if (zStyle) { CssProperty *pStyle; unsigned char *options; options = HtmlCssEnumeratedValues(CSS_PROPERTY_LIST_STYLE_TYPE); pStyle = HtmlCssStringToProperty(zStyle, nStyle); if (propertyValuesSetEnum(0, &eStyle, options, pStyle)) { /* Unknown style type */ return 1; } HtmlFree(pStyle); } zCounter = HtmlCssPropertyGetString(pCounter); iValue = HtmlStyleCounter(pTree, zCounter); HtmlLayoutMarkerBox(eStyle, iValue, 0, zOut); HtmlFree(pCounter); return 0; } static int contentCounters(pTree, pProp, zOut, nOut) HtmlTree *pTree; CssProperty *pProp; char *zOut; int nOut; { const char *zCounter; int nCounter; const char *zStyle; int nStyle; const char *zSep; int nSep; CssProperty *pCounter; CssProperty *pSep; unsigned char eStyle = CSS_CONST_DECIMAL; int aValue[128]; int nValue; int ii; zCounter = HtmlCssGetNextCommaListItem(pProp->v.zVal, -1, &nCounter); zSep = HtmlCssGetNextCommaListItem(&zCounter[nCounter], -1, &nSep); zStyle = HtmlCssGetNextCommaListItem(&zSep[nSep], -1, &nStyle); pCounter = HtmlCssStringToProperty(zCounter, nCounter); pSep = HtmlCssStringToProperty(zSep, nSep); zCounter = HtmlCssPropertyGetString(pCounter); if (!zCounter || !pSep || pSep->eType != CSS_TYPE_STRING) { HtmlFree(pCounter); HtmlFree(pSep); return 1; } zSep = HtmlCssPropertyGetString(pSep); if (zStyle) { CssProperty *pStyle; unsigned char *options; options = HtmlCssEnumeratedValues(CSS_PROPERTY_LIST_STYLE_TYPE); pStyle = HtmlCssStringToProperty(zStyle, nStyle); propertyValuesSetEnum(0, &eStyle, options, pStyle); HtmlFree(pStyle); } nValue = HtmlStyleCounters(pTree, zCounter, aValue, 128); assert(nValue > 0); /* Otherwise zOut[] will never be initialized */ for (ii = 0; ii < nValue; ii++) { if (ii != 0) { strcat(zOut, zSep); zOut = &zOut[strlen(zOut)]; } HtmlLayoutMarkerBox(eStyle, aValue[ii], 0, zOut); zOut = &zOut[strlen(zOut)]; } HtmlFree(pCounter); HtmlFree(pSep); return 0; } static int propertyValuesSetContent(p, pProp) HtmlComputedValuesCreator *p; CssProperty *pProp; { if (p->pzContent) { p->pContent = pProp; } return 0; } static void propertyValuesCalculateContent(p) HtmlComputedValuesCreator *p; { int ii; int nOut = 0; char *zOut = 0; CssProperty *pProp = p->pContent; CssProperty **apProp; assert(p->pzContent); assert(pProp->eType == CSS_TYPE_LIST); apProp = (CssProperty **)pProp->v.p; for (ii = 0; apProp[ii]; ii++) { char zCounter[512]; const char *z = 0; switch (apProp[ii]->eType) { case CSS_TYPE_STRING: z = apProp[ii]->v.zVal; break; case CSS_TYPE_ATTR: z = HtmlNodeAttr(p->pNode, apProp[ii]->v.zVal); break; case CSS_TYPE_COUNTER: contentCounter(p->pTree, apProp[ii], zCounter, 512); z = zCounter; break; case CSS_TYPE_COUNTERS: contentCounters(p->pTree, apProp[ii], zCounter, 512); z = zCounter; break; } if (z) { int n = strlen(z); zOut = HtmlRealloc("zContent", zOut, nOut + n + 1); strcpy(&zOut[nOut], z); nOut += n; } } *(p->pzContent) = zOut; } /* *--------------------------------------------------------------------------- * * propertyValuesSetAutoInteger -- * * Set the value of the 'z-index' property (either an integer or "auto"). * This procedure is also used for the custom Tkhtml3 properties: * * -tkhtml-ordered-list-start * -tkhtml-ordered-list-value * * Results: * 0 if value is successfully set. 1 if the value of *pProp is not a valid * a value for the 'font-weight' property. * * Side effects: * *--------------------------------------------------------------------------- */ static int propertyValuesSetAutoInteger(p, pProp, piVal) HtmlComputedValuesCreator *p; CssProperty *pProp; int *piVal; { if (pProp->eType == CSS_TYPE_FLOAT) { *piVal = (int)pProp->v.rVal; }else if (pProp->eType == CSS_CONST_AUTO) { *piVal = PIXELVAL_AUTO; }else{ /* Type mismatch */ return 1; } return 0; } /* *--------------------------------------------------------------------------- * * propertyValuesSetFontWeight -- * * Keywords 'bold' and 'bolder', and numeric values greater than 550 map to * a Tk bold font. Keywords 'normal' and 'lighter', along with numeric * values less than 550 map to a non-bold font. Any other property value is * rejected as a type-mismatch. * * Results: * 0 if value is successfully set. 1 if the value of *pProp is not a valid * a value for the 'font-weight' property. * * Side effects: * *--------------------------------------------------------------------------- */ static int propertyValuesSetFontWeight(p, pProp) HtmlComputedValuesCreator *p; CssProperty *pProp; { int eType = pProp->eType; if (eType == CSS_CONST_INHERIT) { HtmlNode *pParent = p->pParent; if (pParent) { int i = HtmlNodeComputedValues(pParent)->fFont->pKey->isBold; p->fontKey.isBold = i; } } else if ( eType == CSS_CONST_BOLD || eType == CSS_CONST_BOLDER || (eType == CSS_TYPE_FLOAT && pProp->v.rVal > 550.0) ) { p->fontKey.isBold = 1; } else if ( eType == CSS_CONST_NORMAL || eType == CSS_CONST_LIGHTER || (eType == CSS_TYPE_FLOAT && pProp->v.rVal < 550.0) ) { p->fontKey.isBold = 0; } else { return 1; } return 0; } /* *--------------------------------------------------------------------------- * * propertyValuesSetFontFamily -- * * Just copy the pointer, not the string. * * Results: * 0 if value is successfully set. 1 if the value of *pProp is not a valid * a value for the 'font-family' property. * * Side effects: * *--------------------------------------------------------------------------- */ static int propertyValuesSetFontFamily(p, pProp) HtmlComputedValuesCreator *p; CssProperty *pProp; { const char *z; /* Handle 'inherit' */ if (pProp->eType == CSS_CONST_INHERIT) { HtmlNode *pParent = p->pParent; if (pParent) { z = HtmlNodeComputedValues(pParent)->fFont->pKey->zFontFamily; p->fontKey.zFontFamily = z; } return 0; } z = HtmlCssPropertyGetString(pProp); if (!z) { return 1; } p->fontKey.zFontFamily = z; return 0; } static Tcl_Obj* propertyValuesObjFontSize(p) HtmlComputedValues *p; { char zBuf[64]; int iFontSize = p->fFont->pKey->iFontSize; if (iFontSize >= 0) { sprintf(zBuf, "%.3fpts", (float)iFontSize / HTML_IFONTSIZE_SCALE); } else { sprintf(zBuf, "%dpx", -1 * iFontSize / HTML_IFONTSIZE_SCALE); } return Tcl_NewStringObj(zBuf, -1); } static Tcl_Obj* propertyValuesObjFontStyle(p) HtmlComputedValues *p; { if (p->fFont->pKey->isItalic) { return Tcl_NewStringObj("italic", -1); } return Tcl_NewStringObj("normal", -1); } static Tcl_Obj* propertyValuesObjFontFamily(p) HtmlComputedValues *p; { return Tcl_NewStringObj(p->fFont->pKey->zFontFamily, -1); } static Tcl_Obj* propertyValuesObjFontWeight(p) HtmlComputedValues *p; { if (p->fFont->pKey->isBold) { return Tcl_NewStringObj("bold", -1); } return Tcl_NewStringObj("normal", -1); } static Tcl_Obj* propertyValuesObjContent(p) HtmlComputedValues *p; { return Tcl_NewStringObj("", -1); } static Tcl_Obj* propertyValuesObjLineHeight(p) HtmlComputedValues *p; { char zBuf[64]; int iVal = p->iLineHeight; assert(0 == (p->mask & PROP_MASK_LINE_HEIGHT)); if (iVal == PIXELVAL_NORMAL) { sprintf(zBuf, "normal"); } else if (iVal < 0) { sprintf(zBuf, "%.2f", (float)iVal * -0.01); } else { sprintf(zBuf, "%dpx", iVal); } return Tcl_NewStringObj(zBuf, -1); } static Tcl_Obj* propertyValuesObjVerticalAlign(p) HtmlComputedValues *p; { char zBuf[64]; if (p->eVerticalAlign) { CONST char *zValue = HtmlCssConstantToString(p->eVerticalAlign); return Tcl_NewStringObj(zValue, -1); } sprintf(zBuf, "%dpx", p->iVerticalAlign); return Tcl_NewStringObj(zBuf, -1); } static int normalizeFontSize(p, pNode) HtmlComputedValuesCreator *p; HtmlNode *pNode; { int iFontSize = HtmlNodeComputedValues(pNode)->fFont->pKey->iFontSize; if (iFontSize >= 0) { return iFontSize; } else { return pixelsToPoints(p, iFontSize * -1); } } /* *--------------------------------------------------------------------------- * * propertyValuesSetFontSize -- * * This function sets the HtmlComputedValuesCreator.fontKey.iFontSize * variable in *p based on the value stored in property *pProp. This * function handles the value 'inherit'. * * Results: * 0 if value is successfully set. 1 if the value of *pProp is not a valid * a value for the 'font-size' property. * * Side effects: * *--------------------------------------------------------------------------- */ static int propertyValuesSetFontSize(p, pProp) HtmlComputedValuesCreator *p; CssProperty *pProp; { int iPoints = 0; int iPixels = 0; double iScale = -1.0; assert(pProp); /* Handle 'inherit' separately. */ if (pProp->eType == CSS_CONST_INHERIT) { HtmlNode *pParent = p->pParent; if (pParent) { int i = HtmlNodeComputedValues(pParent)->fFont->pKey->iFontSize; p->fontKey.iFontSize = i; } return 0; } switch (pProp->eType) { /* Font-size is in terms of parent node font size */ case CSS_TYPE_EM: iScale = (double)pProp->v.rVal; break; case CSS_TYPE_EX: { HtmlNode *pParent = p->pParent; if (pParent) { HtmlFont *pFont = HtmlNodeComputedValues(pParent)->fFont; iScale = (double)pProp->v.rVal * ((double)(pFont->ex_pixels) / (double)(pFont->em_pixels)); } else { iScale = 1.0; /* Just to prevent type-mismatch error */ } break; } case CSS_TYPE_PERCENT: iScale = pProp->v.rVal * 0.01; break; case CSS_CONST_SMALLER: { HtmlNode *pParent = p->pParent; if (pParent) { int ii; int *aSize = p->pTree->aFontSizeTable; int ps = normalizeFontSize(p, pParent); int points = ps / HTML_IFONTSIZE_SCALE; for (ii = 1; ii < 7 && aSize[ii] < points; ii++); iPoints = ps + (aSize[ii-1] - aSize[ii]) * HTML_IFONTSIZE_SCALE; } else { iPoints = p->pTree->aFontSizeTable[2] * HTML_IFONTSIZE_SCALE; } break; } case CSS_CONST_LARGER: { HtmlNode *pParent = p->pParent; if (pParent) { int ii; int *aSize = p->pTree->aFontSizeTable; int ps = normalizeFontSize(p, pParent); int points = ps / HTML_IFONTSIZE_SCALE; for (ii = 0; ii < 6 && aSize[ii] < points; ii++); iPoints = ps + (aSize[ii+1] - aSize[ii]) * HTML_IFONTSIZE_SCALE; } else { iPoints = p->pTree->aFontSizeTable[2] * HTML_IFONTSIZE_SCALE; } break; } /* Font-size is in terms of the font-size table */ case CSS_CONST_XX_SMALL: iPoints = p->pTree->aFontSizeTable[0]; iPoints = iPoints * HTML_IFONTSIZE_SCALE; break; case CSS_CONST_X_SMALL: iPoints = p->pTree->aFontSizeTable[1]; iPoints = iPoints * HTML_IFONTSIZE_SCALE; break; case CSS_CONST_SMALL: iPoints = p->pTree->aFontSizeTable[2]; iPoints = iPoints * HTML_IFONTSIZE_SCALE; break; case CSS_CONST_MEDIUM: iPoints = p->pTree->aFontSizeTable[3]; iPoints = iPoints * HTML_IFONTSIZE_SCALE; break; case CSS_CONST_LARGE: iPoints = p->pTree->aFontSizeTable[4]; iPoints = iPoints * HTML_IFONTSIZE_SCALE; break; case CSS_CONST_X_LARGE: iPoints = p->pTree->aFontSizeTable[5]; iPoints = iPoints * HTML_IFONTSIZE_SCALE; break; case CSS_CONST_XX_LARGE: iPoints = p->pTree->aFontSizeTable[6]; iPoints = iPoints * HTML_IFONTSIZE_SCALE; break; /* Font-size is in physical units (except points or picas) */ case CSS_TYPE_CENTIMETER: iPixels = physicalToPixels(p, pProp->v.rVal, 'c'); break; case CSS_TYPE_MILLIMETER: iPixels = physicalToPixels(p, pProp->v.rVal, 'm'); break; case CSS_TYPE_INCH: iPixels = physicalToPixels(p, pProp->v.rVal, 'i'); break; /* Font-size is in pixels */ case CSS_TYPE_PX: iPixels = INTEGER(pProp->v.rVal); break; /* Font-size is already in points or picas*/ case CSS_TYPE_PC: iPoints = (int)(pProp->v.rVal * HTML_IFONTSIZE_SCALE / 12.0); break; case CSS_TYPE_PT: iPoints = INTEGER(HTML_IFONTSIZE_SCALE * pProp->v.rVal); break; default: /* Type-mismatch error */ return 1; } if (iPixels > 0) { p->fontKey.iFontSize = HTML_IFONTSIZE_SCALE * iPixels * -1; } else if (iPoints > 0) { p->fontKey.iFontSize = iPoints; } else if (iScale > 0.0) { HtmlNode *pParent = p->pParent; if (pParent) { HtmlFont *pFont = HtmlNodeComputedValues(pParent)->fFont; p->fontKey.iFontSize = pFont->pKey->iFontSize * iScale; } } else { return 1; } return 0; } static unsigned char * getInheritPointer(p, pVar) HtmlComputedValuesCreator *p; unsigned char *pVar; { const int values_offset = Tk_Offset(HtmlComputedValuesCreator, values); const int fontkey_offset = Tk_Offset(HtmlComputedValuesCreator, fontKey); const int values_end = values_offset + sizeof(HtmlComputedValues); #ifndef NDEBUG const int fontkey_end = fontkey_offset + sizeof(HtmlFontKey); #endif int offset = pVar - (unsigned char *)p; HtmlNode *pParent = p->pParent; assert( values_offset >= 0 && fontkey_offset >= 0 && values_end > 0 && values_end > values_offset && fontkey_end > 0 && fontkey_end > fontkey_offset ); assert(offset >= 0); assert( (offset >= values_offset && offset < values_end) || (offset >= fontkey_offset && offset < fontkey_end) ); if (pParent) { unsigned char *pV; if (offset >= values_offset && offset < values_end) { pV = (unsigned char *)HtmlNodeComputedValues(pParent); assert(pV); return (pV + (offset - values_offset)); } else { pV = (unsigned char *)HtmlNodeComputedValues(pParent)->fFont->pKey; assert(pV); return (pV + (offset - fontkey_offset)); } } return 0; } /* *--------------------------------------------------------------------------- * * propertyValuesSetEnum -- * * aOptions is a 0-terminated list of uchars (all CSS_CONST_XXX values). * If pProp contains a constant string that matches an entry in aOptions, * copy the constant value to *pEVar and return 0. Otherwise return 1 and * leave *pEVar untouched. * * Results: * See above. * * Side effects: * May copy pProp->eType to *pEVar. * *--------------------------------------------------------------------------- */ static int propertyValuesSetEnum(p, pEVar, aOptions, pProp) HtmlComputedValuesCreator *p; unsigned char *pEVar; unsigned char *aOptions; CssProperty *pProp; { int val = pProp->eType; unsigned char *pOpt; if (val == CSS_CONST_INHERIT) { unsigned char *pInherit = getInheritPointer(p, pEVar); if (pInherit) { *pEVar = *pInherit; } return 0; } for (pOpt = aOptions; *pOpt; pOpt++) { if (*pOpt == val) { *pEVar = (unsigned char)val; return 0; } } return 1; } static void decrementColorRef(pTree, pColor) HtmlTree *pTree; HtmlColor *pColor; { if (pColor) { pColor->nRef--; assert(pColor->nRef >= 0); if (pColor->nRef == 0) { Tcl_HashEntry *pEntry; pEntry = Tcl_FindHashEntry(&pTree->aColor, pColor->zColor); Tcl_DeleteHashEntry(pEntry); if (pColor->xcolor) { Tk_FreeColor(pColor->xcolor); } HtmlFree(pColor); } } } #ifndef NDEBUG static int dumpColorTable(pTree) HtmlTree *pTree; { Tcl_HashSearch search; Tcl_HashEntry *pEntry; int iRet = 0; for ( pEntry = Tcl_FirstHashEntry(&pTree->aColor, &search); pEntry; pEntry = Tcl_NextHashEntry(&search) ) { HtmlColor *pColor = Tcl_GetHashValue(pEntry); printf("%s -> {%s (%d) %p}\n", Tcl_GetHashKey(&pTree->aColor, pEntry), pColor->zColor, pColor->nRef, pColor->xcolor ); iRet++; } return iRet; } #endif /* *--------------------------------------------------------------------------- * * propertyValuesSetColor -- * * Css property pProp contains a color-name. Set *pCVar (part of an * HtmlComputedValues structure) to point to the corresponding entry in the * pTree->aColor array. The entry may be created if required. * * Results: * 0 if *pCVar is set correctly. If pProp cannot be parsed as a color name, * 1 is returned and *pCVar remains unmodified. * * Side effects: * May set *pCVar. * *--------------------------------------------------------------------------- */ static int propertyValuesSetColor(p, pCVar, pProp) HtmlComputedValuesCreator *p; HtmlColor **pCVar; CssProperty *pProp; { Tcl_HashEntry *pEntry; int newEntry = 0; CONST char *zColor; HtmlColor *cVal = 0; HtmlTree *pTree = p->pTree; if (pProp->eType == CSS_CONST_INHERIT) { HtmlColor **pInherit = (HtmlColor **)getInheritPointer(p, pCVar); assert(pInherit); cVal = *pInherit; goto setcolor_out; } if (pProp->eType == CSS_CONST__TKHTML_NO_COLOR) { goto setcolor_out; } /* According to CSS2.1, a color value must be either one of the * keyword colors, or a numeric color specification. We modify * this slightly so that any Tk color can be used as a keyword (but * not as a string). */ if (pProp->eType == CSS_TYPE_STRING) { return 1; } zColor = HtmlCssPropertyGetString(pProp); if (!zColor || !zColor[0]) return 1; pEntry = Tcl_CreateHashEntry(&pTree->aColor, zColor, &newEntry); if (newEntry) { XColor *color; if (zColor[0] == '#' && strlen(zColor) == 4) { /* Tk interprets a color value of "#ABC" as the same as "#A0B0C0". * But CSS implementations generally assume that it is equivalent * to "#AABBCC". */ char zBuf[8]; zBuf[0] = '#'; zBuf[1] = zColor[1]; zBuf[2] = zColor[1]; zBuf[3] = zColor[2]; zBuf[4] = zColor[2]; zBuf[5] = zColor[3]; zBuf[6] = zColor[3]; zBuf[7] = '\0'; color = Tk_GetColor(pTree->interp, pTree->tkwin, zBuf); } else { color = Tk_GetColor(pTree->interp, pTree->tkwin, zColor); } if (!color && strlen(zColor) <= 12) { /* Old versions of netscape used to support hex colors * without the '#' character (i.e. "FFF" is the same as * "#FFF"). So naturally this has become a defacto standard, even * though it is obviously wrong. At any rate, if Tk_GetColor() * cannot parse the color-name as it stands, put a '#' character in * front of it and give it another go. */ char zBuf[14]; sprintf(zBuf, "#%s", zColor); color = Tk_GetColor(pTree->interp, pTree->tkwin, zBuf); } if (color) { cVal = (HtmlColor *)HtmlAlloc( "HtmlColor", sizeof(HtmlColor)+strlen(zColor)+1 ); cVal->nRef = 0; cVal->xcolor = color; cVal->zColor = (char *)(&cVal[1]); strcpy(cVal->zColor, zColor); Tcl_SetHashValue(pEntry, cVal); } else { Tcl_DeleteHashEntry(pEntry); return 1; } } else { cVal = (HtmlColor *)Tcl_GetHashValue(pEntry); } setcolor_out: assert(cVal || pProp->eType == CSS_CONST__TKHTML_NO_COLOR); if (cVal) { cVal->nRef++; } if (*pCVar) { decrementColorRef(pTree, *pCVar); } *pCVar = cVal; return 0; } static int propertyValuesSetCounterList(p, ppCL, eProp, pProp) HtmlComputedValuesCreator *p; HtmlCounterList **ppCL; int eProp; CssProperty *pProp; { int nByte = 0; int nCounter = 0; int nCounter2 = 0; int ii; CssProperty **ap; HtmlCounterList *pRet; char *zOut; /* Property should always be a list. */ if (pProp->eType != CSS_TYPE_LIST) return 1; ap = (CssProperty **)(pProp->v.p); /* Figure out the number of counters and the amount of space required * to store everything. */ for (ii = 0; ap[ii]; ii++) { if (ap[ii]->eType == CSS_TYPE_RAW) { nByte += (strlen(ap[ii]->v.zVal) + 1); nCounter++; } else { return 1; } if (ap[ii + 1] && ap[ii + 1]->eType == CSS_TYPE_FLOAT) { ii++; } } nByte += sizeof(HtmlCounterList); nByte += nCounter * (sizeof(int *) + sizeof(char *)); pRet = (HtmlCounterList *)HtmlAlloc("HtmlCounterList", nByte); pRet->nRef = 0; pRet->nCounter = nCounter; pRet->azCounter = (char **)&pRet[1]; pRet->anValue = (int *)&pRet->azCounter[nCounter]; zOut = (char *)&pRet->anValue[nCounter]; for (ii = 0; ap[ii]; ii++) { int n; assert(ap[ii]->eType == CSS_TYPE_RAW); n = (strlen(ap[ii]->v.zVal) + 1); memcpy(zOut, ap[ii]->v.zVal, n); pRet->azCounter[nCounter2] = zOut; zOut += n; if (ap[ii + 1] && ap[ii + 1]->eType == CSS_TYPE_FLOAT) { pRet->anValue[nCounter2] = INTEGER(ap[ii + 1]->v.rVal); ii++; } else if (eProp == CSS_PROPERTY_COUNTER_INCREMENT) { pRet->anValue[nCounter2] = 1; } else { pRet->anValue[nCounter2] = 0; } nCounter2++; } assert(nCounter2 == nCounter); *ppCL = pRet; return 0; } static void decrementCounterListRef(pCounterList) HtmlCounterList *pCounterList; { HtmlFree(pCounterList); } /* *--------------------------------------------------------------------------- * * propertyValuesSetLength -- * * This function attempts to interpret *pProp as a CSS . A * is a numeric quantity with one of the following units: * * em: font-size of the relevant font * ex: x-height of the relevant font * px: pixels * in: inches * cm: centimeters * mm: millimeters * pt: points * pc: picas * * If the widget mode is "quirks", then an integer without units is * considered to be in pixels. If the mode is "standards" or "almost * standards", then a number without any units is a type mismatch for a * length. * * If *pProp is not a numeric quantity with one of the above units, 1 is * returned and *pIVar is not written. * * If *pProp is an 'em' or 'ex' value, then *pIVar is set to the numeric * value of the property * 100.0 and the em_mask bit in either p->em_mask * or p->ex_mask is set. If an 'em' or 'ex' value is encountered but * (em_mask==0), then 1 is returned and *pIVar is not written. * * Note that unlike most of the other propertyValuesSetXXX() functions, * this function does *not* handle the value 'inherit'. * * * Results: * If successful, 0 is returned. If pProp cannot be parsed as a 1 * is returned and *pIVar remains unmodified. * * Side effects: * May set *pIVar, may modify p->em_mask or p->ex_mask. * *--------------------------------------------------------------------------- */ static int propertyValuesSetLength(p, pIVal, em_mask, pProp, allowNegative) HtmlComputedValuesCreator *p; int *pIVal; unsigned int em_mask; CssProperty *pProp; int allowNegative; { int iVal; double rZoomedVal = pProp->v.rVal * p->pTree->options.zoom; switch (pProp->eType) { case CSS_TYPE_EM: if (em_mask == 0) return 1; iVal = (int)(pProp->v.rVal * 100.0); break; case CSS_TYPE_EX: if (em_mask == 0) return 1; iVal = (int)(pProp->v.rVal * 100.0); break; case CSS_TYPE_PX: iVal = INTEGER(rZoomedVal); break; case CSS_TYPE_PT: iVal = physicalToPixels(p, rZoomedVal, 'p'); break; case CSS_TYPE_PC: iVal = physicalToPixels(p, rZoomedVal * 12.0, 'p'); break; case CSS_TYPE_CENTIMETER: iVal = physicalToPixels(p, rZoomedVal, 'c'); break; case CSS_TYPE_INCH: iVal = physicalToPixels(p, rZoomedVal, 'i'); break; case CSS_TYPE_MILLIMETER: iVal = physicalToPixels(p, rZoomedVal, 'm'); break; case CSS_TYPE_FLOAT: { /* There are two cases where a unitless number is a legal * value for a CSS %length%. Other than the following, it * is a type mismatch: * * 1. From section 4.3.2 of CSS 2.1: "After a zero length, * the unit identifier is optional.". * 2. In quirks mode, no unit means pixels. */ iVal = INTEGER(rZoomedVal); if (iVal && p->pTree->options.mode != HTML_MODE_QUIRKS) return 1; break; } default: return 1; } if (iVal < MAX_PIXELVAL || iVal >= 0 || allowNegative) { *pIVal = iVal; if (pProp->eType == CSS_TYPE_EM) { p->em_mask |= em_mask; } else if (pProp->eType == CSS_TYPE_EX) { p->ex_mask |= em_mask; } } else { return 1; } return 0; } /* *--------------------------------------------------------------------------- * * propertyValuesSetLineHeight -- * * Results: * 0 if value is successfully set. 1 if the value of *pProp is not a valid * a value for the 'line-height' property. * * Side effects: * *--------------------------------------------------------------------------- */ static int propertyValuesSetLineHeight(p, pProp) HtmlComputedValuesCreator *p; CssProperty *pProp; { int rc = 1; switch (pProp->eType) { case CSS_CONST_INHERIT: { p->values.iLineHeight = HtmlNodeComputedValues(p->pParent)->iLineHeight; rc = 0; break; } case CSS_CONST_NORMAL: { /* p->values.iLineHeight = -100; */ p->values.iLineHeight = PIXELVAL_NORMAL; rc = 0; break; } case CSS_TYPE_PERCENT: { int iVal = INTEGER(pProp->v.rVal); if (iVal > 0) { p->values.iLineHeight = iVal; p->em_mask |= PROP_MASK_LINE_HEIGHT; rc = 0; } break; } case CSS_TYPE_FLOAT: { double rVal = pProp->v.rVal; if (rVal > 0) { rc = 0; p->values.iLineHeight = (-100.0 * rVal); } break; } default: { /* Try to treat the property as a */ int i = p->values.iLineHeight; int *pIVal = &p->values.iLineHeight; rc = propertyValuesSetLength(p,pIVal,PROP_MASK_LINE_HEIGHT,pProp,0); if (*pIVal < 0) { rc = 1; *pIVal = i; } break; } } return rc; } /* *--------------------------------------------------------------------------- * * propertyValuesSetImage -- * * Results: * 0 if value is successfully set. 1 if the value of *pProp is not a valid * value for an image property. * * Side effects: * *--------------------------------------------------------------------------- */ static int propertyValuesSetImage(p, pImVar, pProp) HtmlComputedValuesCreator *p; HtmlImage2 **pImVar; CssProperty *pProp; { HtmlImage2 *pNew = 0; CONST char *zUrl = 0; switch (pProp->eType) { case CSS_CONST_INHERIT: { unsigned char *v = (unsigned char *)pImVar; HtmlImage2 **pInherit = (HtmlImage2 **)getInheritPointer(p, v); *pImVar = *pInherit; HtmlImageRef(*pImVar); return 0; } case CSS_CONST_NONE: break; case CSS_TYPE_URL: case CSS_TYPE_STRING: case CSS_TYPE_RAW: zUrl = pProp->v.zVal; break; default: return 1; } if (zUrl) { pNew = HtmlImageServerGet(p->pTree->pImageServer, zUrl); } if (*pImVar) { HtmlImageFree(*pImVar); } *pImVar = pNew; return 0; } /* *--------------------------------------------------------------------------- * * propertyValuesSetVerticalAlign -- * * Results: * 0 if value is successfully set. 1 if the value of *pProp is not a valid * a value for the 'vertical-align' property. * * Side effects: * *--------------------------------------------------------------------------- */ static int propertyValuesSetVerticalAlign(p, pProp) HtmlComputedValuesCreator *p; CssProperty *pProp; { static const unsigned int MASK = PROP_MASK_VERTICAL_ALIGN; int rc = 0; switch (pProp->eType) { case CSS_CONST_INHERIT: { HtmlNode *pParent = p->pParent; HtmlComputedValues *pPV; pPV = HtmlNodeComputedValues(pParent); assert(pPV); p->values.iVerticalAlign = pPV->iVerticalAlign; p->values.eVerticalAlign = pPV->eVerticalAlign; p->eVerticalAlignPercent = 0; p->em_mask &= (~MASK); p->ex_mask &= (~MASK); break; } case CSS_CONST_BASELINE: case CSS_CONST_SUB: case CSS_CONST_SUPER: case CSS_CONST_TOP: case CSS_CONST_TEXT_TOP: case CSS_CONST_MIDDLE: case CSS_CONST_BOTTOM: case CSS_CONST_TEXT_BOTTOM: p->values.mask &= (~MASK); p->values.eVerticalAlign = pProp->eType; p->values.iVerticalAlign = 0; p->eVerticalAlignPercent = 0; p->em_mask &= (~MASK); p->ex_mask &= (~MASK); break; case CSS_TYPE_PERCENT: { p->values.mask |= MASK; p->values.iVerticalAlign = INTEGER(100.0 * pProp->v.rVal); p->values.eVerticalAlign = 0; p->eVerticalAlignPercent = 1; p->em_mask &= (~MASK); p->ex_mask &= (~MASK); break; } default: { /* Try to treat the property as a */ int *pIVal = &p->values.iVerticalAlign; rc = propertyValuesSetLength(p, pIVal, MASK, pProp, 1); if (rc == 0) { p->values.mask |= MASK; p->eVerticalAlignPercent = 0; p->values.eVerticalAlign = 0; } break; } } return rc; } /* *--------------------------------------------------------------------------- * * propertyValuesSetSize -- * * Results: * 0 if *pIVar is set correctly. If pProp cannot be parsed as a size, * 1 is returned and *pIVar remains unmodified. * * Side effects: * May set *pIVar and set or clear bits in various *p masks. * *--------------------------------------------------------------------------- */ static int propertyValuesSetSize(p, pIVal, p_mask, pProp, allow_mask) HtmlComputedValuesCreator *p; int *pIVal; unsigned int p_mask; CssProperty *pProp; unsigned int allow_mask; { assert(p_mask != 0); /* Clear the bits in the inherit and percent masks for this property */ p->values.mask &= ~p_mask; p->em_mask &= ~p_mask; p->ex_mask &= ~p_mask; switch (pProp->eType) { /* TODO Percentages are still stored as integers - this is wrong */ case CSS_TYPE_PERCENT: { int iVal = INTEGER(pProp->v.rVal * 100.0); if ( (allow_mask & SZ_PERCENT) && (iVal >= 0 || allow_mask & SZ_NEGATIVE) ) { p->values.mask |= p_mask; *pIVal = iVal; return 0; } return 1; } case CSS_CONST_INHERIT: if (allow_mask & SZ_INHERIT) { HtmlNode *pParent = p->pParent; int *pInherit = (int *)getInheritPointer(p, pIVal); assert(pInherit); assert(pParent); *pIVal = *pInherit; p->values.mask |= (HtmlNodeComputedValues(pParent)->mask & p_mask); return 0; } return 1; case CSS_CONST_AUTO: if (allow_mask & SZ_AUTO) { *pIVal = PIXELVAL_AUTO; return 0; } return 1; case CSS_CONST_NONE: if (allow_mask & SZ_NONE) { *pIVal = PIXELVAL_NONE; return 0; } return 1; case CSS_CONST_NORMAL: if (allow_mask & SZ_NORMAL) { *pIVal = PIXELVAL_NONE; return 0; } return 1; case CSS_TYPE_FLOAT: { #if 0 if (iVal >= 0 || allow_mask & SZ_NEGATIVE) { *pIVal = iVal; return 0; } return 1; #endif } default: return propertyValuesSetLength( p, pIVal, p_mask, pProp, allow_mask & SZ_NEGATIVE); } } /* *--------------------------------------------------------------------------- * * propertyValuesSetBorderWidth -- * * pIVal points to an integer to store the value of a 'border-width-xxx' * property in pixels in (i.e. HtmlComputedValues.border.iTop). This * function attempts to interpret *pProp as a and writes the * number of pixels to render the border as to *pIVal. * * Border-widths are a little different from properties dealt with by * SetSize() in that they may not expressed as percentages. Hence they can * be resolved to an integer number of pixels during the styler phase (i.e. * now). * * Results: * If successful, 0 is returned. If pProp cannot be parsed as a * border-width, 1 is returned and *pIVar remains unmodified. * * Side effects: * May set *pIVar. * *--------------------------------------------------------------------------- */ static int propertyValuesSetBorderWidth(p, pIVal, em_mask, pProp) HtmlComputedValuesCreator *p; int *pIVal; unsigned int em_mask; CssProperty *pProp; { int eType = pProp->eType; /* Check for one of the keywords "thin", "medium" and "thick". TODO: We * should use some kind of table here, rather than constant values. * * Also handle "inherit" seperately here too. */ switch (eType) { case CSS_CONST_INHERIT: { int *pInherit = (int *)getInheritPointer(p, (unsigned char*)pIVal); if (pInherit) { *pIVal = *pInherit; } return 0; } case CSS_CONST_THIN: *pIVal = INTEGER(1.0 * p->pTree->options.zoom); return 0; case CSS_CONST_MEDIUM: *pIVal = INTEGER(2.0 * p->pTree->options.zoom); return 0; case CSS_CONST_THICK: *pIVal = INTEGER(4.0 * p->pTree->options.zoom); return 0; case CSS_TYPE_FLOAT: *pIVal = INTEGER(pProp->v.rVal * p->pTree->options.zoom); return 0; } /* If it is not one of the above keywords, then the border-width may * be expressed as a CSS . */ if (0 == propertyValuesSetLength(p, pIVal, em_mask, pProp, 0)) { return 0; } /* Not one of the keywords or a length -> type-mismatch error */ return 1; } /* *--------------------------------------------------------------------------- * * getPrototypeCreator -- * * This function returns a pointer to an HtmlComputedValuesCreator * structure filled in with default values for each property. If there * is no parent node, then this structure contains the property * values for a node before considering any style rules. * * If there is a parent node, then only the first *piCopyBytes bytes * of this structure should be copied to a new node. The other values * are inherited by default and should be copied from the parent node. * The bits in *pMask should be the only ones copied from the mask * of the returned Creator structure in this case. * * Results: * None. * * Side effects: * *--------------------------------------------------------------------------- */ static HtmlComputedValuesCreator * getPrototypeCreator(pTree, pMask, piCopyBytes) HtmlTree *pTree; unsigned int *pMask; int *piCopyBytes; { static int sMask = 0; static int sCopyBytes = sizeof(HtmlComputedValues); if (0 == pTree->pPrototypeCreator) { HtmlComputedValuesCreator *p; static CssProperty Black = {CSS_CONST_BLACK, {"black"}}; static CssProperty Medium = {CSS_CONST_MEDIUM, {"medium"}}; static CssProperty Trans = {CSS_CONST_TRANSPARENT, {"transparent"}}; HtmlComputedValues *pValues; char *values; int i; getPropertyDef(CSS_PROPERTY_VERTICAL_ALIGN); p = HtmlNew(HtmlComputedValuesCreator); p->pTree = pTree; pTree->pPrototypeCreator = p; pValues = &p->values; values = (char *)pValues; /* Initialise the CUSTOM properties. */ pValues->eVerticalAlign = CSS_CONST_BASELINE; pValues->iLineHeight = PIXELVAL_NORMAL; propertyValuesSetFontSize(p, &Medium); p->fontKey.zFontFamily = "Helvetica"; /* Initialise the 'color' and 'background-color' properties */ propertyValuesSetColor(p, &p->values.cColor, &Black); propertyValuesSetColor(p, &p->values.cBackgroundColor, &Trans); for (i = 0; i < sizeof(propdef) / sizeof(PropertyDef); i++) { PropertyDef *pDef = &propdef[i]; if (pDef->isInherit) { sCopyBytes = MIN(sCopyBytes, pDef->iOffset); } else { sMask = (sMask & pDef->mask); } switch (pDef->eType) { case LENGTH: case BORDERWIDTH: { int *pVal = (int *)(values + pDef->iOffset); /* Todo: -zoom */ *pVal = pDef->iDefault; break; } case ENUM: { /* Default for enum values is the first value in * the list returned by HtmlCssEnumeratedValues(). */ unsigned char *opt = HtmlCssEnumeratedValues(pDef->eProp); *(unsigned char *)(values + pDef->iOffset) = *opt; assert(*opt); break; } case AUTOINTEGER: { /* Default is 'auto' */ *(int *)(values + pDef->iOffset) = PIXELVAL_AUTO; break; } default: /* do nothing */ break; } } assert(p->em_mask == 0); assert(p->ex_mask == 0); for (i = 0; i < sizeof(propdef) / sizeof(PropertyDef); i++) { assert( (!propdef[i].isInherit && propdef[i].iOffset < sCopyBytes) || (propdef[i].isInherit && propdef[i].iOffset >= sCopyBytes) || propdef[i].eType == CUSTOM ); } } *piCopyBytes = sCopyBytes; *pMask = sMask; return pTree->pPrototypeCreator; } /* *--------------------------------------------------------------------------- * * HtmlComputedValuesInit -- * * Initialise an HtmlComputedValuesCreator structure. * * Results: * None. * * Side effects: * Initialises *p. * *--------------------------------------------------------------------------- */ void HtmlComputedValuesInit(pTree, pNode, pParent, p) HtmlTree *pTree; HtmlNode *pNode; /* Node to use for LOG blocks */ HtmlNode *pParent; /* Node to inherit properties from */ HtmlComputedValuesCreator *p; { HtmlComputedValues *pValues = &p->values; char *values = (char *)pValues; unsigned int iCopyMask = 0; int iCopyBytes = 0; HtmlComputedValuesCreator *pPrototype; if (0 == pParent) { pParent = HtmlNodeParent(pNode); } /* Copy non-inherited values from the prototype creator object. If * there is no parent node, then this is all there is to do. */ pPrototype = getPrototypeCreator(pTree, &iCopyMask, &iCopyBytes); memcpy(p, pPrototype, sizeof(HtmlComputedValuesCreator)); p->pTree = pTree; p->pParent = pParent; p->pNode = pNode; /* Copy property values that are inherited by default from the * properties of the parent node, if there is one. */ if (pParent) { int nBytes = sizeof(HtmlComputedValues) - iCopyBytes; char *pvalues = (char *)((HtmlElementNode *)pParent)->pPropertyValues; HtmlComputedValues *pParentValues = (HtmlComputedValues *)pValues; memcpy(&values[iCopyBytes], &pvalues[iCopyBytes], nBytes); memcpy(&p->fontKey, pValues->fFont->pKey, sizeof(HtmlFontKey)); pValues->mask = (pValues->mask & iCopyMask) | (pParentValues->mask & !iCopyMask); } p->values.cColor->nRef++; p->values.cBackgroundColor->nRef++; HtmlImageRef(p->values.imListStyleImage); assert(!p->values.cBorderTopColor); assert(!p->values.cBorderRightColor); assert(!p->values.cBorderBottomColor); assert(!p->values.cBorderLeftColor); assert(!p->values.cOutlineColor); } /* *--------------------------------------------------------------------------- * * propertyValuesTclScript -- * * Results: * * Side effects: * *--------------------------------------------------------------------------- */ static int propertyValuesTclScript(p, eProp, zScript) HtmlComputedValuesCreator *p; int eProp; const char *zScript; { int rc; const char *zRes; CssProperty *pVal; Tcl_Interp *interp = p->pTree->interp; Tcl_Obj *pCommand = HtmlNodeCommand(p->pTree, p->pNode); Tcl_SetVar2Ex(interp, "N", 0, pCommand, 0); rc = Tcl_Eval(interp, zScript); zRes = Tcl_GetStringResult(interp); if (rc == TCL_ERROR) { if (*zRes) { /* A tcl() script has returned a value that caused a type-mismatch * error. Run the -logcmd script if one exists. */ LOG { HtmlLog(p->pTree, "STYLEENGINE", "%s " "tcl() script error: %s", Tcl_GetString(HtmlNodeCommand(p->pTree, p->pNode)), zRes ); } } return 1; } assert(zRes); pVal = HtmlCssStringToProperty(zRes, -1); if (HtmlComputedValuesSet(p, eProp, pVal)) { /* A tcl() script has returned a value that caused a type-mismatch * error. Run the -logcmd script if one exists. */ LOG { HtmlLog(p->pTree, "STYLEENGINE", "%s " "tcl() script result is type mismatch for property '%s'", Tcl_GetString(HtmlNodeCommand(p->pTree, p->pNode)), HtmlCssPropertyToString(eProp) ); } HtmlFree(pVal); return 1; } /* Now that we've successfully called HtmlComputedValuesSet(), the * CssProperty structure (it's associated string data is what matters) * cannot be HtmlFree(0, )d until after HtmlComputedValuesFinish() is * called. * * So we make a linked list of such structures at p->pDeleteList using * CssProperty.v.p as the pNext pointer. * * HtmlComputedValuesFinish() deletes the list when it is called. */ HtmlComputedValuesFreeProperty(p, pVal); return 0; } /* *--------------------------------------------------------------------------- * * propertyValuesAttr -- * * Used to handle the special CSS syntax attr(). Tkhtml supports * the following extensions to this syntax: * * attr() * attr( ) * attr( ) * attr( ) * * Where modifiers is currently either "n" or "l": * * n -> normal * l -> length * * Results: * * Side effects: * *--------------------------------------------------------------------------- */ static int propertyValuesAttr(p, eProp, zArglist) HtmlComputedValuesCreator *p; int eProp; const char *zArglist; { int rc = 1; char *zCopy; const char *zCsr; const char *zEnd; int n; char *zAttr = 0; char *zMod = 0; char *zAncestor = 0; char *zValue = 0; HtmlNode *pNode = p->pNode; zCopy = (char *)HtmlAlloc("tmp", strlen(zArglist) + 1); strcpy(zCopy, zArglist); zCsr = zCopy; zEnd = &zCopy[strlen(zCopy)]; zAttr = (char *)HtmlCssGetNextListItem(zCsr, zEnd-zCsr, &n); if (zAttr) { zAttr[n] = '\0'; zCsr = &zAttr[n+1]; zMod = (char *)HtmlCssGetNextListItem(zCsr, zEnd-zCsr, &n); } if (zMod) { zMod[n] = '\0'; zCsr = &zMod[n+1]; zAncestor = (char *)HtmlCssGetNextListItem(zCsr, zEnd-zCsr, &n); } if (zAncestor) { zAncestor[n] = '\0'; zCsr = &zAncestor[n+1]; zValue = (char *)HtmlCssGetNextListItem(zCsr, zEnd-zCsr, &n); } if (zAncestor) { while (pNode && stricmp(zAncestor, HtmlNodeTagName(pNode))){ pNode = HtmlNodeParent(pNode); } } if (pNode) { const char *zVal = HtmlNodeAttr(pNode, zAttr); if (zVal) { CssProperty *pProp = HtmlCssStringToProperty(zValue?zValue:zVal,-1); if (zMod && *zMod=='l' && pProp->eType == CSS_TYPE_FLOAT) { pProp->eType = CSS_TYPE_PX; } rc = HtmlComputedValuesSet(p, eProp, pProp); HtmlComputedValuesFreeProperty(p, pProp); } } HtmlFree(zCopy); return rc; } void HtmlComputedValuesFreeProperty(p, pProp) HtmlComputedValuesCreator *p; CssProperty *pProp; { pProp->v.p = (void *)p->pDeleteList; p->pDeleteList = pProp; } /* *--------------------------------------------------------------------------- * * HtmlComputedValuesSet -- * * One or more calls to HtmlComputedValuesSet() take place between the * HtmlComputedValuesInit() and HtmlComputedValuesFinish() calls (see * comments above HtmlComputedValuesInit() for an API summary). The value * of property eProp (one of the CSS_PROPERTY_XXX values) in either the * HtmlComputedValues or HtmlFontKey structure is set to the value * contained by pProp. * * Note: If pProp contains a pointer to a string, then the string must * remain valid until HtmlComputedValuesFinish() is called (see the * 'font-family property handling below). * * Results: * Zero to indicate the value was set successfully, or non-zero to * indicate a type-mismatch. * * Side effects: * None. * *--------------------------------------------------------------------------- */ int HtmlComputedValuesSet(p, eProp, pProp) HtmlComputedValuesCreator *p; int eProp; CssProperty *pProp; { PropertyDef *pDef = getPropertyDef(eProp); if (!pProp) { return 0; } LOG { Tcl_Obj *pCmd = HtmlNodeCommand(p->pTree, p->pNode); if (pCmd) { char *zFree; char *zPropVal = HtmlPropertyToString(pProp, &zFree); HtmlLog(p->pTree, "STYLEENGINE", "%s %s -> %s", Tcl_GetString(pCmd), HtmlCssPropertyToString(eProp), zPropVal ); if (zFree) HtmlFree(zFree); } } /* Silently ignore any attempt to set a root-node property to 'inherit'. * It's not a type-mismatch, we just want to leave the value unchanged. */ if (pProp->eType == CSS_CONST_INHERIT && !p->pParent) { return 0; } /* Special case - a Tcl script to evaluate */ if (pProp->eType == CSS_TYPE_TCL) { return propertyValuesTclScript(p, eProp, pProp->v.zVal); } /* Special case number 2 - attr() */ if (pProp->eType == CSS_TYPE_ATTR) { return propertyValuesAttr(p, eProp, pProp->v.zVal); } if (pDef) { switch (pDef->eType) { case ENUM: { unsigned char *options = HtmlCssEnumeratedValues(eProp); unsigned char *pEVar; pEVar = (unsigned char *)&p->values + pDef->iOffset; return propertyValuesSetEnum(p, pEVar, options, pProp); } case LENGTH: { int *pIVar = (int*)((unsigned char*)&p->values + pDef->iOffset); int setsizemask = pDef->setsizemask; return propertyValuesSetSize( p, pIVar, pDef->mask, pProp, setsizemask ); } case BORDERWIDTH: { int *pBVar = (int*)((unsigned char*)&p->values + pDef->iOffset); return propertyValuesSetBorderWidth( p, pBVar, pDef->mask, pProp ); } case AUTOINTEGER: { int *pAVar = (int*)((unsigned char*)&p->values + pDef->iOffset); return propertyValuesSetAutoInteger(p, pProp, pAVar); } case CUSTOM: { return pDef->xSet(p, pProp); } case COLOR: { HtmlColor **pCVar; pCVar = (HtmlColor **)((char *)&p->values + pDef->iOffset); return propertyValuesSetColor(p, pCVar, pProp); } case COUNTERLIST: { HtmlCounterList **ppCL; ppCL= (HtmlCounterList **)((char *)&p->values + pDef->iOffset); return propertyValuesSetCounterList(p, ppCL, eProp, pProp); } case IMAGE: { HtmlImage2 **pI2Var; pI2Var = (HtmlImage2 **) ((unsigned char *)&p->values + pDef->iOffset); return propertyValuesSetImage(p, pI2Var, pProp); } } } return 1; } /* *--------------------------------------------------------------------------- * * allocateNewFont -- * * Allocate a new HtmlFont structure and populate it with the font * described by *pFontKey. The HtmlFont.nRef counter is set to 0 when this * function returns. * * Results: * * Side effects: * None. * *--------------------------------------------------------------------------- */ static void * allocateNewFont(clientData) ClientData clientData; { HtmlComputedValuesCreator *p = (HtmlComputedValuesCreator *)clientData; HtmlTree *pTree = p->pTree; HtmlFontKey *pFontKey = &p->fontKey; Tk_Window tkwin = pTree->tkwin; Tcl_Interp *interp = pTree->interp; int isForceFontMetrics = pTree->options.forcefontmetrics; Tk_Font tkfont = 0; const char *DEFAULT_FONT_FAMILY = "Helvetica"; const char *zFamily = pFontKey->zFontFamily; int isItalic = pFontKey->isItalic; int isBold = pFontKey->isBold; char zTkFontName[256]; /* Tk font name */ HtmlFont *pFont; /* Local variable iFontSize is in points - not thousandths */ int iFontSize; float fontsize = ((float)pFontKey->iFontSize / (float)HTML_IFONTSIZE_SCALE); fontsize = fontsize * pTree->options.fontscale * pTree->options.zoom; #if 0 if (isForceFontMetrics) { iFontSize = INTEGER(fontsize * 0.9); } else { iFontSize = INTEGER(fontsize); } #else iFontSize = INTEGER(fontsize); #endif do { sprintf(zTkFontName, "{%s} %d%.8s%.8s", zFamily, iFontSize, isItalic ? " italic" : "", isBold ? " bold" : "" ); tkfont = Tk_GetFont(interp, tkwin, zTkFontName); if (!tkfont) { if (isItalic) { isItalic = 0; } else if (isBold) { isBold = 0; } else if (zFamily != DEFAULT_FONT_FAMILY) { zFamily = DEFAULT_FONT_FAMILY; } else if (iFontSize != 10) { iFontSize = 10; } else { assert(0); return 0; } } } while (0 == tkfont); pFont = (HtmlFont *)HtmlClearAlloc( "HtmlFont", sizeof(HtmlFont) + strlen(zTkFontName)+1 ); pFont->nRef = 0; pFont->tkfont = tkfont; pFont->zFont = (char *)&pFont[1]; strcpy(pFont->zFont, zTkFontName); Tk_GetFontMetrics(tkfont, &pFont->metrics); pFont->space_pixels = Tk_TextWidth(tkfont, " ", 1); /* Set the number of pixels to be used for 1 "em" unit for this font. * Setting the em-pixels to the ascent + the descent worked Ok for * the old X11 fonts. However the value seems kind of large with the * new Xft fonts (Tk 8.5). */ pFont->em_pixels = pFont->metrics.ascent + pFont->metrics.descent; if (isForceFontMetrics) { float ratio; Tk_FontMetrics *pMet = &pFont->metrics; char zBuf[24]; if (iFontSize >= 0) { sprintf(zBuf, "%.3fp", fontsize); Tk_GetPixels(interp, tkwin, zBuf, &pFont->em_pixels); } else { pFont->em_pixels = -1 * iFontSize; } pMet->linespace = pMet->ascent + pMet->descent; if (pFont->em_pixels < pMet->linespace) { ratio = (float)pFont->em_pixels / (float)pMet->linespace; pMet->ascent = INTEGER((float)pMet->ascent * ratio); pMet->descent = pFont->em_pixels - pMet->ascent; pMet->linespace = pFont->em_pixels; } } /* Determine the x-height of the font. See ticket #221. * * The case dealing specifically with the "Ahem" font is added so * that the official CSS 2.1 test suite can be more easily used to * test Hv3. Ticket #221 describes this issue further. */ pFont->ex_pixels = Tk_TextWidth(tkfont, "x", 1); if (0 == stricmp("Ahem", zFamily)) { pFont->ex_pixels = ((pFont->em_pixels * 4) / 5); } return (void *)pFont; } /* *--------------------------------------------------------------------------- * * setDisplay97 -- * * Modify the value of the 'display' property in the structure pointed * to by argument p according to the table in section 9.7 of the CSS * 2.1 spec. * * Results: * * Side effects: * None. * *--------------------------------------------------------------------------- */ static void setDisplay97(p) HtmlComputedValuesCreator *p; { switch (p->values.eDisplay) { case CSS_CONST_INLINE_TABLE: p->values.eDisplay = CSS_CONST_TABLE; break; case CSS_CONST_INLINE: case CSS_CONST_INLINE_BLOCK: case CSS_CONST_RUN_IN: case CSS_CONST_TABLE_ROW_GROUP: case CSS_CONST_TABLE_COLUMN: case CSS_CONST_TABLE_COLUMN_GROUP: case CSS_CONST_TABLE_HEADER_GROUP: case CSS_CONST_TABLE_FOOTER_GROUP: case CSS_CONST_TABLE_ROW: case CSS_CONST_TABLE_CELL: case CSS_CONST_TABLE_CAPTION: p->values.eDisplay = CSS_CONST_BLOCK; break; } } /* *--------------------------------------------------------------------------- * * HtmlComputedValuesFinish -- * * Results: * * Side effects: * None. * *--------------------------------------------------------------------------- */ HtmlComputedValues * HtmlComputedValuesFinish(p) HtmlComputedValuesCreator *p; { Tcl_HashEntry *pEntry; int ne; /* New Entry */ HtmlFont *pFont; int ii; HtmlComputedValues *pValues = 0; HtmlColor *pColor; #define OFFSET(x) Tk_Offset(HtmlComputedValues, x) struct EmExMap { unsigned int mask; int offset; } emexmap[] = { {PROP_MASK_WIDTH, OFFSET(iWidth)}, {PROP_MASK_MIN_WIDTH, OFFSET(iMinWidth)}, {PROP_MASK_MAX_WIDTH, OFFSET(iMaxWidth)}, {PROP_MASK_HEIGHT, OFFSET(iHeight)}, {PROP_MASK_MIN_HEIGHT, OFFSET(iMinHeight)}, {PROP_MASK_MAX_HEIGHT, OFFSET(iMaxHeight)}, {PROP_MASK_MARGIN_TOP, OFFSET(margin.iTop)}, {PROP_MASK_MARGIN_RIGHT, OFFSET(margin.iRight)}, {PROP_MASK_MARGIN_BOTTOM, OFFSET(margin.iBottom)}, {PROP_MASK_MARGIN_LEFT, OFFSET(margin.iLeft)}, {PROP_MASK_PADDING_TOP, OFFSET(padding.iTop)}, {PROP_MASK_PADDING_RIGHT, OFFSET(padding.iRight)}, {PROP_MASK_PADDING_BOTTOM, OFFSET(padding.iBottom)}, {PROP_MASK_PADDING_LEFT, OFFSET(padding.iLeft)}, {PROP_MASK_VERTICAL_ALIGN, OFFSET(iVerticalAlign)}, {PROP_MASK_BORDER_TOP_WIDTH, OFFSET(border.iTop)}, {PROP_MASK_BORDER_RIGHT_WIDTH, OFFSET(border.iRight)}, {PROP_MASK_BORDER_BOTTOM_WIDTH, OFFSET(border.iBottom)}, {PROP_MASK_BORDER_LEFT_WIDTH, OFFSET(border.iLeft)}, {PROP_MASK_LINE_HEIGHT, OFFSET(iLineHeight)}, {PROP_MASK_OUTLINE_WIDTH, OFFSET(iOutlineWidth)}, {PROP_MASK_TOP, OFFSET(position.iTop)}, {PROP_MASK_BOTTOM, OFFSET(position.iBottom)}, {PROP_MASK_LEFT, OFFSET(position.iLeft)}, {PROP_MASK_RIGHT, OFFSET(position.iRight)}, {PROP_MASK_TEXT_INDENT, OFFSET(iTextIndent)} }; #undef OFFSET Tcl_HashTable *pFontHash = &p->pTree->fontcache.aHash; /* Find the font to use. If there is not a matching font in the font hash * table already, allocate a new one. */ pEntry = Tcl_CreateHashEntry(pFontHash, (char *)&p->fontKey, &ne); if (ne) { #ifndef TKHTML_ENABLE_PROFILE pFont = (HtmlFont *)allocateNewFont((ClientData)p); #else pFont = (HtmlFont *)HtmlInstrumentCall2(p->pTree->pInstrumentData, HTML_INSTRUMENT_ALLOCATE_FONT, allocateNewFont, (ClientData)p ); #endif assert(pFont); Tcl_SetHashValue(pEntry, pFont); pFont->pKey = (HtmlFontKey *)Tcl_GetHashKey(pFontHash, pEntry); } else { pFont = Tcl_GetHashValue(pEntry); if (pFont->nRef == 0) { HtmlFontCache *pCache = &p->pTree->fontcache; if (pFont == pCache->pLruHead) { pCache->pLruHead = pCache->pLruHead->pNext; if (!pCache->pLruHead) { pCache->pLruTail = 0; } } else { HtmlFont *pCsr = pCache->pLruHead; while (pCsr->pNext) { if (pCsr->pNext == pFont) { pCsr->pNext = pFont->pNext; if (!pCsr->pNext) { assert(pCache->pLruTail == pFont); pCache->pLruTail = pCsr; } break; } pCsr = pCsr->pNext; } } pFont->pNext = 0; pCache->nZeroRef--; } } pFont->nRef++; p->values.fFont = pFont; pEntry = 0; ne = 0; /* Now that we have the font, update all the property values that are * currently stored in 'em' or 'ex' form so that they are in pixels. */ for (ii = 0; ii < sizeof(emexmap)/sizeof(struct EmExMap); ii++) { struct EmExMap *pMap = &emexmap[ii]; int h; /* Computed value in hundrenths of pixels */ int *pVal = 0; if (p->em_mask & pMap->mask) { pVal = (int *)(((unsigned char *)&p->values) + pMap->offset); h = (*pVal * pFont->em_pixels); } else if (p->ex_mask & pMap->mask) { pVal = (int *)(((unsigned char *)&p->values) + pMap->offset); h = (*pVal * pFont->ex_pixels); } if (pVal) { h += ((h>0)?50:-50); *pVal = h / 100; } } /* If no value has been assigned to any of the 'border-xxx-color' * properties, then copy the value of the 'color' property. */ pColor = p->values.cColor; if (!p->values.cBorderTopColor) { p->values.cBorderTopColor = pColor; pColor->nRef++; } if (!p->values.cBorderRightColor) { p->values.cBorderRightColor = pColor; pColor->nRef++; } if (!p->values.cBorderBottomColor) { p->values.cBorderBottomColor = pColor; pColor->nRef++; } if (!p->values.cBorderLeftColor) { p->values.cBorderLeftColor = pColor; pColor->nRef++; } if (!p->values.cOutlineColor) { p->values.cOutlineColor = pColor; pColor->nRef++; } /* Post-processing for the 'vertical-align' property: * * 1. If the value was specified as a percentage, transform it * to a pixel length here. This is tricky, because the computed * value of 'line-height' (the property percentages are calculated * relative to) may be stored as a multiple of the font em-pixels. * * The reason iLineHeight is not always stored as an absolute * pixel value is that if it is specified as a , it * is equivalent to an em-pixels value for the current node, but * the inherited value is as specified. * * 2. If the node is a table-cell, then the only valid values are * "baseline", "top", "middle" and "bottom". If anything else has * been specified, set the property to "baseline" instead. */ if (p->eVerticalAlignPercent) { int line_height = p->values.iLineHeight; if (line_height == PIXELVAL_NORMAL) { line_height = -100; } if (line_height < 0) { line_height = (line_height * pFont->em_pixels) / -100; } p->values.iVerticalAlign = (p->values.iVerticalAlign*line_height)/10000; } if (p->values.eDisplay == CSS_CONST_TABLE_CELL && p->values.eVerticalAlign != CSS_CONST_TOP && p->values.eVerticalAlign != CSS_CONST_BOTTOM && p->values.eVerticalAlign != CSS_CONST_MIDDLE ) { p->values.eVerticalAlign = CSS_CONST_BASELINE; } /* The following block implements section 9.7 of the CSS 2.1 * specification. Refer there for details. */ if ( p->values.ePosition == CSS_CONST_ABSOLUTE || p->values.ePosition == CSS_CONST_FIXED ) { p->values.eFloat = CSS_CONST_NONE; setDisplay97(p); } else if (p->values.eFloat != CSS_CONST_NONE) { setDisplay97(p); } else if (p->pNode == p->pTree->pRoot) { setDisplay97(p); } /* This is section 9.4.3 of the same document. Massaging 'left', * 'right', 'top' and 'bottom' if the 'position' property is set to * "relative". */ if (p->values.ePosition == CSS_CONST_RELATIVE) { /* First for 'left' and 'right' */ if (p->values.position.iLeft == PIXELVAL_AUTO) { if (p->values.position.iRight == PIXELVAL_AUTO) { p->values.position.iRight = 0; p->values.position.iLeft = 0; } else { p->values.position.iLeft = -1 * p->values.position.iRight; p->values.mask = (p->values.mask & ~(PROP_MASK_LEFT)) | ((p->values.mask & PROP_MASK_RIGHT) ? PROP_MASK_LEFT : 0); } } else { p->values.position.iRight = -1 * p->values.position.iLeft; p->values.mask = (p->values.mask & ~(PROP_MASK_RIGHT)) | ((p->values.mask & PROP_MASK_LEFT) ? PROP_MASK_RIGHT : 0); } /* Then for 'top' and 'bottom' */ if (p->values.position.iTop == PIXELVAL_AUTO) { if (p->values.position.iBottom == PIXELVAL_AUTO) { p->values.position.iBottom = 0; p->values.position.iTop = 0; } else { p->values.position.iTop = -1 * p->values.position.iBottom; p->values.mask = (p->values.mask & ~(PROP_MASK_TOP)) | ((p->values.mask & PROP_MASK_BOTTOM) ? PROP_MASK_TOP : 0); } } else { p->values.position.iBottom = -1 * p->values.position.iTop; p->values.mask = (p->values.mask & ~(PROP_MASK_BOTTOM)) | ((p->values.mask & PROP_MASK_TOP) ? PROP_MASK_BOTTOM : 0); } } if ( p->values.eDisplay == CSS_CONST_TABLE_CAPTION || p->values.eDisplay == CSS_CONST_RUN_IN /* || p->values.eDisplay == CSS_CONST_INLINE_BLOCK */ ) { p->values.eDisplay = CSS_CONST_BLOCK; } if (p->values.eDisplay == CSS_CONST_INLINE_TABLE) { p->values.eDisplay = CSS_CONST_TABLE; } /* Look the values structure up in the hash-table. */ pEntry = Tcl_CreateHashEntry(&p->pTree->aValues, (char *)&p->values, &ne); pValues = (HtmlComputedValues *)Tcl_GetHashKey(&p->pTree->aValues, pEntry); assert(!ne || !pValues->imZoomedBackgroundImage); if (!ne) { /* If this is not a new entry, we need to decrement the reference count * on the font, image and color values. */ pValues->fFont->nRef--; pValues->cColor->nRef--; pValues->cBackgroundColor->nRef--; pValues->cBorderTopColor->nRef--; pValues->cBorderRightColor->nRef--; pValues->cBorderBottomColor->nRef--; pValues->cBorderLeftColor->nRef--; pValues->cOutlineColor->nRef--; assert(pValues->fFont->nRef > 0); assert(pValues->cColor->nRef > 0); assert(pValues->cBackgroundColor->nRef > 0); assert(pValues->cBorderTopColor->nRef > 0); assert(pValues->cBorderRightColor->nRef > 0); assert(pValues->cBorderBottomColor->nRef > 0); assert(pValues->cBorderLeftColor->nRef > 0); assert(pValues->cOutlineColor->nRef > 0); HtmlImageFree(pValues->imReplacementImage); HtmlImageFree(pValues->imBackgroundImage); HtmlImageFree(pValues->imListStyleImage); } HtmlImageCheck(pValues->imReplacementImage); HtmlImageCheck(pValues->imBackgroundImage); HtmlImageCheck(pValues->imListStyleImage); if (pValues->imBackgroundImage && !pValues->imZoomedBackgroundImage) { int w = PIXELVAL_AUTO; int h = PIXELVAL_AUTO; HtmlImage2 *pZ = HtmlImageScale(pValues->imBackgroundImage, &w, &h, 1); pValues->imZoomedBackgroundImage = pZ; } if (p->pContent) { HtmlStyleHandleCounters(p->pTree, pValues); propertyValuesCalculateContent(p); } /* Delete any CssProperty structures allocated for Tcl properties */ if (p->pDeleteList) { CssProperty *p1 = p->pDeleteList; while (p1) { CssProperty *p2 = (CssProperty *)p1->v.p; HtmlFree(p1); p1 = p2; } p->pDeleteList = 0; } pValues->nRef++; return pValues; } /* *--------------------------------------------------------------------------- * * HtmlFontRelease -- * * Decrement the refcount of font pFont. Fonts are deleted when * the refcount reaches 0. * * Results: * * None. * * Side effects: * May delete pFont. * *--------------------------------------------------------------------------- */ void HtmlFontRelease(pTree, pFont) HtmlTree *pTree; HtmlFont *pFont; { if (pFont) { pFont->nRef--; assert(pFont->nRef >= 0); if (pFont->nRef == 0) { HtmlFontCache *p = &pTree->fontcache; assert(pFont->pNext == 0); assert((p->pLruTail&&p->pLruHead) || (!p->pLruTail&&!p->pLruHead)); if (p->pLruTail) { p->pLruTail->pNext = pFont; }else{ p->pLruHead = pFont; } p->pLruTail = pFont; p->nZeroRef++; if (p->nZeroRef > HTML_MAX_ZEROREF_FONTS) { Tcl_HashEntry *pEntry; HtmlFont *pRem = p->pLruHead; const char *pKey = (const char *)pRem->pKey; p->pLruHead = pRem->pNext; if (!p->pLruHead) { p->pLruTail = 0; } pEntry = Tcl_FindHashEntry(&p->aHash, pKey); Tcl_DeleteHashEntry(pEntry); Tk_FreeFont(pRem->tkfont); HtmlFree(pRem); } } } } /* *--------------------------------------------------------------------------- * * HtmlFontReference -- * * Increment the refcount of font pFont. * * Results: * * None. * * Side effects: * None. * *--------------------------------------------------------------------------- */ void HtmlFontReference(pFont) HtmlFont *pFont; { assert(pFont); assert(pFont->nRef >= 0); pFont->nRef++; } void HtmlComputedValuesReference(pValues) HtmlComputedValues *pValues; { assert(pValues->nRef > 0); pValues->nRef++; } void HtmlComputedValuesRelease(pTree, pValues) HtmlTree *pTree; HtmlComputedValues *pValues; { if (pValues) { pValues->nRef--; assert(pValues->nRef >= 0); /* If the reference count on this values structure has reached 0, then * decrement the reference counts on the font and colors and delete the * values structure hash entry. */ if (pValues->nRef == 0) { Tcl_HashEntry *pEntry; pEntry = Tcl_FindHashEntry(&pTree->aValues, (CONST char *)pValues); assert(pValues == &pTree->pPrototypeCreator->values || pEntry); HtmlFontRelease(pTree, pValues->fFont); decrementColorRef(pTree, pValues->cColor); decrementColorRef(pTree, pValues->cBackgroundColor); decrementColorRef(pTree, pValues->cBorderTopColor); decrementColorRef(pTree, pValues->cBorderRightColor); decrementColorRef(pTree, pValues->cBorderBottomColor); decrementColorRef(pTree, pValues->cBorderLeftColor); decrementColorRef(pTree, pValues->cOutlineColor); HtmlImageFree(pValues->imReplacementImage); HtmlImageFree(pValues->imBackgroundImage); HtmlImageFree(pValues->imZoomedBackgroundImage); HtmlImageFree(pValues->imListStyleImage); decrementCounterListRef(pValues->clCounterIncrement); decrementCounterListRef(pValues->clCounterReset); if (pEntry) { Tcl_DeleteHashEntry(pEntry); } } } } /* *--------------------------------------------------------------------------- * * HtmlComputedValuesSetupTables -- * * This function is called during widget initialisation to initialise the * three hash-tables used by code in this file: * * HtmlTree.aColor * HtmlTree.fontcache.aHash * HtmlTree.aFontFamilies * HtmlTree.aValues * * The aColor array is pre-loaded with 16 colors - the colors defined by * the CSS standard. This is because the RGB definitions of these colors in * CSS may be different than Tk's definition. If we preload all 16 and * leave them in the color-cache permanently, we can be sure that the CSS * defintions will always be used. * * The fontcache.aHash and aValues hash tables are initialised empty. * * Results: * * Side effects: * None. * *--------------------------------------------------------------------------- */ void HtmlComputedValuesSetupTables(pTree) HtmlTree *pTree; { static struct CssColor { char *css; char *tk; } color_map[] = { {"silver", "#C0C0C0"}, {"gray", "#808080"}, {"white", "#FFFFFF"}, {"maroon", "#800000"}, {"red", "#FF0000"}, {"purple", "#800080"}, {"fuchsia", "#FF00FF"}, {"green", "#008000"}, {"lime", "#00FF00"}, {"olive", "#808000"}, {"yellow", "#FFFF00"}, {"navy", "#000080"}, {"blue", "#0000FF"}, {"teal", "#008080"}, {"aqua", "#00FFFF"} }; int ii; Tcl_HashEntry *pEntry; Tcl_Interp *interp = pTree->interp; Tcl_HashKeyType *pType; HtmlColor *pColor; int n; Tcl_Obj **apFamily; int nFamily; int dummy; pType = HtmlCaseInsenstiveHashType(); Tcl_InitCustomHashTable(&pTree->aColor, TCL_CUSTOM_TYPE_KEYS, pType); pType = HtmlFontKeyHashType(); Tcl_InitCustomHashTable(&pTree->fontcache.aHash,TCL_CUSTOM_TYPE_KEYS,pType); pType = HtmlComputedValuesHashType(); Tcl_InitCustomHashTable(&pTree->aValues, TCL_CUSTOM_TYPE_KEYS, pType); /* Initialise the aFontFamilies hash table. */ pType = HtmlCaseInsenstiveHashType(); Tcl_InitCustomHashTable(&pTree->aFontFamilies, TCL_CUSTOM_TYPE_KEYS, pType); Tcl_Eval(interp, "font families"); Tcl_ListObjGetElements(NULL, Tcl_GetObjResult(interp), &nFamily, &apFamily); for (ii = 0; ii < nFamily; ii++) { Tcl_HashEntry *pEntry = Tcl_CreateHashEntry( &pTree->aFontFamilies, Tcl_GetString(apFamily[ii]), &dummy ); Tcl_SetHashValue(pEntry, 0); /* Note that sometimes the [font families] command returns a list * containing duplicate elements. Therefore we cannot "assert(dummy)". */ } pEntry = Tcl_CreateHashEntry(&pTree->aFontFamilies, "serif", &dummy); Tcl_SetHashValue(pEntry, "Times"); pEntry = Tcl_CreateHashEntry(&pTree->aFontFamilies, "sans-serif", &dummy); Tcl_SetHashValue(pEntry, "Helvetica"); pEntry = Tcl_CreateHashEntry(&pTree->aFontFamilies, "monospace", &dummy); Tcl_SetHashValue(pEntry, "Courier"); /* Initialise the color table */ for (ii = 0; ii < sizeof(color_map)/sizeof(struct CssColor); ii++) { pColor = (HtmlColor *)HtmlAlloc("HtmlColor", sizeof(HtmlColor)); pColor->zColor = color_map[ii].css; pColor->nRef = 1; pColor->xcolor = Tk_GetColor(interp, pTree->tkwin, color_map[ii].tk); assert(pColor->xcolor); pEntry = Tcl_CreateHashEntry(&pTree->aColor, pColor->zColor, &n); assert(pEntry && n); Tcl_SetHashValue(pEntry, pColor); } /* Add the "transparent" color */ pEntry = Tcl_CreateHashEntry(&pTree->aColor, "transparent", &n); assert(pEntry && n); pColor = (HtmlColor *)HtmlAlloc("HtmlColor", sizeof(HtmlColor)); pColor->zColor = "transparent"; pColor->nRef = 1; pColor->xcolor = 0; Tcl_SetHashValue(pEntry, pColor); } /* *--------------------------------------------------------------------------- * * HtmlFontClearCache -- * * Assuming there are no valid references to any fonts in the * font-cache, clean up all fonts at the Tk level. This happens: * * (a) when the widget is being destroyed, and * (b) when font-related options change. * * If the isReinit argument is non-zero, the hash-table at * HtmlTree.fontcache.aHash is left in a usable (but empty) state. * If isReinit is zero, it is not safe to use the hash table after * this function returns. * * Results: * None. * * Side effects: * None * *--------------------------------------------------------------------------- */ void HtmlFontCacheClear(pTree, isReinit) HtmlTree *pTree; int isReinit; { HtmlFont *pFont; HtmlFont *pNext; #ifndef NDEBUG /* Check there are no valid font references. */ Tcl_HashSearch search; Tcl_HashEntry *pEntry; for ( pEntry = Tcl_FirstHashEntry(&pTree->fontcache.aHash, &search); pEntry; pEntry = Tcl_NextHashEntry(&search) ) { pFont = (HtmlFont *)Tcl_GetHashValue(pEntry); assert(pFont->nRef == 0); } #endif Tcl_DeleteHashTable(&pTree->fontcache.aHash); for (pFont = pTree->fontcache.pLruHead; pFont; pFont = pNext) { Tk_FreeFont(pFont->tkfont); pNext = pFont->pNext; HtmlFree(pFont); } if (isReinit) { memset(&pTree->fontcache, 0, sizeof(HtmlFontCache)); Tcl_InitCustomHashTable( &pTree->fontcache.aHash, TCL_CUSTOM_TYPE_KEYS, HtmlFontKeyHashType() ); } } void HtmlComputedValuesFreePrototype(pTree) HtmlTree *pTree; { if (pTree->pPrototypeCreator) { pTree->pPrototypeCreator->values.nRef = 1; HtmlComputedValuesRelease(pTree, &pTree->pPrototypeCreator->values); HtmlFree(pTree->pPrototypeCreator); pTree->pPrototypeCreator = 0; } } /* *--------------------------------------------------------------------------- * * HtmlComputedValuesCleanupTables -- * * This function is called during widget destruction to deallocate * resources allocated by HtmlComputedValuesSetupTables(). This should be * called after HtmlComputedValues references have been released (otherwise * an assertion will fail). * * Resources are currently: * * - The entries in aColor for the 15 CSS defined colors. * - The entry in aColor for "transparent". * - The entries in the font-family table. * * Results: * None. * * Side effects: * Cleans up resources allocated by HtmlComputedValuesSetupTables(). * *--------------------------------------------------------------------------- */ void HtmlComputedValuesCleanupTables(pTree) HtmlTree *pTree; { CONST char **pzCursor; CONST char *azColor[] = { "silver", "gray", "white", "maroon", "red", "purple", "fuchsia", "green", "lime", "olive", "yellow", "navy", "blue", "teal", "aqua", "transparent", 0 }; HtmlComputedValuesFreePrototype(pTree); for (pzCursor = azColor; *pzCursor; pzCursor++) { HtmlColor *pColor; Tcl_HashEntry *pEntry = Tcl_FindHashEntry(&pTree->aColor, *pzCursor); assert(pEntry); pColor = (HtmlColor *)Tcl_GetHashValue(pEntry); decrementColorRef(pTree, pColor); } HtmlFontCacheClear(pTree, 0); Tcl_DeleteHashTable(&pTree->aFontFamilies); #ifndef NDEBUG /* This code is to assert() that there are no stray entries left in * the colors table. If there is, the restrack.c code would catch it * eventually, but it's better to dump core here. Memory leaks make * me look like a clown! */ assert(dumpColorTable(pTree) == 0); #endif } static Tcl_Obj * getPropertyObj(pValues, eProp) HtmlComputedValues *pValues; int eProp; { Tcl_Obj *pValue = 0; PropertyDef *pDef; /* If the following returns NULL, then the specified property name * is a legal one, but not one that Tkhtml3 handles. Return an * empty string in this case. */ pDef = getPropertyDef(eProp); if (pDef) { unsigned char *v = (unsigned char *)pValues; switch (pDef->eType) { case ENUM: { int eValue = (int)*(unsigned char *)(v + pDef->iOffset); CONST char *zValue = HtmlCssConstantToString(eValue); pValue = Tcl_NewStringObj(zValue, -1); break; } case COLOR: { HtmlColor *pColor = *(HtmlColor **)(v + pDef->iOffset); pValue = Tcl_NewStringObj(pColor->zColor, -1); break; } case COUNTERLIST: { HtmlCounterList *pCL = *(HtmlCounterList **)(v + pDef->iOffset); if (!pCL) { pValue = Tcl_NewStringObj("none", -1); } else { int ii; pValue = Tcl_NewObj(); for (ii = 0; ii < pCL->nCounter; ii++) { if (ii > 0) { Tcl_AppendToObj(pValue, " ", -1); } Tcl_AppendToObj(pValue, pCL->azCounter[ii], -1); Tcl_AppendToObj(pValue, " ", -1); Tcl_AppendObjToObj( pValue, Tcl_NewIntObj(pCL->anValue[ii]) ); } } break; } case IMAGE: { HtmlImage2 *pImage = *(HtmlImage2 **)(v + pDef->iOffset); if (pImage) { /* Todo: Might be some character escapin' to do here */ pValue = Tcl_NewStringObj("url('", -1); Tcl_AppendToObj(pValue, HtmlImageUrl(pImage), -1); Tcl_AppendToObj(pValue, "')", -1); } else { pValue = Tcl_NewStringObj("none", -1); } break; } case LENGTH: { int iVal = *(int *)(v + pDef->iOffset); if ( (pDef->setsizemask & SZ_PERCENT) && (pValues->mask & pDef->mask) ) { pValue = Tcl_NewDoubleObj(((double)iVal) / 100.0); Tcl_AppendToObj(pValue, "%", -1); break; } else if (iVal < MAX_PIXELVAL) { switch (iVal) { case PIXELVAL_AUTO: pValue = Tcl_NewStringObj("auto", -1); break; case PIXELVAL_NONE: pValue = Tcl_NewStringObj("none", -1); break; case PIXELVAL_NORMAL: pValue = Tcl_NewStringObj("normal", -1); break; } break; } /* Fall through for pixel value */ } case BORDERWIDTH: { int iWidth = *(int *)(v + pDef->iOffset); pValue = Tcl_NewIntObj(iWidth); Tcl_AppendToObj(pValue, "px", -1); break; } case AUTOINTEGER: { int i = *(int *)(v + pDef->iOffset); if (i==PIXELVAL_AUTO) { pValue = Tcl_NewStringObj("auto", 4); } else { pValue = Tcl_NewIntObj(i); } break; } case CUSTOM: { pValue = pDef->xObj(pValues); break; } } assert(pValue); } else { pValue = Tcl_NewStringObj("", -1); } return pValue; } /* *--------------------------------------------------------------------------- * * HtmlNodeGetProperty -- * * Obtain a Tcl (string) representation of the computed value of * a specified property. * * Results: * * Side effects: * None. * *--------------------------------------------------------------------------- */ int HtmlNodeGetProperty(interp, pProp, pValues) Tcl_Interp *interp; /* Interpreter to set result in */ Tcl_Obj *pProp; /* Property name */ HtmlComputedValues *pValues; /* Read value from here */ { int nProp; const char *zProp = Tcl_GetStringFromObj(pProp, &nProp); int eProp = HtmlCssPropertyLookup(nProp, zProp); /* Special case - the "font" property returns the Tk font. This ** is so that code implementing replaced objects can do this: ** ** $widget configure -font [$node property font] ** ** Probably in a -stylecmd callback. */ if (eProp == CSS_SHORTCUTPROPERTY_FONT) { Tcl_SetResult(interp, pValues->fFont->zFont, TCL_VOLATILE); return TCL_OK; } assert(eProp <= CSS_PROPERTY_MAX_PROPERTY); if (eProp < 0) { Tcl_AppendResult(interp, "no such property: ", zProp, 0); return TCL_ERROR; } Tcl_SetObjResult(interp, getPropertyObj(pValues, eProp)); return TCL_OK; } int HtmlNodeProperties(interp, pValues) Tcl_Interp *interp; HtmlComputedValues *pValues; { int ii; Tcl_Obj *pRet = Tcl_NewObj(); Tcl_IncrRefCount(pRet); for (ii = 0; ii < sizeof(propdef) / sizeof(propdef[0]); ii++) { PropertyDef *pDef = &propdef[ii]; Tcl_ListObjAppendElement(interp, pRet, Tcl_NewStringObj(HtmlCssPropertyToString(pDef->eProp), -1) ); Tcl_ListObjAppendElement(interp, pRet, getPropertyObj(pValues, pDef->eProp) ); } /* Special attribute: font. */ Tcl_ListObjAppendElement(0, pRet, Tcl_NewStringObj("font", -1)); Tcl_ListObjAppendElement(0,pRet,Tcl_NewStringObj(pValues->fFont->zFont,-1)); Tcl_SetObjResult(interp, pRet); Tcl_DecrRefCount(pRet); return TCL_OK; } #define HTML_REQUIRE_CONTENT 3 #define HTML_REQUIRE_LAYOUT 2 #define HTML_REQUIRE_PAINT 1 #define HTML_OK 0 int HtmlComputedValuesCompare(pV1, pV2) HtmlComputedValues *pV1; HtmlComputedValues *pV2; { unsigned char *v1 = (unsigned char *)pV1; unsigned char *v2 = (unsigned char *)pV2; int ii; if (pV1 == pV2) { return HTML_OK; } /* * Check for changes in the following properties: * * 'counter-reset' * 'counter-increment' * */ if ( (!pV1 && (pV2->clCounterIncrement || pV2->clCounterReset)) || (!pV2 && (pV1->clCounterIncrement || pV1->clCounterReset)) || (pV1 && pV2 && pV2->clCounterIncrement != pV1->clCounterIncrement) || (pV1 && pV2 && pV2->clCounterReset != pV1->clCounterReset) ) { return HTML_REQUIRE_CONTENT; } /* * Check for changes in the following properties: * * '-tkhtml-replacement-image' * 'list-style-image' * 'font' * 'vertical-align' */ if ( !pV1 || !pV2 || pV1->imReplacementImage != pV2->imReplacementImage || pV1->imListStyleImage != pV2->imListStyleImage || pV1->fFont != pV2->fFont || pV1->eVerticalAlign != pV2->eVerticalAlign || (!pV1->eVerticalAlign && pV1->iVerticalAlign != pV1->iVerticalAlign) ) { return HTML_REQUIRE_LAYOUT; } for (ii = 0; ii < sizeof(propdef) / sizeof(propdef[0]); ii++){ PropertyDef *pDef = &propdef[ii]; if (pDef->isNolayout) continue; switch (pDef->eType) { case ENUM: { if (*(v1 + pDef->iOffset) != *(v2 + pDef->iOffset)) { return HTML_REQUIRE_LAYOUT; } break; } case BORDERWIDTH: case LENGTH: { int *pL1 = (int *)(v1 + pDef->iOffset); int *pL2 = (int *)(v2 + pDef->iOffset); if ( *pL1 != *pL2 || ((pDef->mask & pV1->mask) != (pDef->mask & pV2->mask)) ) { return HTML_REQUIRE_LAYOUT; } break; } case COLOR: case IMAGE: break; case AUTOINTEGER: { int *pI1 = (int *)(v1 + pDef->iOffset); int *pI2 = (int *)(v2 + pDef->iOffset); if (*pI1 != *pI2) { return HTML_REQUIRE_LAYOUT; } break; } case CUSTOM: /* TODO */ break; case COUNTERLIST: /* TODO */ break; } } return HTML_REQUIRE_PAINT; } tkHTML-4ee7aaa953d6cb59/src/htmlprop.h000064400000000000000000000516451151224263100167350ustar00nobodynobody/* * htmlprop.h -- * * This header file contains the definition of the HtmlComputedValues * structure, which stores a set of CSS2 properties output by the * styler. This information is used by the layout engine in * htmllayout.c to create the runtime model of the document. * * ----------------------------------------------------------------------- * TODO: Copyright. */ #ifndef __HTMLPROP_H__ #define __HTMLPROP_H__ /* * We need to get the INT_MIN symbol (the most negative number that * can be stored in a C "int". */ #include typedef struct HtmlFourSides HtmlFourSides; typedef struct HtmlComputedValues HtmlComputedValues; typedef struct HtmlComputedValuesCreator HtmlComputedValuesCreator; typedef struct HtmlColor HtmlColor; typedef struct HtmlCounterList HtmlCounterList; typedef struct HtmlFont HtmlFont; typedef struct HtmlFontKey HtmlFontKey; typedef struct HtmlFontCache HtmlFontCache; /* * This structure is used to group four padding, margin or border-width * values together. When we get around to it, it will be used for the * position properties too ('top', 'right', 'bottom' and 'left'). */ struct HtmlFourSides { int iTop; int iLeft; int iBottom; int iRight; }; /* * The HtmlFont structure is used to store a font in use by the current * document. The following properties are used to determine the Tk * font to load: * * 'font-size' * 'font-family' * 'font-style' * 'font-weight' * * HtmlFont structures are stored in the HtmlTree.aFonts hash table. The hash * table uses a custom key type (struct HtmlFontKey) implemented in htmlhash.c. */ #define HTML_IFONTSIZE_SCALE 1000 struct HtmlFontKey { /* If iFontSize is positive, then it is in thousandths of points. * If negative, in thousandths of pixels. */ int iFontSize; /* Font size in thousandths of points */ const char *zFontFamily; /* Name of font family (i.e. "Serif") */ unsigned char isItalic; /* True if the font is italic */ unsigned char isBold; /* True if the font is bold */ }; struct HtmlFont { int nRef; /* Number of pointers to this structure */ HtmlFontKey *pKey; /* Pointer to corresponding HtmlFontKey structure */ char *zFont; /* Name of font */ Tk_Font tkfont; /* The Tk font */ int em_pixels; /* Pixels per 'em' unit */ int ex_pixels; /* Pixels per 'ex' unit */ int space_pixels; /* Pixels per space (' ') in this font */ Tk_FontMetrics metrics; HtmlFont *pNext; /* Next entry in the Html.FontCache LRU list */ }; /* * In Tk, allocating new fonts is very expensive. So we try hard to * avoid doing it more than is required. */ #define HTML_MAX_ZEROREF_FONTS 50 struct HtmlFontCache { Tcl_HashTable aHash; HtmlFont *pLruHead; HtmlFont *pLruTail; int nZeroRef; }; /* * An HtmlColor structure is used to store each color in use by the current * document. HtmlColor structures are stored in the HtmlTree.aColors hash * table. The hash table uses string keys (the name of the color). */ struct HtmlColor { int nRef; /* Number of pointers to this structure */ char *zColor; /* Name of color */ XColor *xcolor; /* The XColor* */ }; /* * An HtmlCounterList is used to store the computed value of the * 'counter-increment' and 'counter-reset' properties. */ struct HtmlCounterList { int nRef; int nCounter; char **azCounter; int *anValue; }; /* * An instance of this structure stores a set of property values as assigned by * the styler process. The values are as far as I can tell "computed" values, * but in some cases I'm really only guessing. * * All values are stored as one of the following broad "types": * * Variable Name Type * ------------------------------------------ * eXXX Enumerated type values * iXXX Pixel type values * cXXX Color type values * fXXX Font type values * ------------------------------------------ * * Enumerated type values * * Many properties can be stored as a single variable, for example the * 'display' property is stored in the HtmlComputedValues.eDisplay * variable. Members of the HtmlComputedValues structure with names that * match the pattern "eXXX" contain a CSS constant value (one of the * CSS_CONST_XXX #define symbols). These are defined in the header file * cssprop.h, which is generated during compilation by the script in * cssprop.tcl. * * Note: Since we use 'unsigned char' to store the eXXX variables: * * assert(CSS_CONST_MIN_CONSTANT >= 0); * assert(CSS_CONST_MAX_CONSTANT < 256); * * Color type values * * Font type values * * Pixel type values: * * Most variables that match the pattern 'iXXX' contain pixel values - a * length or size expressed in pixels. The only exceptions at the moment * are HtmlFontKey.iFontSize and iZIndex. * * Percentage values * * Some values, for example the 'width' property, may be either * calculated to an exact number of pixels by the styler or left as a * percentage value. In the first case, the 'int iXXX;' variable for * the property contains the number of pixels. Otherwise, it contains * the percentage value multiplied by 100. If the value is a * percentage, then the PROP_MASK_XXX bit is set in the * HtmlComputedValues.mask mask. For example, given the width of the * parent block in pixels, the following code determines the width in * pixels contained by the HtmlComputedValues structure: * * int iParentPixelWidth = ; * HtmlComputedValues Values = ; * * int iPixelWidth; * if (Values.mask & PROP_MASK_WIDTH) { * iPixelWidth = (Values.iWidth * iParentPixelWidth / 10000); * } else { * iPixelWidth = Values.iWidth; * } * * The 'auto', 'none' and 'normal' values: * * If a pixel type value is set to 'auto', 'none' or 'normal', the * integer variable is set to the constant PIXELVAL_AUTO, * PIXELVAL_NONE or PIXELVAL_NORMAL respectively. These are both very * large negative numbers, unlikely to be confused with real pixel * values. * * iVerticalAlign: * * The 'vertical-align' property, stored in iVerticalAlign is different * from the other iXXX values. The styler output for vertical align is * either a number of pixels or one of the constants 'baseline', 'sub' * 'super', 'top', 'text-top', 'middle', 'bottom', 'text-bottom'. The * 'vertical-align' property can be assigned a percentage value, but * the styler can resolve it. (This matches the CSS 2.1 description of * the computed value - section 10.8.1). * * If 'vertical-align' is a constant value, it is stored in * eVerticalAlign (as a CSS_CONST_XXX value). Otherwise, if it is a * pixel value it is stored in iVerticalAlign and eVerticalAlign is set * to 0. * * iLineHeight: * Todo: Note that inheritance is not done correctly for this property * if it is set to . * * * Properties not represented: * * The following properties should be supported by this structure, as * Tkhtml aims to one day support them. They are not currently supported * because (a) layout engine support is a long way off, and (b) it would * be tricky in some way to do so: * * 'clip' 'cursor' 'counter-increment' * 'counter-reset' 'quotes' */ struct HtmlComputedValues { HtmlImage2 *imZoomedBackgroundImage; /* MUST BE FIRST (see htmlhash.c) */ int nRef; /* MUST BE FIRST (see htmlhash.c) */ unsigned int mask; unsigned char eDisplay; /* 'display' */ unsigned char eFloat; /* 'float' */ unsigned char eClear; /* 'clear' */ /* ePosition stores the enumerated 'position' property. The position * structure stores the computed values of the 'top', 'bottom', 'left' * and 'right' properties. */ unsigned char ePosition; /* 'position' */ HtmlFourSides position; /* (pixels, %, AUTO) */ HtmlColor *cBackgroundColor; /* 'background-color' */ unsigned char eTextDecoration; /* 'text-decoration' */ /* See above. iVerticalAlign is used only if (eVerticalAlign==0) */ unsigned char eVerticalAlign; /* 'vertical-align' */ int iVerticalAlign; /* 'vertical-align' (pixels) */ int iWidth; /* 'width' (pixels, %, AUTO) */ int iMinWidth; /* 'min-width' (pixels, %) */ int iMaxWidth; /* 'max-height' (pixels, %, NONE) */ int iHeight; /* 'height' (pixels, % AUTO) */ int iMinHeight; /* 'min-height' (pixels, %) */ int iMaxHeight; /* 'max-height' (pixels, %, NONE) */ HtmlFourSides padding; /* 'padding' (pixels, %) */ HtmlFourSides margin; /* 'margin' (pixels, %, AUTO) */ HtmlFourSides border; /* 'border-width' (pixels) */ unsigned char eBorderTopStyle; /* 'border-top-style' */ unsigned char eBorderRightStyle; /* 'border-right-style' */ unsigned char eBorderBottomStyle; /* 'border-bottom-style' */ unsigned char eBorderLeftStyle; /* 'border-left-style' */ HtmlColor *cBorderTopColor; /* 'border-top-color' */ HtmlColor *cBorderRightColor; /* 'border-right-color' */ HtmlColor *cBorderBottomColor; /* 'border-bottom-color' */ HtmlColor *cBorderLeftColor; /* 'border-left-color' */ unsigned char eOutlineStyle; /* 'outline-style' */ int iOutlineWidth; /* 'outline-width' (pixels) */ HtmlColor *cOutlineColor; /* 'outline-color' */ HtmlImage2 *imBackgroundImage; /* 'background-image' */ unsigned char eBackgroundRepeat; /* 'background-repeat' */ unsigned char eBackgroundAttachment; /* 'background-attachment' */ int iBackgroundPositionX; int iBackgroundPositionY; unsigned char eOverflow; /* 'overflow' */ int iZIndex; /* 'z-index' (integer, AUTO) */ /* The Tkhtml specific properties */ HtmlImage2 *imReplacementImage; /* '-tkhtml-replacement-image' */ int iOrderedListStart; /* '-tkhtml-ordered-list-start' */ int iOrderedListValue; /* '-tkhtml-ordered-list-value' */ /* Properties not yet in use - TODO! */ unsigned char eUnicodeBidi; /* 'unicode-bidi' */ unsigned char eTableLayout; /* 'table-layout' */ HtmlCounterList *clCounterReset; HtmlCounterList *clCounterIncrement; /* 'font-size', 'font-family', 'font-style', 'font-weight' */ HtmlFont *fFont; /* INHERITED PROPERTIES START HERE */ unsigned char eListStyleType; /* 'list-style-type' */ unsigned char eListStylePosition; /* 'list-style-position' */ unsigned char eWhitespace; /* 'white-space' */ unsigned char eTextAlign; /* 'text-align' */ unsigned char eVisibility; /* 'visibility' */ HtmlColor *cColor; /* 'color' */ HtmlImage2 *imListStyleImage; /* 'list-style-image' */ int iTextIndent; /* 'text-indext' (pixels, %) */ int iBorderSpacing; /* 'border-spacing' (pixels) */ int iLineHeight; /* 'line-height' (pixels, %, NORMAL) */ unsigned char eFontVariant; /* 'font-variant' */ unsigned char eCursor; /* 'cursor' */ /* Properties not yet in use - TODO! */ int iWordSpacing; /* 'word-spacing' (pixels, NORMAL) */ int iLetterSpacing; /* 'letter-spacing' (pixels, NORMAL) */ unsigned char eTextTransform; /* 'text-transform' */ unsigned char eDirection; /* 'direction' */ unsigned char eBorderCollapse; /* 'border-collapse' */ unsigned char eCaptionSide; /* 'caption-side' */ unsigned char eEmptyCells; /* 'empty-cells' */ }; /* * If pzContent is not NULL, then the pointer it points to may be set * to point at allocated memory in which to store the computed value * of the 'content' property. */ struct HtmlComputedValuesCreator { HtmlComputedValues values; HtmlFontKey fontKey; HtmlTree *pTree; HtmlNode *pNode; /* Node to associate LOG with */ HtmlNode *pParent; /* Node to inherit from */ unsigned int em_mask; unsigned int ex_mask; int eVerticalAlignPercent; /* True if 'vertical-align' is a % */ CssProperty *pDeleteList; CssProperty *pContent; char **pzContent; }; /* * Percentage masks. * * According to the spec, the following CSS2 properties can also be set to * percentages: * * Unsupported properties: * 'background-position' * 'bottom', 'top', 'left', 'right' * 'text-indent' * * These can be set to percentages, but the styler can resolve them: * 'font-size', 'line-height', 'vertical-align' * * The HtmlComputedValues.mask mask also contains the * CONSTANT_MASK_VERTICALALIGN bit. If this bit is set, then * HtmlComputedValues.iVerticalAlign should be interpreted as a constant value * (like an HtmlComputedValues.eXXX variable). */ #define PROP_MASK_WIDTH 0x00000001 #define PROP_MASK_MIN_WIDTH 0x00000002 #define PROP_MASK_MAX_WIDTH 0x00000004 #define PROP_MASK_HEIGHT 0x00000008 #define PROP_MASK_MIN_HEIGHT 0x00000010 #define PROP_MASK_MAX_HEIGHT 0x00000020 #define PROP_MASK_MARGIN_TOP 0x00000040 #define PROP_MASK_MARGIN_RIGHT 0x00000080 #define PROP_MASK_MARGIN_BOTTOM 0x00000100 #define PROP_MASK_MARGIN_LEFT 0x00000200 #define PROP_MASK_PADDING_TOP 0x00000400 #define PROP_MASK_PADDING_RIGHT 0x00000800 #define PROP_MASK_PADDING_BOTTOM 0x00001000 #define PROP_MASK_PADDING_LEFT 0x00002000 #define PROP_MASK_VERTICAL_ALIGN 0x00004000 #define PROP_MASK_BORDER_TOP_WIDTH 0x00008000 #define PROP_MASK_BORDER_RIGHT_WIDTH 0x00010000 #define PROP_MASK_BORDER_BOTTOM_WIDTH 0x00020000 #define PROP_MASK_BORDER_LEFT_WIDTH 0x00040000 #define PROP_MASK_LINE_HEIGHT 0x00080000 #define PROP_MASK_BACKGROUND_POSITION_X 0x00100000 #define PROP_MASK_BACKGROUND_POSITION_Y 0x00200000 #define PROP_MASK_BORDER_SPACING 0x00400000 #define PROP_MASK_OUTLINE_WIDTH 0x00800000 #define PROP_MASK_TOP 0x01000000 #define PROP_MASK_BOTTOM 0x02000000 #define PROP_MASK_RIGHT 0x04000000 #define PROP_MASK_LEFT 0x08000000 #define PROP_MASK_TEXT_INDENT 0x10000000 #define PROP_MASK_WORD_SPACING 0x20000000 #define PROP_MASK_LETTER_SPACING 0x40000000 /* * Pixel values in the HtmlComputedValues struct may also take the following * special values. These are all very large negative numbers, unlikely to be * confused with real pixel counts. INT_MIN comes from , which is * supplied by Tcl if the operating system doesn't have it. */ #define PIXELVAL_AUTO (2 + (int)INT_MIN) #define PIXELVAL_NONE (3 + (int)INT_MIN) #define PIXELVAL_NORMAL (4 + (int)INT_MIN) #define MAX_PIXELVAL (5 + (int)INT_MIN) /* * API Notes for managing HtmlComputedValues structures: * * The following three functions are used by the styler phase to create and * populate an HtmlComputedValues structure (a set of property values for a * node): * * HtmlComputedValuesInit() (exactly one call) * HtmlComputedValuesSet() (zero or more calls) * HtmlComputedValuesFinish() (exactly one call) * * To use this API, the caller allocates (either on the heap or the stack, * doesn't matter) an HtmlComputedValuesCreator struct. The contents are * initialised by HtmlComputedValuesInit(). * * HtmlComputedValuesCreator sValues; * HtmlComputedValuesInit(pTree, pNode, &sValues); * * This initialises the HtmlComputedValuesCreator structure to contain the * default (called "initial" in the CSS spec) value for each property. The * default property values can be overwritten using the * HtmlComputedValuesSet() function (see comments above implementation * below). * * Finally, HtmlComputedValuesFinish() is called to obtain the populated * HtmlComputedValues structure. This function returns a pointer to an * HtmlComputedValues structure, which should be associated with the node * in question before it is passed to the layout engine: * * p = HtmlComputedValuesFinish(&sValues); * assert(p); * pNode->pPropertyValues = p; * * Once an HtmlComputedValues pointer returned by Finish() is no longer * required (when the node is being restyled or deleted), it should be * freed using: * * HtmlComputedValuesRelease(pNode->pPropertyValues); */ void HtmlComputedValuesInit( HtmlTree*, HtmlNode*, HtmlNode*, HtmlComputedValuesCreator*); int HtmlComputedValuesSet(HtmlComputedValuesCreator *, int, CssProperty*); HtmlComputedValues *HtmlComputedValuesFinish(HtmlComputedValuesCreator *); void HtmlComputedValuesFreeProperty(HtmlComputedValuesCreator*, CssProperty *); void HtmlComputedValuesRelease(HtmlTree *, HtmlComputedValues*); void HtmlComputedValuesReference(HtmlComputedValues *); /* * The following two functions are used to initialise and destroy the following * tables used by code in htmlprop.c. They are called as part of the * initialisation and destruction of the widget. * * HtmlTree.aColor * HtmlTree.aFont * HtmlTree.aValues * HtmlTree.aFontSizeTable */ void HtmlComputedValuesSetupTables(HtmlTree *); void HtmlComputedValuesCleanupTables(HtmlTree *); void HtmlComputedValuesFreePrototype(HtmlTree *); /* * Empty the font cache (i.e. because font config options have changed). */ void HtmlFontCacheClear(HtmlTree *, int); /* * This function formats the HtmlComputedValues structure as a Tcl list and * sets the result of the interpreter to that list. Used to allow inspection of * a nodes computed values from a Tcl script. */ int HtmlNodeProperties(Tcl_Interp *, HtmlComputedValues *); int HtmlNodeGetProperty(Tcl_Interp *, Tcl_Obj *, HtmlComputedValues *); /* * Determine if changing the computed properties of a node from one * argument structure to the other requires a re-layout. Return 1 if it * does, or 0 otherwise. */ int HtmlComputedValuesCompare(HtmlComputedValues *, HtmlComputedValues *); #define HTML_COMPUTED_MARGIN_TOP margin.iTop #define HTML_COMPUTED_MARGIN_RIGHT margin.iRight #define HTML_COMPUTED_MARGIN_BOTTOM margin.iBottom #define HTML_COMPUTED_MARGIN_LEFT margin.iLeft #define HTML_COMPUTED_PADDING_TOP padding.iTop #define HTML_COMPUTED_PADDING_RIGHT padding.iRight #define HTML_COMPUTED_PADDING_BOTTOM padding.iBottom #define HTML_COMPUTED_PADDING_LEFT padding.iLeft #define HTML_COMPUTED_PADDING_TOP padding.iTop #define HTML_COMPUTED_PADDING_RIGHT padding.iRight #define HTML_COMPUTED_PADDING_BOTTOM padding.iBottom #define HTML_COMPUTED_PADDING_LEFT padding.iLeft #define HTML_COMPUTED_TOP position.iTop #define HTML_COMPUTED_RIGHT position.iRight #define HTML_COMPUTED_BOTTOM position.iBottom #define HTML_COMPUTED_LEFT position.iLeft #define HTML_COMPUTED_HEIGHT iHeight #define HTML_COMPUTED_WIDTH iWidth #define HTML_COMPUTED_MIN_HEIGHT iMinHeight #define HTML_COMPUTED_MIN_WIDTH iMinWidth #define HTML_COMPUTED_MAX_HEIGHT iMaxHeight #define HTML_COMPUTED_MAX_WIDTH iMaxWidth #define HTML_COMPUTED_TEXT_INDENT iTextIndent /* The PIXELVAL macro takes three arguments: * * pV - Pointer to HtmlComputedValues structure. * * prop - Property identifier (i.e. MARGIN_LEFT). The * HTML_COMPUTED_XXX macros define the set of acceptable * identifiers. * * percent_of - The pixel value used to calculate percentage values against. * * Notes: * * * If percent_of is less than 0 (i.e. PIXELVAL_AUTO) and the property * specified by prop computed to a percentage, a copy of percent_of is * returned. * * * If pV==NULL, 0 is returned. */ #define PIXELVAL(pV, prop, percent_of) ( \ (!pV ? 0 : \ ((pV)->mask & PROP_MASK_ ## prop) ? ( \ ((percent_of) <= 0) ? (percent_of) : \ (((pV)-> HTML_COMPUTED_ ## prop * (percent_of)) / 10000) \ ) : ((pV)-> HTML_COMPUTED_ ## prop) \ )) #endif tkHTML-4ee7aaa953d6cb59/src/htmlsizer.c000064400000000000000000001402711151224263100170760ustar00nobodynobodystatic char const rcsid[] = "@(#) $Id: htmlsizer.c,v 1.44 2005/03/23 01:36:54 danielk1977 Exp $"; /* ** Routines used to compute the style and size of individual elements. ** ** This source code is released into the public domain by the author, ** D. Richard Hipp, on 2002 December 17. Instead of a license, here ** is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. */ #include #include #include #include "html.h" /* ** Get the current rendering style. In other words, get the style ** that is currently on the top of the style stack. */ static HtmlStyle GetCurrentStyle(htmlPtr) HtmlWidget *htmlPtr; { HtmlStyle style; if (htmlPtr->styleStack) { style = htmlPtr->styleStack->style; } else { style.font = NormalFont(2); style.color = COLOR_Normal; style.bgcolor = COLOR_Background; style.subscript = 0; style.align = ALIGN_Left; style.flags = 0; style.expbg = 0; } return style; } /* ** Push a new rendering style onto the stack. */ static void PushStyleStack(htmlPtr, tag, style) HtmlWidget *htmlPtr; /* Widget on which to push the style */ int tag; /* Tag for this style. Normally the * end-tag such as or . */ HtmlStyle style; /* The style to push */ { HtmlStyleStack *p; p = HtmlAlloc(sizeof(*p)); p->pNext = htmlPtr->styleStack; p->type = tag; p->style = style; htmlPtr->styleStack = p; } /* ** Pop a rendering style off of the stack. ** ** The top-most style on the stack should have a tag equal to "tag". ** If not, then we have an HTML coding error. Perhaps something ** like this: "Some text Enphasized more text". It is an ** interesting problem to figure out how to respond sanely to this ** kind of error. Our solution it to keep popping the stack until ** we find the correct tag, or until the stack is empty. */ HtmlStyle HtmlPopStyleStack(htmlPtr, tag) HtmlWidget *htmlPtr; int tag; { int type; HtmlStyleStack *p; static Html_u8 priority[Html_TypeCount + 1]; if (priority[Html_TABLE] == 0) { int i; for (i = 0; i <= Html_TypeCount; i++) priority[i] = 1; priority[Html_TD] = 2; priority[Html_EndTD] = 2; priority[Html_TH] = 2; priority[Html_EndTH] = 2; priority[Html_TR] = 3; priority[Html_EndTR] = 3; priority[Html_TABLE] = 4; priority[Html_EndTABLE] = 4; } if (tag <= 0 || tag > Html_TypeCount) { CANT_HAPPEN; return GetCurrentStyle(htmlPtr); } while ((p = htmlPtr->styleStack) != 0) { type = p->type; if (type <= 0 || type > Html_TypeCount) { CANT_HAPPEN; return GetCurrentStyle(htmlPtr); } if (type != tag && priority[type] > priority[tag]) { return GetCurrentStyle(htmlPtr); } htmlPtr->styleStack = p->pNext; HtmlFree(p); if (type == tag) { break; } } return GetCurrentStyle(htmlPtr); } /* ** Change the font size on the given style by the delta-amount given */ static void ScaleFont(pStyle, delta) HtmlStyle *pStyle; int delta; { int size = FontSize(pStyle->font) + delta; if (size < 0) { delta -= size; } else if (size > 6) { delta -= size - 6; } pStyle->font += delta; } /* ** Lookup an argument in the given markup with the name given. ** Return a pointer to its value, or the given default ** value if it doesn't appear. */ char * HtmlMarkupArg(p, tag, zDefault) HtmlElement *p; const char *tag; char *zDefault; { int i; if (!HtmlIsMarkup(p)) { return 0; } for (i = 0; i < p->base.count; i += 2) { if (strcmp(p->markup.argv[i], tag) == 0) { return p->markup.argv[i + 1]; } } return zDefault; } /* ** Return an alignment or justification flag associated with the ** given markup. The given default value is returned if no alignment is ** specified. */ static int GetAlignment(p, dflt) HtmlElement *p; int dflt; { char *z = HtmlMarkupArg(p, "align", 0); int rc = dflt; if (z) { if (stricmp(z, "left") == 0) { rc = ALIGN_Left; } else if (stricmp(z, "right") == 0) { rc = ALIGN_Right; } else if (stricmp(z, "center") == 0) { rc = ALIGN_Center; } } return rc; } /* ** The "type" argument to the given element might describe the type ** for an ordered list. Return the corresponding LI_TYPE_* entry ** if this is the case, or the default value if it isn't. */ static int GetOrderedListType(p, dflt) HtmlElement *p; int dflt; { char *z; z = HtmlMarkupArg(p, "type", 0); if (z) { switch (*z) { case 'A': dflt = LI_TYPE_Enum_A; break; case 'a': dflt = LI_TYPE_Enum_a; break; case '1': dflt = LI_TYPE_Enum_1; break; case 'I': dflt = LI_TYPE_Enum_I; break; case 'i': dflt = LI_TYPE_Enum_i; break; default: break; } } else { } return dflt; } /* ** The "type" argument to the given element might describe a type ** for an unordered list. Return the corresponding LI_TYPE entry ** if this is the case, or the default value if it isn't. */ static int GetUnorderedListType(p, dflt) HtmlElement *p; int dflt; { char *z; z = HtmlMarkupArg(p, "type", 0); if (z) { if (stricmp(z, "disc") == 0) { dflt = LI_TYPE_Bullet1; } else if (stricmp(z, "circle") == 0) { dflt = LI_TYPE_Bullet2; } else if (stricmp(z, "square") == 0) { dflt = LI_TYPE_Bullet3; } } return dflt; } /* ** Add the STY_Invisible style to every token between pFirst and pLast. */ static void MakeInvisible(pFirst, pLast) HtmlElement *pFirst; HtmlElement *pLast; { if (pFirst == 0) return; pFirst = pFirst->pNext; while (pFirst && pFirst != pLast) { pFirst->base.style.flags |= STY_Invisible; pFirst = pFirst->pNext; } } /* ** For the markup , find out if the URL has been visited ** before or not. Return COLOR_Visited or COLOR_Unvisited, as ** appropriate. ** ** This routine may invoke a callback procedure which could delete ** the HTML widget. The calling function should call HtmlLock() ** if it needs the widget structure to be preserved. */ static int GetLinkColor(htmlPtr, zURL) HtmlWidget *htmlPtr; char *zURL; { char *zCmd; int result; int isVisited; if (htmlPtr->tkwin == 0) { return COLOR_Normal; } if (htmlPtr->zIsVisited == 0 || htmlPtr->zIsVisited[0] == 0) { return COLOR_Unvisited; } zCmd = HtmlAlloc(strlen(htmlPtr->zIsVisited) + strlen(zURL) + 10); if (zCmd == 0) { return COLOR_Unvisited; } sprintf(zCmd, "%s {%s}", htmlPtr->zIsVisited, zURL); HtmlLock(htmlPtr); result = Tcl_GlobalEval(htmlPtr->interp, zCmd); HtmlFree(zCmd); if (HtmlUnlock(htmlPtr)) { return COLOR_Unvisited; } if (result != TCL_OK) { goto errorOut; } result = Tcl_GetBoolean(htmlPtr->interp, htmlPtr->interp->result, &isVisited); if (result != TCL_OK) { goto errorOut; } return isVisited ? COLOR_Visited : COLOR_Unvisited; errorOut: Tcl_AddErrorInfo(htmlPtr->interp, "\n (\"-isvisitedcommand\" command executed by html widget)"); Tcl_BackgroundError(htmlPtr->interp); return COLOR_Unvisited; } static int * GetCoords(str, nptr) char *str; int *nptr; { char *cp = str, *ncp; int i, n = 0, sz = 4, *cr; cr = (int *) HtmlAlloc(sz * sizeof(int)); while (cp) { while (*cp && (!isdigit(*cp))) cp++; if ((!*cp) || (!isdigit(*cp))) break; cr[n] = (int) strtol(cp, &ncp, 10); if (cp == ncp) break; cp = ncp; n++; if (n >= sz) { sz += 4; cr = (int *) HtmlRealloc((char *) cr, sz * sizeof(int)); } } *nptr = n; return cr; } /* ** This routine adds information to the input texts that doesn't change ** when the display is resized or when new fonts are selected, etc. ** Mostly this means adding style attributes. But other constant ** information (such as numbering on
  • and images used for ) ** is also obtained. The key is that this routine is only called ** once, where the sizer and layout routines can be called many times. ** ** This routine is called whenever the list of elements grows. The ** style stack is stored as part of the HTML widget so that we can ** always continue where we left off the last time. ** ** In addition to adding style, this routine will invoke callbacks ** needed to acquire information about a markup. The htmlPtr->zIsVisitied ** callback is called for each and the htmlPtr->zGetImage is called ** for each or for each
  • that has a SRC= field. ** ** This routine may invoke a callback procedure which could delete ** the HTML widget. ** ** When a markup is inserted or deleted from the token list, the ** style routine must be completely rerun from the beginning. So ** what we said above, that this routine is only run once, is not ** strictly true. */ void HtmlAddStyle(htmlPtr, p) HtmlWidget *htmlPtr; HtmlElement *p; { HtmlStyle style; /* Current style */ int size; /* A new font size */ int i; /* Loop counter */ int paraAlign; /* Current paragraph alignment */ int rowAlign; /* Current table row alignment */ int anchorFlags; /* Flags associated with tag */ int inDt; /* True if within
    ..
    */ HtmlStyle nextStyle; /* Style for next token if * useNextStyle==1 */ int useNextStyle = 0; /* True if nextStyle is valid */ char *z; /* A tag parameter's value */ /* * The size of header fonts relative to the current font size */ static int header_sizes[] = { +2, +1, 1, 1, -1, -1 }; /* * Don't allow recursion */ if (htmlPtr->flags & STYLER_RUNNING) { return; } htmlPtr->flags |= STYLER_RUNNING; /* * Load the style state out of the htmlPtr structure and into local ** * variables. This is purely a matter of convenience... */ style = GetCurrentStyle(htmlPtr); paraAlign = htmlPtr->paraAlignment; rowAlign = htmlPtr->rowAlignment; anchorFlags = htmlPtr->anchorFlags; inDt = htmlPtr->inDt; /* * Loop over tokens */ while (htmlPtr->pFirst && p) { switch (p->base.type) { case Html_A: if (htmlPtr->anchorStart) { style = HtmlPopStyleStack(htmlPtr, Html_EndA); htmlPtr->anchorStart = 0; anchorFlags = 0; } z = HtmlMarkupArg(p, "href", 0); if (z) { HtmlLock(htmlPtr); style.color = GetLinkColor(htmlPtr, z); if (htmlPtr->underlineLinks) { style.flags |= STY_Underline; } if (HtmlUnlock(htmlPtr)) return; anchorFlags |= STY_Anchor; PushStyleStack(htmlPtr, Html_EndA, style); htmlPtr->anchorStart = p; } break; case Html_EndA: if (htmlPtr->anchorStart) { p->ref.pOther = htmlPtr->anchorStart; style = HtmlPopStyleStack(htmlPtr, Html_EndA); htmlPtr->anchorStart = 0; anchorFlags = 0; } break; case Html_MAP: break; case Html_EndMAP: break; case Html_AREA: z = HtmlMarkupArg(p, "shape", 0); p->area.type = MAP_RECT; if (z) { if (!strcasecmp(z, "circle")) p->area.type = MAP_CIRCLE; else if (!strcasecmp(z, "poly")) p->area.type = MAP_POLY; } z = HtmlMarkupArg(p, "coords", 0); if (z) { p->area.coords = GetCoords(z, &p->area.num); } break; case Html_ADDRESS: case Html_EndADDRESS: case Html_BLOCKQUOTE: case Html_EndBLOCKQUOTE: paraAlign = ALIGN_None; break; case Html_APPLET: if (htmlPtr->zAppletCommand && *htmlPtr->zAppletCommand) { nextStyle = style; nextStyle.flags |= STY_Invisible; PushStyleStack(htmlPtr, Html_EndAPPLET, nextStyle); useNextStyle = 1; } else { PushStyleStack(htmlPtr, Html_EndAPPLET, style); } break; case Html_B: style.font = BoldFont(FontSize(style.font)); PushStyleStack(htmlPtr, Html_EndB, style); break; case Html_EndAPPLET: case Html_EndB: case Html_EndBIG: case Html_EndCENTER: case Html_EndCITE: case Html_EndCODE: case Html_EndCOMMENT: case Html_EndEM: case Html_EndFONT: case Html_EndI: case Html_EndKBD: case Html_EndMARQUEE: case Html_EndNOBR: case Html_EndNOFRAMES: case Html_EndNOSCRIPT: case Html_EndNOEMBED: case Html_EndS: case Html_EndSAMP: case Html_EndSMALL: case Html_EndSTRIKE: case Html_EndSTRONG: case Html_EndSUB: case Html_EndSUP: case Html_EndTITLE: case Html_EndTT: case Html_EndU: case Html_EndVAR: style = HtmlPopStyleStack(htmlPtr, p->base.type); break; case Html_BASE: z = HtmlMarkupArg(p, "href", 0); if (z) { HtmlLock(htmlPtr); z = HtmlResolveUri(htmlPtr, z); if (HtmlUnlock(htmlPtr)) { if (z) HtmlFree(z); return; } if (z != 0) { if (htmlPtr->zBaseHref) { HtmlFree(htmlPtr->zBaseHref); } htmlPtr->zBaseHref = z; } } break; case Html_EndDIV: paraAlign = ALIGN_None; style = HtmlPopStyleStack(htmlPtr, p->base.type); break; case Html_EndBASEFONT: style = HtmlPopStyleStack(htmlPtr, Html_EndBASEFONT); style.font = FontFamily(style.font) + 2; break; case Html_BIG: ScaleFont(&style, 1); PushStyleStack(htmlPtr, Html_EndBIG, style); break; case Html_CAPTION: paraAlign = GetAlignment(p, paraAlign); break; case Html_EndCAPTION: paraAlign = ALIGN_None; break; case Html_CENTER: paraAlign = ALIGN_None; style.align = ALIGN_Center; PushStyleStack(htmlPtr, Html_EndCENTER, style); break; case Html_CITE: PushStyleStack(htmlPtr, Html_EndCITE, style); break; case Html_CODE: style.font = CWFont(FontSize(style.font)); PushStyleStack(htmlPtr, Html_EndCODE, style); break; case Html_COMMENT: style.flags |= STY_Invisible; PushStyleStack(htmlPtr, Html_EndCOMMENT, style); break; case Html_DD: if (htmlPtr->innerList && htmlPtr->innerList->base.type == Html_DL) { p->ref.pOther = htmlPtr->innerList; } else { p->ref.pOther = 0; } inDt = 0; break; case Html_DIR: case Html_MENU: case Html_UL: p->list.pPrev = htmlPtr->innerList; p->list.cnt = 0; htmlPtr->innerList = p; if (p->list.pPrev == 0) { p->list.type = LI_TYPE_Bullet1; p->list.compact = HtmlMarkupArg(p, "compact", 0) != 0; } else if (p->list.pPrev->list.pPrev == 0) { p->list.type = LI_TYPE_Bullet2; p->list.compact = 1; } else { p->list.type = LI_TYPE_Bullet3; p->list.compact = 1; } p->list.type = GetUnorderedListType(p, p->list.type); break; case Html_EndDL: inDt = 0; /* * Fall thru into the next case */ case Html_EndDIR: case Html_EndMENU: case Html_EndOL: case Html_EndUL: p->ref.pOther = htmlPtr->innerList; if (htmlPtr->innerList) { htmlPtr->innerList = htmlPtr->innerList->list.pPrev; } else { } break; case Html_DIV: paraAlign = ALIGN_None; style.align = GetAlignment(p, style.align); PushStyleStack(htmlPtr, Html_EndDIV, style); break; case Html_DT: if (htmlPtr->innerList && htmlPtr->innerList->base.type == Html_DL) { p->ref.pOther = htmlPtr->innerList; } else { p->ref.pOther = 0; } inDt = STY_DT; break; case Html_EndDD: case Html_EndDT: inDt = 0; break; case Html_DL: p->list.pPrev = htmlPtr->innerList; p->list.cnt = 0; htmlPtr->innerList = p; p->list.compact = HtmlMarkupArg(p, "compact", 0) != 0; inDt = 0; break; case Html_EM: style.font = ItalicFont(FontSize(style.font)); PushStyleStack(htmlPtr, Html_EndEM, style); break; case Html_EMBED: break; case Html_BASEFONT: case Html_FONT: z = HtmlMarkupArg(p, "size", 0); if (z && (!htmlPtr->overrideFonts)) { if (*z == '-') { size = FontSize(style.font) - atoi(&z[1]) + 1; } else if (*z == '+') { size = FontSize(style.font) + atoi(&z[1]); } else { size = atoi(z); } if (size <= 0) { size = 1; } if (size >= N_FONT_SIZE) { size = N_FONT_SIZE - 1; } style.font = FontFamily(style.font) + size - 1; } z = HtmlMarkupArg(p, "color", 0); if (z && z[0] && (!htmlPtr->overrideColors)) { style.color = HtmlGetColorByName(htmlPtr, z, style.color); } PushStyleStack(htmlPtr, p->base.type == Html_FONT ? Html_EndFONT : Html_EndBASEFONT, style); break; case Html_FORM:{ char *zUrl; char *zMethod; Tcl_DString cmd; /* -formcommand callback */ int result; char zToken[50]; htmlPtr->formStart = 0; /* p->form.id = 0; */ if (htmlPtr->zFormCommand == 0 || htmlPtr->zFormCommand[0] == 0) { TestPoint(0); break; } zUrl = HtmlMarkupArg(p, "action", 0); if (zUrl == 0) { TestPoint(0); /* * break; */ zUrl = htmlPtr->zBase; } HtmlLock(htmlPtr); zUrl = HtmlResolveUri(htmlPtr, zUrl); if (HtmlUnlock(htmlPtr)) { if (zUrl) HtmlFree(zUrl); return; } if (zUrl == 0) zUrl = strdup(""); zMethod = HtmlMarkupArg(p, "method", "GET"); sprintf(zToken, " %d form {} ", p->form.id); Tcl_DStringInit(&cmd); Tcl_DStringAppend(&cmd, htmlPtr->zFormCommand, -1); Tcl_DStringAppend(&cmd, zToken, -1); Tcl_DStringAppendElement(&cmd, zUrl); HtmlFree(zUrl); Tcl_DStringAppendElement(&cmd, zMethod); Tcl_DStringStartSublist(&cmd); HtmlAppendArglist(&cmd, p); Tcl_DStringEndSublist(&cmd); HtmlLock(htmlPtr); htmlPtr->inParse++; result = Tcl_GlobalEval(htmlPtr->interp, Tcl_DStringValue(&cmd)); htmlPtr->inParse--; Tcl_DStringFree(&cmd); if (HtmlUnlock(htmlPtr)) return; if (result == TCL_OK) { htmlPtr->formStart = p; } else { Tcl_AddErrorInfo(htmlPtr->interp, "\n (\"-formcommand\" command executed by html widget)"); Tcl_BackgroundError(htmlPtr->interp); } Tcl_ResetResult(htmlPtr->interp); break; } case Html_EndFORM: p->ref.pOther = htmlPtr->formStart; if (htmlPtr->formStart) htmlPtr->formStart->form.pEnd = p; htmlPtr->formStart = 0; break; case Html_H1: case Html_H2: case Html_H3: case Html_H4: case Html_H5: case Html_H6: paraAlign = ALIGN_None; i = (p->base.type - Html_H1) / 2 + 1; if (i >= 1 && i <= 6) { ScaleFont(&style, header_sizes[i - 1]); } style.font = BoldFont(FontSize(style.font)); style.align = GetAlignment(p, style.align); PushStyleStack(htmlPtr, Html_EndH1, style); break; case Html_EndH1: case Html_EndH2: case Html_EndH3: case Html_EndH4: case Html_EndH5: case Html_EndH6: paraAlign = ALIGN_None; style = HtmlPopStyleStack(htmlPtr, Html_EndH1); break; case Html_HR: nextStyle = style; style.align = GetAlignment(p, ALIGN_None); useNextStyle = 1; break; case Html_I: style.font = ItalicFont(FontSize(style.font)); PushStyleStack(htmlPtr, Html_EndI, style); break; case Html_IMG: if (style.flags & STY_Invisible) break; HtmlLock(htmlPtr); p->image.pImage = HtmlGetImage(htmlPtr, p); if (HtmlUnlock(htmlPtr)) return; break; case Html_OPTION: break; case Html_INPUT: p->input.pForm = htmlPtr->formStart; if (htmlPtr->TclHtml) HtmlControlSize(htmlPtr, p); break; case Html_KBD: style.font = CWFont(FontSize(style.font)); PushStyleStack(htmlPtr, Html_EndKBD, style); break; case Html_LI: if (htmlPtr->innerList) { p->li.type = htmlPtr->innerList->list.type; if (htmlPtr->innerList->base.type == Html_OL) { z = HtmlMarkupArg(p, "value", 0); if (z) { int n = atoi(z); if (n > 0) { p->li.cnt = n; htmlPtr->innerList->list.cnt = n + 1; } else { } } else { p->li.cnt = htmlPtr->innerList->list.cnt++; } p->li.type = GetOrderedListType(p, p->li.type); } else { p->li.type = GetUnorderedListType(p, p->li.type); } } else { p->base.flags &= ~HTML_Visible; } break; case Html_MARQUEE: style.flags |= STY_Invisible; PushStyleStack(htmlPtr, Html_EndMARQUEE, style); break; case Html_NOBR: style.flags |= STY_NoBreak; PushStyleStack(htmlPtr, Html_EndNOBR, style); break; case Html_NOFRAMES: if (htmlPtr->zFrameCommand && *htmlPtr->zFrameCommand) { nextStyle = style; nextStyle.flags |= STY_Invisible; PushStyleStack(htmlPtr, Html_EndNOFRAMES, nextStyle); useNextStyle = 1; } else { PushStyleStack(htmlPtr, Html_EndNOFRAMES, style); } break; case Html_NOEMBED: if (htmlPtr->zScriptCommand && *htmlPtr->zScriptCommand && htmlPtr->HasScript) { nextStyle = style; nextStyle.flags |= STY_Invisible; PushStyleStack(htmlPtr, Html_EndNOEMBED, nextStyle); useNextStyle = 1; } else { PushStyleStack(htmlPtr, Html_EndNOEMBED, style); } break; case Html_NOSCRIPT: if (htmlPtr->zScriptCommand && *htmlPtr->zScriptCommand && htmlPtr->HasScript) { nextStyle = style; nextStyle.flags |= STY_Invisible; PushStyleStack(htmlPtr, Html_EndNOSCRIPT, nextStyle); useNextStyle = 1; } else { PushStyleStack(htmlPtr, Html_EndNOSCRIPT, style); } break; case Html_OL: p->list.pPrev = htmlPtr->innerList; p->list.type = GetOrderedListType(p, LI_TYPE_Enum_1); p->list.cnt = 1; z = HtmlMarkupArg(p, "start", 0); if (z) { int n = atoi(z); if (n > 0) { p->list.cnt = n; } else { } } else { } p->list.compact = htmlPtr->innerList != 0 || HtmlMarkupArg(p, "compact", 0) != 0; htmlPtr->innerList = p; break; case Html_P: paraAlign = GetAlignment(p, ALIGN_None); break; case Html_EndP: paraAlign = ALIGN_None; break; case Html_PRE: case Html_LISTING: case Html_XMP: case Html_PLAINTEXT: paraAlign = ALIGN_None; style.font = CWFont(FontSize(style.font)); style.flags |= STY_Preformatted; PushStyleStack(htmlPtr, Html_EndPRE, style); break; case Html_EndPRE: case Html_EndLISTING: case Html_EndXMP: style = HtmlPopStyleStack(htmlPtr, Html_EndPRE); break; case Html_S: style.flags |= STY_StrikeThru; PushStyleStack(htmlPtr, Html_EndS, style); break; case Html_SCRIPT: #if 0 if (htmlPtr->zScriptCommand && *htmlPtr->zScriptCommand) { Tcl_DString cmd; char *resstr; int result, reslen; Tcl_DStringInit(&cmd); Tcl_DStringAppend(&cmd, htmlPtr->zScriptCommand, -1); Tcl_DStringStartSublist(&cmd); HtmlAppendArglist(&cmd, p); Tcl_DStringEndSublist(&cmd); Tcl_DStringStartSublist(&cmd); Tcl_DStringAppend(&cmd, p->script.zScript, p->script.nScript); Tcl_DStringEndSublist(&cmd); HtmlLock(htmlPtr); htmlPtr->inParse++; result = Tcl_GlobalEval(htmlPtr->interp, Tcl_DStringValue(&cmd)); htmlPtr->inParse--; Tcl_DStringFree(&cmd); if (HtmlUnlock(htmlPtr)) return; resstr = Tcl_GetByteArrayObj(Tcl_GetObjResult (htmlPtr->interp->result), &reslen); if (result == 0 && resstr && reslen) { HtmlElement *b2 = p->pNext, *b3, *ps, *e1 = p, *e2 = b2, *e3; if (e2) while (e2->pNext) e2 = e2->pNext; HtmlTokenizerAppend(htmlPtr, resstr, reslen); if (e2 && e2 != p && ((e3 = b3 = e2->pNext))) { while (e3->pNext) e3 = e3->pNext; e1->pNext = b3; e2->pNext = 0; b2->base.pPrev = e3; e3->pNext = b2; b3->base.pPrev = e1; } } Tcl_ResetResult(htmlPtr->interp); } #endif nextStyle = style; style.flags |= STY_Invisible; useNextStyle = 1; break; case Html_SELECT: p->input.pForm = htmlPtr->formStart; nextStyle.flags |= STY_Invisible; useNextStyle = 1; PushStyleStack(htmlPtr, Html_EndSELECT, style); htmlPtr->formElemStart = p; break; case Html_EndSELECT: style = HtmlPopStyleStack(htmlPtr, Html_EndSELECT); if (htmlPtr->formElemStart && htmlPtr->formElemStart->base.type == Html_SELECT) { p->ref.pOther = htmlPtr->formElemStart; MakeInvisible(p->ref.pOther, p); } else { p->ref.pOther = 0; } htmlPtr->formElemStart = 0; break; case Html_STRIKE: style.flags |= STY_StrikeThru; PushStyleStack(htmlPtr, Html_EndSTRIKE, style); break; case Html_STYLE: /* * Ignore style sheets */ break; case Html_SAMP: style.font = CWFont(FontSize(style.font)); PushStyleStack(htmlPtr, Html_EndSAMP, style); break; case Html_SMALL: ScaleFont(&style, -1); PushStyleStack(htmlPtr, Html_EndSMALL, style); break; case Html_STRONG: style.font = BoldFont(FontSize(style.font)); PushStyleStack(htmlPtr, Html_EndSTRONG, style); break; case Html_SUB: ScaleFont(&style, -1); if (style.subscript > -6) { style.subscript--; } else { } PushStyleStack(htmlPtr, Html_EndSUB, style); break; case Html_SUP: ScaleFont(&style, -1); if (style.subscript < 6) { style.subscript++; } else { } PushStyleStack(htmlPtr, Html_EndSUP, style); break; case Html_TABLE: if (p->table.tktable) { if (p->table.pEnd = HtmlFindEndNest(htmlPtr, p, Html_EndTABLE, 0)) MakeInvisible(p, p->table.pEnd); if (p->table.pEnd) { p = p->table.pEnd; break; } } paraAlign = ALIGN_None; nextStyle = style; if (style.flags & STY_Preformatted) { nextStyle.flags &= ~STY_Preformatted; style.flags |= STY_Preformatted; } nextStyle.align = ALIGN_Left; z = HtmlMarkupArg(p, "bgcolor", 0); if (z && z[0] && (!htmlPtr->overrideColors)) { style.bgcolor = nextStyle.bgcolor = HtmlGetColorByName(htmlPtr, z, style.bgcolor); style.expbg = 1; /* }else{ nextStyle.bgcolor = COLOR_Background; */ } HtmlTableBgImage(htmlPtr, p); PushStyleStack(htmlPtr, Html_EndTABLE, nextStyle); useNextStyle = 1; htmlPtr->inTd = 0; htmlPtr->inTr = 0; break; case Html_EndTABLE: paraAlign = ALIGN_None; if (htmlPtr->inTd) { style = HtmlPopStyleStack(htmlPtr, Html_EndTD); htmlPtr->inTd = 0; } if (htmlPtr->inTr) { style = HtmlPopStyleStack(htmlPtr, Html_EndTR); htmlPtr->inTr = 0; } style = HtmlPopStyleStack(htmlPtr, p->base.type); break; case Html_TD: if (htmlPtr->inTd) { style = HtmlPopStyleStack(htmlPtr, Html_EndTD); } htmlPtr->inTd = 1; paraAlign = GetAlignment(p, rowAlign); if ((z = HtmlMarkupArg(p, "bgcolor", 0)) != 0 && z[0] && (!htmlPtr->overrideColors)) { style.bgcolor = HtmlGetColorByName(htmlPtr, z, style.bgcolor); style.expbg = 1; } HtmlTableBgImage(htmlPtr, p); PushStyleStack(htmlPtr, Html_EndTD, style); break; case Html_TEXTAREA: p->input.pForm = htmlPtr->formStart; nextStyle = style; nextStyle.flags |= STY_Invisible; PushStyleStack(htmlPtr, Html_EndTEXTAREA, nextStyle); htmlPtr->formElemStart = p; useNextStyle = 1; break; case Html_EndTEXTAREA: style = HtmlPopStyleStack(htmlPtr, Html_EndTEXTAREA); if (htmlPtr->formElemStart && htmlPtr->formElemStart->base.type == Html_TEXTAREA) { p->ref.pOther = htmlPtr->formElemStart; } else { p->ref.pOther = 0; } htmlPtr->formElemStart = 0; break; case Html_TH: /* * paraAlign = GetAlignment(p, rowAlign); */ if (htmlPtr->inTd) { style = HtmlPopStyleStack(htmlPtr, Html_EndTD); } paraAlign = GetAlignment(p, ALIGN_Center); style.font = BoldFont(FontSize(style.font)); if ((z = HtmlMarkupArg(p, "bgcolor", 0)) != 0 && z[0]) { style.bgcolor = HtmlGetColorByName(htmlPtr, z, style.bgcolor); style.expbg = 1; } HtmlTableBgImage(htmlPtr, p); PushStyleStack(htmlPtr, Html_EndTD, style); htmlPtr->inTd = 1; break; case Html_TR: if (htmlPtr->inTd) { style = HtmlPopStyleStack(htmlPtr, Html_EndTD); htmlPtr->inTd = 0; } if (htmlPtr->inTr) { style = HtmlPopStyleStack(htmlPtr, Html_EndTR); } rowAlign = GetAlignment(p, ALIGN_None); if ((z = HtmlMarkupArg(p, "bgcolor", 0)) != 0 && z[0] && (!htmlPtr->overrideColors)) { style.bgcolor = HtmlGetColorByName(htmlPtr, z, style.bgcolor); style.expbg = 1; } HtmlTableBgImage(htmlPtr, p); PushStyleStack(htmlPtr, Html_EndTR, style); htmlPtr->inTr = 1; break; case Html_EndTR: if (htmlPtr->inTd) { style = HtmlPopStyleStack(htmlPtr, Html_EndTD); htmlPtr->inTd = 0; } style = HtmlPopStyleStack(htmlPtr, Html_EndTR); htmlPtr->inTr = 0; paraAlign = ALIGN_None; rowAlign = ALIGN_None; break; case Html_EndTD: case Html_EndTH: style = HtmlPopStyleStack(htmlPtr, Html_EndTD); htmlPtr->inTd = 0; paraAlign = ALIGN_None; rowAlign = ALIGN_None; break; case Html_TITLE: style.flags |= STY_Invisible; PushStyleStack(htmlPtr, Html_EndTITLE, style); break; case Html_TT: style.font = CWFont(FontSize(style.font)); PushStyleStack(htmlPtr, Html_EndTT, style); break; case Html_U: style.flags |= STY_Underline; PushStyleStack(htmlPtr, Html_EndU, style); break; case Html_VAR: style.font = ItalicFont(FontSize(style.font)); PushStyleStack(htmlPtr, Html_EndVAR, style); break; default: break; } p->base.style = style; p->base.style.flags |= anchorFlags | inDt; if (paraAlign != ALIGN_None) { p->base.style.align = paraAlign; } if (useNextStyle) { style = nextStyle; style.expbg = 0; useNextStyle = 0; } TRACE(HtmlTrace_Style, ("Style of 0x%08x font=%02d color=%02d bg=%02d " "align=%d flags=0x%04x token=%s\n", (int) p, p->base.style.font, p->base.style.color, p->base.style.bgcolor, p->base.style.align, p->base.style.flags, HtmlTokenName(htmlPtr, p))); p = p->pNext; } /* * Copy state information back into the htmlPtr structure for ** safe * keeping. */ htmlPtr->paraAlignment = paraAlign; htmlPtr->rowAlignment = rowAlign; htmlPtr->anchorFlags = anchorFlags; htmlPtr->inDt = inDt; htmlPtr->flags &= ~STYLER_RUNNING; } void HtmlTableBgImage(htmlPtr, p) HtmlWidget *htmlPtr; HtmlElement *p; { #ifndef _TCLHTML_ Tcl_DString cmd; int result; char *z, buf[30]; if (htmlPtr->TclHtml) return; if ((!htmlPtr->zGetBGImage) || (!*htmlPtr->zGetBGImage)) return; if (!(z = HtmlMarkupArg(p, "background", 0))) return; Tcl_DStringInit(&cmd); Tcl_DStringAppend(&cmd, htmlPtr->zGetBGImage, -1); Tcl_DStringAppend(&cmd, " ", 1); Tcl_DStringAppend(&cmd, z, -1); sprintf(buf, " %d", p->base.id); Tcl_DStringAppend(&cmd, buf, -1); HtmlLock(htmlPtr); htmlPtr->inParse++; result = Tcl_GlobalEval(htmlPtr->interp, Tcl_DStringValue(&cmd)); htmlPtr->inParse--; Tcl_DStringFree(&cmd); if (HtmlUnlock(htmlPtr)) return; if (result == TCL_OK) HtmlSetImageBg(htmlPtr, htmlPtr->interp, htmlPtr->interp->result, p); Tcl_ResetResult(htmlPtr->interp); #endif } /* ** Compute the size of all elements in the widget. Assume that a ** style has already been assigned to all elements. ** ** Some of the elements might have already been sized. Refer to the ** htmlPtr->lastSized and only compute sizes for elements that follow ** this one. If htmlPtr->lastSized==0, then size everything. ** ** This routine only computes the sizes of individual elements. The ** size of aggregate elements (like tables) are computed separately. ** ** The HTML_Visible flag is also set on every element that results ** in ink on the page. ** ** This routine may invoke a callback procedure which could delete ** the HTML widget. */ void HtmlSizer(htmlPtr) HtmlWidget *htmlPtr; { HtmlElement *p; int iFont = -1; Tk_Font font = 0; int spaceWidth = 0; Tk_FontMetrics fontMetrics; char *z; int stop = 0; if (htmlPtr->pFirst == 0) { return; } if (htmlPtr->lastSized == 0) { p = htmlPtr->pFirst; } else { p = htmlPtr->lastSized->pNext; } for (; !stop && p; p = p ? p->pNext : 0) { if (p->base.style.flags & STY_Invisible) { p->base.flags &= ~HTML_Visible; continue; } if (iFont != p->base.style.font) { iFont = p->base.style.font; HtmlLock(htmlPtr); #ifndef _TCLHTML_ font = HtmlGetFont(htmlPtr, iFont); if (HtmlUnlock(htmlPtr)) break; Tk_GetFontMetrics(font, &fontMetrics); #else fontMetrics.descent = 1; fontMetrics.ascent = 9; #endif spaceWidth = 0; } switch (p->base.type) { case Html_Text: #ifndef _TCLHTML_ p->text.w = Tk_TextWidth(font, p->text.zText, p->base.count); p->base.flags |= HTML_Visible; p->text.descent = fontMetrics.descent; p->text.ascent = fontMetrics.ascent; if (spaceWidth == 0) { spaceWidth = Tk_TextWidth(font, " ", 1); } else { } p->text.spaceWidth = spaceWidth; #else p->text.w = 10; p->base.flags |= HTML_Visible; p->text.descent = 1; p->text.ascent = 9; if (spaceWidth == 0) { spaceWidth = 10; TestPoint(0); } else { TestPoint(0); } p->text.spaceWidth = spaceWidth; #endif break; case Html_Space: if (spaceWidth == 0) { #ifndef _TCLHTML_ spaceWidth = Tk_TextWidth(font, " ", 1); #else spaceWidth = 10; #endif } p->space.w = spaceWidth; p->space.descent = fontMetrics.descent; p->space.ascent = fontMetrics.ascent; p->base.flags &= ~HTML_Visible; break; case Html_TD: case Html_TH: z = HtmlMarkupArg(p, "rowspan", "1"); p->cell.rowspan = atoi(z); z = HtmlMarkupArg(p, "colspan", "1"); p->cell.colspan = atoi(z); p->base.flags |= HTML_Visible; break; case Html_LI: p->li.descent = fontMetrics.descent; p->li.ascent = fontMetrics.ascent; p->base.flags |= HTML_Visible; break; case Html_IMG: #ifndef _TCLHTML_ z = HtmlMarkupArg(p, "usemap", 0); if (z && *z == '#') { p->image.pMap = HtmlGetMap(htmlPtr, z + 1); } else p->image.pMap = 0; p->base.flags |= HTML_Visible; p->image.redrawNeeded = 0; p->image.textAscent = fontMetrics.ascent; p->image.textDescent = fontMetrics.descent; p->image.align = HtmlGetImageAlignment(p); if (p->image.pImage == 0) { p->image.ascent = fontMetrics.ascent; p->image.descent = fontMetrics.descent; p->image.zAlt = HtmlMarkupArg(p, "alt", ""); p->image.w = Tk_TextWidth(font, p->image.zAlt, strlen(p->image.zAlt)); } else { int w, h; p->image.pNext = p->image.pImage->pList; p->image.pImage->pList = p; Tk_SizeOfImage(p->image.pImage->image, &w, &h); p->image.h = h; p->image.w = w; p->image.ascent = h / 2; p->image.descent = h - p->image.ascent; } if ((z = HtmlMarkupArg(p, "width", 0)) != 0) { int w = atoi(z); if (w > 0) p->image.w = w; } if ((z = HtmlMarkupArg(p, "height", 0)) != 0) { int h = atoi(z); if (h > 0) p->image.h = h; } #endif /* _TCLHTML_ */ break; case Html_TABLE: if (p->table.tktable) { p = p->table.pEnd; break; } case Html_HR: p->base.flags |= HTML_Visible; break; case Html_APPLET: case Html_EMBED: case Html_INPUT: p->input.textAscent = fontMetrics.ascent; p->input.textDescent = fontMetrics.descent; stop = HtmlControlSize(htmlPtr, p); break; case Html_SELECT: case Html_TEXTAREA: p->input.textAscent = fontMetrics.ascent; p->input.textDescent = fontMetrics.descent; break; case Html_EndSELECT: case Html_EndTEXTAREA: if (p->ref.pOther) { p->ref.pOther->input.pEnd = p; stop = HtmlControlSize(htmlPtr, p->ref.pOther); } break; default: p->base.flags &= ~HTML_Visible; break; } } if (p) { htmlPtr->lastSized = p; } else { htmlPtr->lastSized = htmlPtr->pLast; } } tkHTML-4ee7aaa953d6cb59/src/htmlstyle.c000064400000000000000000000631201151224263100170770ustar00nobodynobody /* * htmlstyle.c --- * * This file applies the cascade algorithm using the stylesheet * code in css.c to the tree built with code in htmltree.c * *-------------------------------------------------------------------------- * Copyright (c) 2005 Eolas Technologies Inc. * All rights reserved. * * This Open Source project was made possible through the financial support * of Eolas Technologies Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ static const char rcsid[] = "$Id: htmlstyle.c,v 1.61 2007/12/12 04:50:29 danielk1977 Exp $"; #include "html.h" #include #include void HtmlDelScrollbars(pTree, pNode) HtmlTree *pTree; HtmlNode *pNode; { HtmlElementNode *pElem = (HtmlElementNode *)pNode; if (!HtmlNodeIsText(pNode) && pElem->pScrollbar) { HtmlNodeScrollbars *p = pElem->pScrollbar; if (p->vertical.win) { /* Remove any entry from the HtmlTree.pMapped list. */ if (&p->vertical == pTree->pMapped) { pTree->pMapped = p->vertical.pNext; } else { HtmlNodeReplacement *pCur = pTree->pMapped; while( pCur && pCur->pNext != &p->vertical ) pCur = pCur->pNext; if (pCur) { pCur->pNext = p->vertical.pNext; } } Tk_DestroyWindow(p->vertical.win); Tcl_DecrRefCount(p->vertical.pReplace); } if (p->horizontal.win) { /* Remove any entry from the HtmlTree.pMapped list. */ if (&p->horizontal == pTree->pMapped) { pTree->pMapped = p->horizontal.pNext; } else { HtmlNodeReplacement *pCur = pTree->pMapped; while( pCur && pCur->pNext != &p->horizontal ) { pCur = pCur->pNext; } if (pCur) { pCur->pNext = p->horizontal.pNext; } } Tk_DestroyWindow(p->horizontal.win); Tcl_DecrRefCount(p->horizontal.pReplace); } HtmlFree(p); pElem->pScrollbar = 0; } } void HtmlDelStackingInfo(pTree, pElem) HtmlTree *pTree; HtmlElementNode *pElem; { HtmlNodeStack *pStack = pElem->pStack; if (pStack && pStack->pElem == pElem){ if (pStack->pPrev) { pStack->pPrev->pNext = pStack->pNext; } if (pStack->pNext) { pStack->pNext->pPrev = pStack->pPrev; } if (pStack==pTree->pStack) { pTree->pStack = pStack->pNext; } assert(!pTree->pStack || !pTree->pStack->pPrev); HtmlFree(pStack); pTree->nStack--; } pElem->pStack = 0; } #define STACK_NONE 0 #define STACK_FLOAT 1 #define STACK_AUTO 2 #define STACK_CONTEXT 3 static int stackType(p) HtmlNode *p; { HtmlComputedValues *pV = HtmlNodeComputedValues(p); /* STACK_CONTEXT is created by the root element and any * positioned block with (z-index!='auto). */ if ( (!HtmlNodeParent(p)) || (pV->ePosition != CSS_CONST_STATIC && pV->iZIndex != PIXELVAL_AUTO) ) { return STACK_CONTEXT; } /* Postioned elements with 'auto' z-index are STACK_AUTO. */ if (pV->ePosition != CSS_CONST_STATIC) { return STACK_AUTO; } /* Floating boxes are STACK_FLOAT. */ if (pV->eFloat != CSS_CONST_NONE){ return STACK_FLOAT; } return STACK_NONE; } static void addStackingInfo(pTree, pElem) HtmlTree *pTree; HtmlElementNode *pElem; { HtmlNode *pNode = (HtmlNode *)pElem; int eStack = stackType(pNode); /* A node forms a new stacking context if it is positioned or floating. * Or if it is the root node. We only need create an HtmlNodeStack if this * is the case. */ if (eStack != STACK_NONE) { HtmlNodeStack *pStack = HtmlNew(HtmlNodeStack); pStack->pElem = pElem; pStack->eType = eStack; pStack->pNext = pTree->pStack; if( pStack->pNext ){ pStack->pNext->pPrev = pStack; } pTree->pStack = pStack; pElem->pStack = pStack; pTree->cb.flags |= HTML_STACK; pTree->nStack++; } else { pElem->pStack = ((HtmlElementNode *)HtmlNodeParent(pNode))->pStack; } assert(pElem->pStack); } #define STACK_STACKING 1 #define STACK_BLOCK 3 #define STACK_INLINE 5 typedef struct StackCompare StackCompare; struct StackCompare { HtmlNodeStack *pStack; int eStack; }; /* *--------------------------------------------------------------------------- * * scoreStack -- * * Results: * 1 -> Border and background of stacking context box. * 2 -> Descendants with negative z-index values. * 3 -> In-flow, non-inline descendants. * 4 -> Floats and their contents. * 5 -> In-flow, inline descendants. * 6 -> Positioned descendants with z-index values of "auto" or "0". * 7 -> Descendants with positive z-index values. * * Side effects: * None. * *--------------------------------------------------------------------------- */ static int scoreStack(pParentStack, pStack, eStack) HtmlNodeStack *pParentStack; HtmlNodeStack *pStack; int eStack; { int z; if (pStack == pParentStack) { return eStack; } assert(pStack->pElem->node.pParent); if (pStack->eType == STACK_FLOAT) return 4; if (pStack->eType == STACK_AUTO) return 6; z = pStack->pElem->pPropertyValues->iZIndex; assert(z != PIXELVAL_AUTO); if (z == 0) return 6; if (z < 0) return 2; return 7; } #define IS_STACKING_CONTEXT(x) ( \ x == x->pStack->pElem && x->pStack->eType == STACK_CONTEXT \ ) static void setStackingContext(p, ppOut) HtmlElementNode *p; HtmlNodeStack **ppOut; { if (p == p->pStack->pElem) { HtmlNodeStack *pS = p->pStack; if (pS->eType == STACK_CONTEXT || (*ppOut)->eType != STACK_CONTEXT) { *ppOut = pS; } } } static int stackCompare(pVoidLeft, pVoidRight) const void *pVoidLeft; const void *pVoidRight; { StackCompare *pLeft = (StackCompare *)pVoidLeft; StackCompare *pRight = (StackCompare *)pVoidRight; HtmlNodeStack *pLeftStack = pLeft->pStack; HtmlNodeStack *pRightStack = pRight->pStack; HtmlNodeStack *pParentStack = 0; int nLeftDepth = -1; /* Tree depth of node pLeftStack->pNode */ int nRightDepth = -1; /* Tree depth of node pRightStack->pNode */ int iLeft; int iRight; int iRes; int iTreeOrder = 0; int ii; HtmlElementNode *pL; HtmlElementNode *pR; /* There are three scenarios: * * 1) pLeft and pRight are associated with the same HtmlNodeStack * structure. In this case "inline" beats "block" and "block" * beats "stacking". * * 2) pLeft is descended from pRight, or vice versa. * * 3) Both are descended from a common stacking context. */ /* Calculate pLeftStack, pRightStack and pParentStack */ for (pL = pLeftStack->pElem; pL; pL = HtmlElemParent(pL)) nLeftDepth++; for (pR = pRightStack->pElem; pR; pR = HtmlElemParent(pR)) nRightDepth++; pL = pLeftStack->pElem; pR = pRightStack->pElem; for (ii = 0; ii < MAX(0, nLeftDepth - nRightDepth); ii++) { setStackingContext(pL, &pLeftStack); pL = HtmlElemParent(pL); iTreeOrder = +1; } for (ii = 0; ii < MAX(0, nRightDepth - nLeftDepth); ii++) { setStackingContext(pR, &pRightStack); pR = HtmlElemParent(pR); iTreeOrder = -1; } while (pR != pL) { HtmlElementNode *pParentL = HtmlElemParent(pL); HtmlElementNode *pParentR = HtmlElemParent(pR); setStackingContext(pL, &pLeftStack); setStackingContext(pR, &pRightStack); if (pParentL == pParentR) { iTreeOrder = 0; for (ii = 0; 0 == iTreeOrder; ii++) { HtmlNode *pChild = HtmlNodeChild(&pParentL->node, ii); if (pChild == (HtmlNode *)pL) { iTreeOrder = -1; } if (pChild == (HtmlNode *)pR) { iTreeOrder = +1; } } assert(iTreeOrder != 0); } pL = pParentL; pR = pParentR; assert(pL && pR); } while (pR->pStack->pElem != pR) { pR = HtmlElemParent(pR); assert(pR); } pParentStack = pR->pStack; iLeft = scoreStack(pParentStack, pLeftStack, pLeft->eStack); iRight = scoreStack(pParentStack, pRightStack, pRight->eStack); iRes = iLeft - iRight; if (iRes == 0 && (iRight == 2 || iRight == 6 || iRight == 7)) { int z1 = pLeftStack->pElem->pPropertyValues->iZIndex; int z2 = pRightStack->pElem->pPropertyValues->iZIndex; if (z1 == PIXELVAL_AUTO) z1 = 0; if (z2 == PIXELVAL_AUTO) z2 = 0; iRes = z1 - z2; } /* if (iRes == 0 && (iRight == 4 || pLeftStack == pRightStack)) { */ if (iRes == 0 && pLeftStack == pRightStack) { iRes = (pLeft->eStack - pRight->eStack); } if (iRes == 0) { assert(iTreeOrder != 0); iRes = iTreeOrder; } return iRes; } /* *--------------------------------------------------------------------------- * * checkStackSort -- * * This function is equivalent to an assert() statement. It is not * part of the functionality of Tkhtml3, but is used to check the * integrity of internal data structures. * * The first argument, aStack, should be an array of nStack (the * second arg) StackCompare structure. An assert fails inside * this function if the array is not sorted in ascending order. * * The primary purpose of this test is to ensure that the stackCompare() * comparision function is stable. It is quite an expensive check, * so is normally disabled at compile time. Change the "#if 0" * below to reenable the checking. * * NOTE: If you got this file from tkhtml.tcl.tk and there is an * "#if 1" in the code below, I have checked it in by mistake. * * Results: * None. * * Side effects: * None. * *--------------------------------------------------------------------------- */ #ifdef NDEBUG #define checkStackSort(a,b,c) #else static void checkStackSort(pTree, aStack, nStack) HtmlTree *pTree; StackCompare *aStack; int nStack; { #if 0 int ii; int jj; for (ii = 0; ii < nStack; ii++) { for (jj = ii + 1; jj < nStack; jj++) { int r1 = stackCompare(&aStack[ii], &aStack[jj]); int r2 = stackCompare(&aStack[jj], &aStack[ii]); assert(r1 && r2); assert((r1 * r2) < 0); assert(r1 < 0); } } #endif } #endif /* *--------------------------------------------------------------------------- * * HtmlRestackNodes -- * * This function is called from with the callbackHandler() routine * after updating the computed properties of the tree. * * Results: * None. * * Side effects: * None. * *--------------------------------------------------------------------------- */ void HtmlRestackNodes(pTree) HtmlTree *pTree; { HtmlNodeStack *pStack; StackCompare *apTmp; int iTmp = 0; if (0 == (pTree->cb.flags & HTML_STACK)) return; apTmp = (StackCompare *)HtmlAlloc(0, sizeof(StackCompare)*pTree->nStack*3); for (pStack = pTree->pStack; pStack; pStack = pStack->pNext) { apTmp[iTmp].pStack = pStack; apTmp[iTmp].eStack = STACK_BLOCK; apTmp[iTmp+1].pStack = pStack; apTmp[iTmp+1].eStack = STACK_INLINE; apTmp[iTmp+2].pStack = pStack; apTmp[iTmp+2].eStack = STACK_STACKING; iTmp += 3; } assert(iTmp == pTree->nStack * 3); qsort(apTmp, pTree->nStack * 3, sizeof(StackCompare), stackCompare); for (iTmp = 0; iTmp < pTree->nStack * 3; iTmp++) { #if 0 printf("Stack %d: %s %s\n", iTmp, Tcl_GetString(HtmlNodeCommand(pTree, &apTmp[iTmp].pStack->pElem->node)), (apTmp[iTmp].eStack == STACK_INLINE ? "inline" : apTmp[iTmp].eStack == STACK_BLOCK ? "block" : "stacking") ); #endif switch (apTmp[iTmp].eStack) { case STACK_INLINE: apTmp[iTmp].pStack->iInlineZ = iTmp; break; case STACK_BLOCK: apTmp[iTmp].pStack->iBlockZ = iTmp; break; case STACK_STACKING: apTmp[iTmp].pStack->iStackingZ = iTmp; break; } } checkStackSort(pTree, apTmp, pTree->nStack * 3); pTree->cb.flags &= (~HTML_STACK); HtmlFree(apTmp); } /* *--------------------------------------------------------------------------- * * styleNode -- * * Results: * None. * * Side effects: * None. * *--------------------------------------------------------------------------- */ static int styleNode(pTree, pNode, clientData) HtmlTree *pTree; HtmlNode *pNode; ClientData clientData; { CONST char *zStyle; /* Value of "style" attribute for node */ int trashDynamics = (int)((size_t) clientData); HtmlElementNode *pElem = (HtmlElementNode *)pNode; HtmlComputedValues *pV = pElem->pPropertyValues; pElem->pPropertyValues = 0; HtmlDelStackingInfo(pTree, pElem); /* If the clientData was set to a non-zero value, then the * stylesheet configuration has changed. In this case we need to * recalculate the nodes list of dynamic conditions. */ if (trashDynamics) { HtmlCssFreeDynamics(pElem); } /* If there is a "style" attribute on this node, parse the attribute * value and put the resulting mini-stylesheet in pNode->pStyle. * * We assume that if the pStyle attribute is not NULL, then this node * has been styled before. The stylesheet configuration may have * changed since then, so we have to recalculate pNode->pProperties, * but the "style" attribute is constant so pStyle is never invalid. * * Actually, the style attribute can be modified by the user, using * the [$node attribute style "new-value"] command. In this case * the style attribute is treated as a special case and the * pElem->pStyle structure is invalidated/recalculated as required. */ if (!pElem->pStyle) { zStyle = HtmlNodeAttr(pNode, "style"); if (zStyle) { HtmlCssInlineParse(pTree, -1, zStyle, &pElem->pStyle); } } /* Recalculate the properties for this node */ HtmlCssStyleSheetApply(pTree, pNode); HtmlComputedValuesRelease(pTree, pElem->pPreviousValues); pElem->pPreviousValues = pV; addStackingInfo(pTree, pElem); /* Compare the new computed property set with the old. If * ComputedValuesCompare() returns 0, then the properties have * not changed (in any way that affects rendering). If it * returns 1, then some aspect has changed that does not * require a relayout (i.e. 'color', or 'text-decoration'). * If it returns 2, then something has changed that does require * relayout (i.e. 'display', 'font-size'). */ return HtmlComputedValuesCompare(pElem->pPropertyValues, pV); } typedef struct StyleCounter StyleCounter; struct StyleCounter { char *zName; int iValue; }; struct StyleApply { /* Node to begin recalculating style at */ HtmlNode *pRestyle; /* True if currently traversing pRestyle, or a descendent, right-sibling * or descendent of a right-sibling of pRestyle. */ int doStyle; int doContent; /* True if the whole tree is being restyled. */ int isRoot; StyleCounter **apCounter; int nCounter; int nCounterAlloc; int nCounterStartScope; /* True if we have seen one or more "fixed" items */ int isFixed; }; typedef struct StyleApply StyleApply; static void styleApply(pTree, pNode, p) HtmlTree *pTree; HtmlNode *pNode; StyleApply *p; { int i; int doStyle; int nCounterStartScope; int redrawmode = 0; HtmlElementNode *pElem = HtmlNodeAsElement(pNode); /* Text nodes do not have an associated style. */ if (!pElem) return; if (p->pRestyle == pNode) { p->doStyle = 1; } if (p->doStyle) { redrawmode = styleNode(pTree, pNode, (ClientData) ((size_t) p->isRoot)); /* If there has been a style-callback configured (-stylecmd option to * the [nodeHandle replace] command) for this node, invoke it now. */ if (pElem->pReplacement && pElem->pReplacement->pStyleCmd) { Tcl_Obj *pCmd = pElem->pReplacement->pStyleCmd; int rc = Tcl_EvalObjEx(pTree->interp, pCmd, TCL_EVAL_GLOBAL); if (rc != TCL_OK) { Tcl_BackgroundError(pTree->interp); } } } HtmlStyleHandleCounters(pTree, HtmlNodeComputedValues(pNode)); nCounterStartScope = p->nCounterStartScope; p->nCounterStartScope = p->nCounter; if (p->doStyle || p->doContent) { /* Destroy current generated content */ if (pElem->pBefore || pElem->pAfter) { HtmlNodeClearGenerated(pTree, pElem); redrawmode = MAX(redrawmode, 2); } /* Generate :before content */ HtmlCssStyleGenerateContent(pTree, pElem, 1); if (pElem->pBefore) { ((HtmlElementNode *)(pElem->pBefore))->pStack = pElem->pStack; pElem->pBefore->pParent = pNode; pElem->pBefore->iNode = -1; } } else if (pElem->pBefore) { HtmlStyleHandleCounters(pTree, HtmlNodeComputedValues(pElem->pBefore)); } doStyle = p->doStyle; for (i = 0; i < HtmlNodeNumChildren(pNode); i++) { styleApply(pTree, HtmlNodeChild(pNode, i), p); } p->doStyle = doStyle; if (p->doStyle || p->doContent) { /* Generate :after content */ HtmlCssStyleGenerateContent(pTree, pElem, 0); if (pElem->pAfter) { ((HtmlElementNode *)(pElem->pAfter))->pStack = pElem->pStack; pElem->pAfter->pParent = pNode; pElem->pAfter->iNode = -1; } if (pElem->pBefore || pElem->pAfter) { redrawmode = MAX(redrawmode, 2); } } else if(pElem->pAfter) { HtmlStyleHandleCounters(pTree, HtmlNodeComputedValues(pElem->pAfter)); } for (i = p->nCounterStartScope; i < p->nCounter; i++) { HtmlFree(p->apCounter[i]); } p->nCounter = p->nCounterStartScope; p->nCounterStartScope = nCounterStartScope; if (redrawmode == 3) { HtmlCallbackLayout(pTree, pNode); HtmlCallbackDamageNode(pTree, pNode); p->doContent = 1; } else if (redrawmode == 2) { HtmlCallbackLayout(pTree, pNode); HtmlCallbackDamageNode(pTree, pNode); } else if (redrawmode == 1) { /* HtmlCallbackLayout(pTree, pNode); */ HtmlCallbackDamageNode(pTree, pNode); } /* If this element was either the or nodes, * go ahead and repaint the entire display. The worst that * can happen is that we have to paint a little extra * area if the document background is set by the * element. */ if (redrawmode && ( (HtmlNode *)pElem == pTree->pRoot || (HtmlNode *)pElem == HtmlNodeChild(pTree->pRoot, 1) ) ) { HtmlCallbackDamage(pTree, 0, 0, 1000000, 1000000); } if (pElem->pPropertyValues->eDisplay != CSS_CONST_NONE && ( pElem->pPropertyValues->ePosition == CSS_CONST_FIXED || pElem->pPropertyValues->eBackgroundAttachment == CSS_CONST_FIXED )) { p->isFixed = 1; } } static void addCounterEntry(p, zName, iValue) StyleApply *p; const char *zName; int iValue; { StyleCounter *pCounter; int n; if (p->nCounterAlloc < (p->nCounter + 1)) { int nByte; p->nCounterAlloc += 10; nByte = p->nCounterAlloc * sizeof(HtmlCounterList *); p->apCounter = (StyleCounter **)HtmlRealloc( "apCounter", p->apCounter, nByte ); } n = sizeof(StyleCounter) + strlen(zName) + 1; pCounter = (StyleCounter *)HtmlAlloc("StyleCounter", n); pCounter->zName = (char *)&pCounter[1]; strcpy(pCounter->zName, zName); pCounter->iValue = iValue; p->apCounter[p->nCounter] = pCounter; p->nCounter++; } void HtmlStyleHandleCounters(pTree, pComputed) HtmlTree *pTree; HtmlComputedValues *pComputed; { StyleApply *p = (StyleApply *)pTree->pStyleApply; HtmlCounterList *pReset = pComputed->clCounterReset; HtmlCounterList *pIncr = pComputed->clCounterIncrement; /* Section 12.4.3 of CSS 2.1: Elements with "display:none" neither * increment or reset counters. */ if (pComputed->eDisplay == CSS_CONST_NONE) { return; } if (pReset) { int ii; for (ii = 0; ii < pReset->nCounter; ii++) { StyleCounter *pCounter = 0; int jj; for (jj = p->nCounterStartScope; jj < p->nCounter; jj++) { if (!strcmp(pReset->azCounter[ii], p->apCounter[jj]->zName)) { pCounter = p->apCounter[jj]; pCounter->iValue = pReset->anValue[ii]; break; } } if (pCounter == 0) { addCounterEntry(p, pReset->azCounter[ii], pReset->anValue[ii]); } } } if (pIncr) { int ii; for (ii = 0; ii < pIncr->nCounter; ii++) { int jj; for (jj = p->nCounter - 1; jj >= 0; jj--) { if (0 == strcmp(pIncr->azCounter[ii],p->apCounter[jj]->zName)) { p->apCounter[jj]->iValue += pIncr->anValue[ii]; break; } } if (jj < 0) { /* No counter with the specified name is found. Act as if * there is a 'counter-reset: zName iValue' directive. */ addCounterEntry(p, pIncr->azCounter[ii], pIncr->anValue[ii]); } } } } int HtmlStyleCounters(pTree, zName, aValue, nValue) HtmlTree *pTree; const char *zName; int *aValue; int nValue; { int ii; StyleApply *p = (StyleApply *)(pTree->pStyleApply); int n = 0; for (ii = 0; ii < p->nCounter && n < nValue; ii++) { if (0 == strcmp(zName, p->apCounter[ii]->zName)) { aValue[n] = p->apCounter[ii]->iValue; n++; } } if (n == 0) { n = 1; aValue[0] = 0; } return n; } int HtmlStyleCounter(pTree, zName) HtmlTree *pTree; const char *zName; { int ii; StyleApply *p = (StyleApply *)(pTree->pStyleApply); for (ii = p->nCounter - 1; ii >= 0; ii--) { if (0 == strcmp(zName, p->apCounter[ii]->zName)) { return p->apCounter[ii]->iValue; } } return 0; } /* *--------------------------------------------------------------------------- * * HtmlStyleApply -- * * Results: * None. * * Side effects: * None. * *--------------------------------------------------------------------------- */ int HtmlStyleApply(pTree, pNode) HtmlTree *pTree; HtmlNode *pNode; { StyleApply sApply; int isRoot = ((pNode == pTree->pRoot) ? 1 : 0); HtmlLog(pTree, "STYLEENGINE", "START"); memset(&sApply, 0, sizeof(StyleApply)); sApply.pRestyle = pNode; sApply.isRoot = isRoot; assert(pTree->pStyleApply == 0); pTree->pStyleApply = (void *)&sApply; styleApply(pTree, pTree->pRoot, &sApply); pTree->pStyleApply = 0; pTree->isFixed = sApply.isFixed; HtmlFree(sApply.apCounter); return TCL_OK; } /* *--------------------------------------------------------------------------- * * HtmlStyleSyntaxErrs -- * * Results: * None. * * Side effects: * None. * *--------------------------------------------------------------------------- */ int HtmlStyleSyntaxErrs(clientData, interp, objc, objv) ClientData clientData; /* The HTML widget */ Tcl_Interp *interp; /* The interpreter */ int objc; /* Number of arguments */ Tcl_Obj *CONST objv[]; /* List of all arguments */ { HtmlTree *pTree = (HtmlTree *)clientData; int nSyntaxErrs = 0; if( pTree->pStyle ){ nSyntaxErrs = HtmlCssStyleSheetSyntaxErrs(pTree->pStyle); } Tcl_SetObjResult(interp, Tcl_NewIntObj(nSyntaxErrs)); return TCL_OK; } tkHTML-4ee7aaa953d6cb59/src/htmltable.c000064400000000000000000001772711151224263100170430ustar00nobodynobody/* * htmltable.c --- * * This file contains code for layout of tables. * *-------------------------------------------------------------------------- * Copyright (c) 2005 Eolas Technologies Inc. * All rights reserved. * * This Open Source project was made possible through the financial support * of Eolas Technologies Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ static const char rcsid[] = "$Id: htmltable.c,v 1.124 2007/11/03 11:23:16 danielk1977 Exp $"; #include "htmllayout.h" #define LOG if (pLayout->pTree->options.logcmd && !pLayout->minmaxTest) struct TableCell { BoxContext box; int startrow; /* Index of row cell starts at */ int finrow; /* Index of row cell ends at */ int colspan; /* Number of columns spanned by cell (often 1) */ HtmlNode *pNode; /* Node with "display:table-cell" */ }; typedef struct TableCell TableCell; typedef struct CellReqWidth CellReqWidth; struct CellReqWidth { int eType; union { int iVal; /* For CELL_WIDTH_PIXELS */ float fVal; /* For CELL_WIDTH_PERCENT */ } x; }; #define CELL_WIDTH_AUTO 0 #define CELL_WIDTH_PIXELS 1 #define CELL_WIDTH_PERCENT 2 /* * Structure used whilst laying out tables. See HtmlTableLayout(). */ struct TableData { HtmlNode *pNode; /* node */ LayoutContext *pLayout; int border_spacing; /* Pixel value of 'border-spacing' property */ int availablewidth; /* Width available between margins for table */ /* * Determined by: * * tableCountCells() */ int nCol; /* Total number of columns in table */ int nRow; /* Total number of rows in table */ /* * The following four arrays are populated by the two-pass algorithm * implemented by functions: * * tableColWidthSingleSpan() * tableColWidthMultiSpan() */ int *aMaxWidth; /* Maximum content width of each column */ int *aMinWidth; /* Minimum content width of each column */ CellReqWidth *aReqWidth; /* Widths requested via CSS */ CellReqWidth *aSingleReqWidth; /* Widths requested by single span cells */ /* * Determined by: * * tableCalculateCellWidths() */ int *aWidth; /* Actual widths of each column (calculated) */ int *aY; /* Top y-coord for each row+1, wrt table box */ TableCell *aCell; int row; /* Current row */ int y; /* y-coord to draw at */ int x; /* x-coord to draw at */ BoxContext *pBox; /* Box to draw into */ HtmlComputedValues *pDefaultProperties; }; typedef struct TableData TableData; /* The two types of callbacks made by tableIterate(). */ typedef int (CellCallback)(HtmlNode *, int, int, int, int, void *); typedef int (RowCallback)(HtmlNode *, int, void *); /* Iterate through each cell in each row of the table. */ static void tableIterate(HtmlTree*,HtmlNode*, CellCallback, RowCallback, void*); /* Count the number of rows/columns in the table */ static CellCallback tableCountCells; /* Populate the aMinWidth, aMaxWidth, aReqWidth and aSingleReqWidth array * members of the TableData structure. */ static CellCallback tableColWidthSingleSpan; static CellCallback tableColWidthMultiSpan; /* Figure out the actual column widths (TableData.aWidth[]). */ static void tableCalculateCellWidths(TableData *, int, int); /* A row and cell callback (used together in a single iteration) to draw * the table content. All the actual drawing is done here. Everything * else is just about figuring out column widths. */ static CellCallback tableDrawCells; static RowCallback tableDrawRow; /* *--------------------------------------------------------------------------- * * walkChildren() -- * * This function is a wrapper around HtmlWalkTree(). It is identical * in all respects but one - the callback function is not invoked for * pNode (the root of the tree). * * Results: * None. * * Side effects: * Whatever xCallback() does. * *--------------------------------------------------------------------------- */ #if 0 static void walkChildren(pTree, pNode, xCallback, pContext) HtmlTree *pTree; HtmlNode *pNode; int (*xCallback)(HtmlTree *, HtmlNode *, ClientData clientData); ClientData pContext; { int i; int nChild = HtmlNodeNumChildren(pNode); for (i = 0; i < nChild; i++) { HtmlNode *pChild = HtmlNodeChild(pNode, i); xCallback(pTree, pChild, pContext); } } #endif static void fixNodeProperties(pData, pNode) TableData *pData; HtmlNode *pNode; { HtmlElementNode *pElem = (HtmlElementNode *)pNode; if (!pElem->pPropertyValues) { if (!pData->pDefaultProperties) { HtmlTree *pTree = pData->pLayout->pTree; HtmlComputedValuesCreator sCreator; HtmlComputedValuesInit(pTree, pNode, 0, &sCreator); pData->pDefaultProperties = HtmlComputedValuesFinish(&sCreator); } pElem->pPropertyValues = pData->pDefaultProperties; } } /* *--------------------------------------------------------------------------- * * tableColWidthSingleSpan -- * * A tableIterate() callback to determine the following for each * column in the table: * * * The minimum content width * * The maximum content width * * The requested width (may be in pixels, a percentage or "auto") * * This function only considers cells that span a single column (either * colspan="1" cells, or cells with no explicit colspan value). A second * tableIterate() loop, with tableColWidthMultiSpan() as the callback * analyses the cells that span multiple columns. * * Results: * None. * * Side effects: * Populates the following arrays: * * TableData.aMinWidth[] * TableData.aMaxWidth[] * TableData.aSingleReqWidth[] * *--------------------------------------------------------------------------- */ static int tableColWidthSingleSpan(pNode, col, colspan, row, rowspan, pContext) HtmlNode *pNode; int col; int colspan; int row; int rowspan; void *pContext; { TableData *pData = (TableData *)pContext; int *aMinWidth = pData->aMinWidth; int *aMaxWidth = pData->aMaxWidth; /* Because a cell originates in this column, it's min and max width * must be at least 1 pixel. It doesn't matter if the cell spans * multiple columns or not (gleaned from alternative CSS engine * implementation). */ aMaxWidth[col] = MAX(aMaxWidth[col], 1); aMinWidth[col] = MAX(aMinWidth[col], 1); if (colspan == 1) { HtmlComputedValues *pV; BoxProperties box; int max; int min; /* Note: aReq is an alias for aSingleReqWidth, NOT aReqWidth. * aReqWidth is populated by the second analysis parse of * the table - the one that uses tableColWidthMultiSpan(). */ CellReqWidth *aReq = pData->aSingleReqWidth; /* Figure out the minimum and maximum widths of the content */ fixNodeProperties(pData, pNode); pV = HtmlNodeComputedValues(pNode); blockMinMaxWidth(pData->pLayout, pNode, &min, &max); nodeGetBoxProperties(pData->pLayout, pNode, 0, &box); aMinWidth[col] = MAX(aMinWidth[col], min + box.iLeft + box.iRight); aMaxWidth[col] = MAX(aMaxWidth[col], max + box.iLeft + box.iRight); assert(aMinWidth[col] <= aMaxWidth[col]); if (pV->mask & PROP_MASK_WIDTH) { /* The computed value of the 'width' property is a percentage */ float val = ((float)pV->iWidth) / 100.0; switch (aReq[col].eType) { case CELL_WIDTH_AUTO: case CELL_WIDTH_PIXELS: aReq[col].eType = CELL_WIDTH_PERCENT; aReq[col].x.fVal = val; break; case CELL_WIDTH_PERCENT: aReq[col].x.fVal = MAX(aReq[col].x.fVal, val); break; } } else if (pV->iWidth >= 0) { /* There is a pixel value for the 'width' property */ int val = pV->iWidth + box.iLeft + box.iRight; switch (aReq[col].eType) { case CELL_WIDTH_AUTO: case CELL_WIDTH_PIXELS: aReq[col].eType = CELL_WIDTH_PIXELS; aReq[col].x.iVal = MAX(aReq[col].x.iVal, val); aMaxWidth[col] = MAX(val, aMaxWidth[col]); break; case CELL_WIDTH_PERCENT: break; } } } return TCL_OK; } /* *--------------------------------------------------------------------------- * * logWidthsToTable -- * * This function is only used by LOG{...} blocks (i.e. to debug the * widget internals). It appends a formatted HTML table to the * current value of pObj summarizing the values in the following arrays: * * pData->aReqWidth * pData->aMinWidth * pData->aMaxWidth * * Results: * None. * * Side effects: * Appends to pObj. * *--------------------------------------------------------------------------- */ static void logWidthsToTable(pData, pObj) TableData *pData; Tcl_Obj *pObj; { int *aMinWidth = pData->aMinWidth; int *aMaxWidth = pData->aMaxWidth; CellReqWidth *aReqWidth = pData->aReqWidth; int ii; Tcl_AppendToObj(pObj, "
    " "
    Col Number" " Min Content Width" " Max Content Width" " Explicit Width" " Percentage Width", -1); for (ii = 0; ii < pData->nCol; ii++) { int jj; char zPercent[32]; Tcl_AppendToObj(pObj, "
    ", -1); Tcl_AppendObjToObj(pObj, Tcl_NewIntObj(ii)); for (jj = 0; jj < 3; jj++) { int val = PIXELVAL_AUTO; switch (jj) { case 0: val = aMinWidth[ii]; break; case 1: val = aMaxWidth[ii]; break; case 2: if (aReqWidth[ii].eType == CELL_WIDTH_PIXELS) { val = aReqWidth[ii].x.iVal; } else { val = PIXELVAL_AUTO; } break; default: assert(0); } Tcl_AppendToObj(pObj, "", -1); if (val != PIXELVAL_AUTO) { Tcl_AppendObjToObj(pObj, Tcl_NewIntObj(val)); Tcl_AppendToObj(pObj, "px", -1); } else { Tcl_AppendToObj(pObj, "N/A", -1); } } Tcl_AppendToObj(pObj, "", -1); if (aReqWidth[ii].eType == CELL_WIDTH_PERCENT) { sprintf(zPercent, "%.2f%%", aReqWidth[ii].x.fVal); } else { sprintf(zPercent, "N/A"); } Tcl_AppendToObj(pObj, zPercent, -1); } Tcl_AppendToObj(pObj, "
    ", -1); } static void getReqWidth(pNode, pReq) HtmlNode *pNode; CellReqWidth *pReq; { HtmlComputedValues *pV = HtmlNodeComputedValues(pNode); if (pV->mask & PROP_MASK_WIDTH) { /* The computed value of the 'width' property is a percentage */ pReq->eType = CELL_WIDTH_PERCENT; pReq->x.fVal = ((float)pV->iWidth) / 100.0; } else if (pV->iWidth > 0) { pReq->eType = CELL_WIDTH_PIXELS; pReq->x.iVal = pV->iWidth; } else { pReq->eType = CELL_WIDTH_AUTO; } } static void logMinMaxWidths(pLayout, pNode, col, colspan, aMinWidth, aMaxWidth) LayoutContext *pLayout; HtmlNode *pNode; int col; int colspan; int *aMinWidth; int *aMaxWidth; { LOG { int ii; HtmlTree *pTree = pLayout->pTree; Tcl_Obj *pMinWidths = Tcl_NewObj(); Tcl_IncrRefCount(pMinWidths); Tcl_AppendToObj(pMinWidths, " aMinWidth", -1); for (ii = col; ii < (col + colspan); ii++) { Tcl_AppendToObj(pMinWidths, "", 4); Tcl_AppendObjToObj(pMinWidths, Tcl_NewIntObj(ii)); Tcl_AppendToObj(pMinWidths, ":", 1); Tcl_AppendObjToObj( pMinWidths, Tcl_NewIntObj(aMinWidth[ii]) ); } Tcl_AppendToObj(pMinWidths, " aMaxWidths", -1); for (ii = col; ii < (col + colspan); ii++) { Tcl_AppendToObj(pMinWidths, "", 4); Tcl_AppendObjToObj(pMinWidths, Tcl_NewIntObj(ii)); Tcl_AppendToObj(pMinWidths, ":", 1); Tcl_AppendObjToObj( pMinWidths, Tcl_NewIntObj(aMaxWidth[ii]) ); } HtmlLog(pTree, "LAYOUTENGINE", "%s tableColWidthMultiSpan() aMinWidth before:" " %s
    ", Tcl_GetString(HtmlNodeCommand(pTree, pNode)), Tcl_GetString(pMinWidths) ); Tcl_DecrRefCount(pMinWidths); } } /* *--------------------------------------------------------------------------- * * tableColWidthMultiSpan -- * * A tableIterate() callback to analyse the following for each * cell in the table that spans more than one column: * * * The minimum content width * * The maximum content width * * The requested width (may be in pixels, a percentage or "auto") * * This function updates values set by the tableColWidthSingleSpan() * loop. * * Results: * None. * * Side effects: * Populates the following arrays: * * TableData.aMinWidth[] * TableData.aMaxWidth[] * TableData.aReqWidth[] * *--------------------------------------------------------------------------- */ static int tableColWidthMultiSpan(pNode, col, colspan, row, rowspan, pContext) HtmlNode *pNode; int col; int colspan; int row; int rowspan; void *pContext; { TableData *pData = (TableData *)pContext; int *aMinWidth = pData->aMinWidth; int *aMaxWidth = pData->aMaxWidth; CellReqWidth *aReq = pData->aSingleReqWidth; CellReqWidth *aReqOut = pData->aReqWidth; /* Because a cell originates in column $col, it's min and max content * width must be at least 1 pixel. tableColWidthSingleSpan() should * have taken care of this. */ assert(aMaxWidth[col] > 0); assert(aMinWidth[col] > 0); if (colspan > 1) { double fTotalPercent = 0.0; /* Total of spanned percentage widths */ int iTotalMin = 0; /* Total min-width of all spanned cols */ int iTotalMax = 0; /* Total max-width of all spanned cols */ int iTotalPixel = 0; /* Total pixel width of all spanned cols */ int nPixelWidth = 0; /* Number of spanned pixel width cols */ int nPercentWidth = 0; /* Number of spanned percent width cols */ int nAutoWidth = 0; /* Number of spanned auto width cols */ int ii; /* Minimum, maximum and requested width of the multi-span cell */ int min; int max; CellReqWidth req; BoxProperties box; /* Retrieve the min, max and requested width of the multi-span cell. * Adjust min and max so that they take into account the * 'border-spacing' regions that this cell spans and the borders and * padding on the cell itself. */ getReqWidth(pNode, &req); blockMinMaxWidth(pData->pLayout, pNode, &min, &max); min = min - pData->border_spacing * (colspan - 1); max = max - pData->border_spacing * (colspan - 1); nodeGetBoxProperties(pData->pLayout, pNode, 0, &box); min = min + box.iLeft + box.iRight; max = max + box.iLeft + box.iRight; for (ii = col; ii < (col + colspan); ii++) { switch (aReq[ii].eType) { case CELL_WIDTH_AUTO: nAutoWidth++; break; case CELL_WIDTH_PIXELS: iTotalPixel += aReq[ii].x.iVal; nPixelWidth++; break; case CELL_WIDTH_PERCENT: nPercentWidth++; fTotalPercent += aReq[ii].x.fVal; break; } iTotalMin += aMinWidth[ii]; iTotalMax += aMaxWidth[ii]; } if ( req.eType == CELL_WIDTH_PERCENT && (colspan == nPercentWidth || fTotalPercent > req.x.fVal) ) { /* We have no means to satisfy this condition, so simply discard * the percentage width request. */ req.eType = CELL_WIDTH_AUTO; } if (req.eType == CELL_WIDTH_PERCENT) { /* Any columns in the spanned set that do not already have * percentage values are given them, so that the percentages * add up to that requested by the spanning cell. * * If there is more than one column to add a percentage width * to, the percentages are allocated in proportion to the * maximum content widths of the columns. */ int iMaxNonPercent = 0; float fRem = req.x.fVal - fTotalPercent; for (ii = col; ii < (col + colspan); ii++) { if (aReq[ii].eType != CELL_WIDTH_PERCENT) { iMaxNonPercent += aMaxWidth[ii]; } } for (ii = col; ii < (col + colspan) && iMaxNonPercent > 0; ii++) { if (aReq[ii].eType != CELL_WIDTH_PERCENT) { aReqOut[ii].eType = CELL_WIDTH_PERCENT; aReqOut[ii].x.fVal = fRem * aMaxWidth[ii] / iMaxNonPercent; iMaxNonPercent -= aMaxWidth[ii]; } } assert(iMaxNonPercent == 0); } if (min > iTotalMin) { /* The minimum required width for the spanning cell is greater * than that of the columns it spans. */ int iRem = min; int iTPW = iTotalPixel; if (nPixelWidth == colspan) { /* All spanned columns have explicit pixel widths. In this * case try to divide up the minimum width of the spanning * cell according to the ratio between the pixel widths. * Respect each cells min-width while doing this. */ for (ii = col; ii < (col + colspan) && iTPW > 0; ii++) { int w = MAX(aMinWidth[ii], iRem * aReq[ii].x.iVal / iTPW); iRem -= w; aMinWidth[ii] = w; iTPW -= aReq[ii].x.iVal; } assert(iTPW == 0); } else { LayoutContext *pLayout = pData->pLayout; int iMin = iTotalMin; int iMax = iTotalMax; LOG { HtmlTree *pTree = pLayout->pTree; HtmlLog(pTree, "LAYOUTENGINE", "%s tableColWidthMultiSpan() Distributing %d pixels." " iMax=%d iMin=%d.", Tcl_GetString(HtmlNodeCommand(pTree, pNode)), iRem, iMin, iMax ); } logMinMaxWidths( pLayout, pNode, col, colspan, aMinWidth, aMaxWidth ); for (ii = col; iMax >= 0 && ii < (col + colspan); ii++) { int isFixed = (aReq[ii].eType == CELL_WIDTH_PIXELS); if (isFixed && nAutoWidth > 0 && iTPW <= iRem) { int w = MAX(aMinWidth[ii], aReq[ii].x.iVal); iRem -= w; iTPW -= aReq[ii].x.iVal; iMax -= aMaxWidth[ii]; iMin -= aMinWidth[ii]; aMinWidth[ii] = w; } } ii = col; for (; iMax >= 0 && iMin < iRem && ii < (col + colspan); ii++){ int isFixed = (aReq[ii].eType == CELL_WIDTH_PIXELS); if (!isFixed || nAutoWidth == 0) { int w = aMinWidth[ii]; if (iMax) { assert(aMaxWidth[ii] <= iMax); w = MAX(w, iRem * aMaxWidth[ii] / iMax); } else { w = MAX(w, iRem); } assert(w <= iRem); iMax -= aMaxWidth[ii]; iMin -= aMinWidth[ii]; iRem -= w; aMinWidth[ii] = w; } } logMinMaxWidths( pLayout, pNode, col, colspan, aMinWidth, aMaxWidth ); } } if (iTotalMax < max) { int iM = iTotalMax; /* Current sum of aMaxWidth[] */ int iRem = max; /* Required sum of aMaxWidth[] */ for (ii = col; iM > 0 && iRem > 0 && ii < (col + colspan); ii++){ int w = MAX(aMaxWidth[ii], iRem * aMaxWidth[ii] / iM); iM -= aMaxWidth[ii]; iRem -= w; aMaxWidth[ii] = w; } } for (ii = col; ii < (col + colspan); ii++){ aMaxWidth[ii] = MAX(aMaxWidth[ii], aMinWidth[ii]); } } return TCL_OK; } /* *--------------------------------------------------------------------------- * * tableCountCells -- * * A callback invoked by the tableIterate() function to figure out * how many columns are in the table. * * Results: * None. * * Side effects: * None. * *--------------------------------------------------------------------------- */ static int tableCountCells(pNode, col, colspan, row, rowspan, pContext) HtmlNode *pNode; int col; int colspan; int row; int rowspan; void *pContext; { TableData *pData = (TableData *)pContext; /* A colspan of 0 is legal (apparently), but Tkhtml just handles it as 1 */ if (colspan==0) { colspan = 1; } if (pData->nCol<(col+colspan)) { pData->nCol = col+colspan; } return TCL_OK; } static int tableCountRows(pNode, row, pContext) HtmlNode *pNode; int row; void *pContext; { TableData *pData = (TableData *)pContext; pData->nRow = row + 1; return TCL_OK; } /* *--------------------------------------------------------------------------- * * tableDrawRow -- * * This is a tableIterate() 'row callback' used while actually drawing * table data to canvas. See comments above tableDrawCells() for a * description. * * Results: * None. * * Side effects: * None. * *--------------------------------------------------------------------------- */ static int tableDrawRow(pNode, row, pContext) HtmlNode *pNode; int row; void *pContext; { TableData *pData = (TableData *)pContext; LayoutContext *pLayout = pData->pLayout; int nextrow = row+1; int x = 0; /* X coordinate to draw content */ int i; /* Column iterator */ const int mmt = pLayout->minmaxTest; HtmlElementNode *pElem = (HtmlElementNode *)pNode; assert(!pElem || !HtmlNodeIsText(pNode)); assert(row < pData->nRow); /* Add the background and border for the table-row, if a node exists. A * node may not exist if the row is entirely populated by overflow from * above. For example in the following document, there is no node for the * second row of the table. * *
    */ CHECK_INTEGER_PLAUSIBILITY(pData->pBox->vc.bottom); if (pElem && pElem->node.iNode >= 0 && pElem->pPropertyValues) { int iHeight; int x1, y1, w1, h1; /* Border coordinates */ x1 = pData->border_spacing; y1 = pData->aY[row]; h1 = pData->aY[nextrow] - pData->aY[row] - pData->border_spacing; /* If we have a non-auto 'height' property on the table-row, then * use it as a minimum height. Such a 'height' does not include * the border-spacing. */ iHeight = PIXELVAL(pElem->pPropertyValues, HEIGHT, 0); if (iHeight > h1) { pData->aY[nextrow] += (iHeight - h1); h1 = iHeight; } w1 = 0; for (i=0; inCol; i++) { w1 += pData->aWidth[i]; } w1 += ((pData->nCol - 1) * pData->border_spacing); HtmlLayoutDrawBox(pData->pLayout->pTree, &pData->pBox->vc, x1, y1, w1, h1, pNode, 0, mmt ); } CHECK_INTEGER_PLAUSIBILITY(pData->pBox->vc.bottom); CHECK_INTEGER_PLAUSIBILITY(pData->pBox->vc.right); for (i=0; inCol; i++) { TableCell *pCell = &pData->aCell[i]; /* At this point variable x holds the horizontal canvas offset of * the outside edge of the cell pCell's left border. */ x += pData->border_spacing; if (pCell->finrow == nextrow) { BoxProperties box; int x1, y1, w1, h1; /* Border coordinates */ int y; int k; HtmlCanvas *pCanvas = &pData->pBox->vc; x1 = x; y1 = pData->aY[pCell->startrow]; w1 = 0; for (k=i; k<(i+pCell->colspan); k++) { w1 += pData->aWidth[k]; } w1 += ((pCell->colspan-1) * pData->border_spacing); h1 = pData->aY[pCell->finrow] - pData->border_spacing - y1; if (pCell->pNode->iNode >= 0) { HtmlLayoutDrawBox(pData->pLayout->pTree, pCanvas, x1, y1, w1, h1, pCell->pNode, 0, mmt ); } nodeGetBoxProperties(pLayout, pCell->pNode, 0, &box); /* Todo: The formulas for the various vertical alignments below * only work if the top and bottom borders of the cell * are of the same thickness. Same goes for the padding. */ switch (HtmlNodeComputedValues(pCell->pNode)->eVerticalAlign) { case CSS_CONST_TOP: case CSS_CONST_BASELINE: y = pData->aY[pCell->startrow] + box.iTop; break; case CSS_CONST_BOTTOM: y = pData->aY[pCell->finrow] - pCell->box.height - box.iBottom - pData->border_spacing; break; default: y = pData->aY[pCell->startrow]; y += (h1 - box.iTop - box.iBottom - pCell->box.height) / 2; y += box.iTop; break; } CHECK_INTEGER_PLAUSIBILITY(pCanvas->bottom); DRAW_CANVAS(pCanvas, &pCell->box.vc, x+box.iLeft, y, pCell->pNode); CHECK_INTEGER_PLAUSIBILITY(pCanvas->bottom); memset(pCell, 0, sizeof(TableCell)); } x += pData->aWidth[i]; } CHECK_INTEGER_PLAUSIBILITY(pData->pBox->vc.bottom); CHECK_INTEGER_PLAUSIBILITY(pData->pBox->vc.right); return TCL_OK; } /* *--------------------------------------------------------------------------- * * tableDrawCells -- * * tableIterate() callback to actually draw cells. Drawing uses two * callbacks. This function is called for each cell in the table * and the tableDrawRow() function above is called after each row has * been completed. * * This function draws the cell into the BoxContext at location * aCell[col-number].box in the TableData struct. The border and * background are not drawn at this stage. * * When the tableDrawRow() function is called, it is possible to * determine the height of the row. This is needed before cell contents * can be copied into the table canvas, so that the cell can be * vertically aligned correctly, and so that the cell border and * background match the height of the row they are in. * * Plus a few complications for cells that span multiple rows. * * Results: * None. * * Side effects: * None. * *--------------------------------------------------------------------------- */ static int tableDrawCells(pNode, col, colspan, row, rowspan, pContext) HtmlNode *pNode; int col; int colspan; int row; int rowspan; void *pContext; { TableData *pData = (TableData *)pContext; BoxContext *pBox; BoxProperties box; int i; int x = 0; int y = 0; int belowY; LayoutContext *pLayout = pData->pLayout; int iHeight; HtmlComputedValues *pV; fixNodeProperties(pData, pNode); pV = HtmlNodeComputedValues(pNode); /* A rowspan of 0 means the cell spans the remainder of the table * vertically. Similarly, a colspan of 0 means the cell spans the * remainder of the table horizontally. */ if (rowspan<=0) { rowspan = (pData->nRow-row); } if (colspan<=0) { colspan = (pData->nCol-col); } y = pData->aY[row]; if (y==0) { y = pData->border_spacing * (row+1); pData->aY[row] = y; } for (i=0; iaWidth[i]; } x += ((col+1) * pData->border_spacing); pBox = &pData->aCell[col].box; assert (pData->aCell[col].finrow==0); pData->aCell[col].finrow = row+rowspan; pData->aCell[col].startrow = row; pData->aCell[col].pNode = pNode; pData->aCell[col].colspan = colspan; nodeGetBoxProperties(pData->pLayout, pNode, 0, &box); pBox->iContaining = pData->aWidth[col] - box.iLeft - box.iRight; for (i=col+1; iiContaining += (pData->aWidth[i] + pData->border_spacing); } HtmlLayoutNodeContent(pData->pLayout, pBox, pNode); /* Handle the 'height' property on the table-cell node. The 'height' * really specifies a minimum height for the row, not the height of the * table-cell box. * * Later: I have now learned that the 'height' property actually refers * to the minimum height of the cell box. The cell box includes the * border edge of the box generated by the table cell. See CSS 2.1 * sections 17.5 and 17.5.3. */ iHeight = pBox->height + box.iTop + box.iBottom; iHeight = MAX(PIXELVAL(pV, HEIGHT, 0), iHeight); belowY = y + iHeight + pData->border_spacing; LOG { HtmlTree *pTree = pLayout->pTree; Tcl_Obj *pCmd = HtmlNodeCommand(pTree, pNode); if (pCmd) { HtmlLog(pTree, "LAYOUTENGINE", "%s tableDrawCells() " "containing=%d actual=%d", Tcl_GetString(pCmd), pBox->iContaining, pBox->width ); } } assert(row+rowspan < pData->nRow+1); pData->aY[row+rowspan] = MAX(pData->aY[row+rowspan], belowY); for (i=row+rowspan+1; i<=pData->nRow; i++) { pData->aY[i] = MAX(pData->aY[row+rowspan], pData->aY[i]); } CHECK_INTEGER_PLAUSIBILITY(pData->aY[row+rowspan]); CHECK_INTEGER_PLAUSIBILITY(pBox->vc.bottom); CHECK_INTEGER_PLAUSIBILITY(pBox->vc.right); return TCL_OK; } /* * Context object used by the tableIterate() iteration procedure. i.e. * the functions: * * tableIterate() * rowIterate() * cellIterate() */ struct RowIterateContext { /* The cell and row callbacks */ int (*xRowCallback)(HtmlNode *, int, void *); int (*xCallback)(HtmlNode *, int, int, int, int, void *); ClientData clientData; /* Client data for the callbacks */ /* The following two variables are used to keep track of cells that * span multiple rows. The array aRowSpan is dynamically allocated as * needed and freed before tableIterate() returns. The allocated size * of aRowSpan is stored in nRowSpan. * * When iterating through the columns in a row (i.e. or tags * that are children of a ) if a table cell with a rowspan greater * than 1 is encountered, then aRowSpan[] is set to * rowspan. */ int nRowSpan; int *aRowSpan; int iMaxRow; /* Index of the final row of table */ int iRow; /* The current row number (first row is 0) */ int iCol; /* The current col number (first row is 0) */ }; typedef struct RowIterateContext RowIterateContext; static void cellIterate(pTree, pNode, p) HtmlTree *pTree; HtmlNode *pNode; RowIterateContext *p; { int nSpan = 1; int nRSpan = 1; int col_ok = 0; char const *zSpan = 0; HtmlElementNode *pElem = (HtmlElementNode *)pNode; /* Either this is a synthetic node, or it's 'display' property * is set to "table-cell" (in HTML or ). */ assert( 0 == HtmlNodeParent(pNode) || CSS_CONST_TABLE_CELL == DISPLAY(HtmlNodeComputedValues(pNode)) ); if (pElem->pPropertyValues) { /* Set nSpan to the number of columns this cell spans */ zSpan = HtmlNodeAttr(pNode, "colspan"); nSpan = zSpan?atoi(zSpan):1; if (nSpan <= 0) { nSpan = 1; } /* Set nRowSpan to the number of rows this cell spans */ zSpan = HtmlNodeAttr(pNode, "rowspan"); nRSpan = zSpan?atoi(zSpan):1; if (nRSpan <= 0) { nRSpan = 1; } } /* Now figure out what column this cell falls in. The * value of the 'col' variable is where we would like * to place this cell (i.e. just to the right of the * previous cell), but that might change based on cells * from a previous row with a rowspan greater than 1. * If this is true, we shift the cell one column to the * right until the above condition is false. */ do { int k; for (k = p->iCol; k < (p->iCol + nSpan); k++) { if (k < p->nRowSpan && p->aRowSpan[k]) break; } if (k == (p->iCol + nSpan)) { col_ok = 1; } else { p->iCol++; } } while (!col_ok); /* Update the p->aRowSpan array. It grows here if required. */ if (nRSpan!=1) { int k; if (p->nRowSpan<(p->iCol+nSpan)) { int n = p->iCol+nSpan; p->aRowSpan = (int *)HtmlRealloc(0, (char *)p->aRowSpan, sizeof(int)*n); for (k=p->nRowSpan; kaRowSpan[k] = 0; } p->nRowSpan = n; } for (k=p->iCol; kiCol+nSpan; k++) { assert(k < p->nRowSpan); p->aRowSpan[k] = (nRSpan>1?nRSpan:-1); } } if (p->xCallback) { p->xCallback(pNode, p->iCol, nSpan, p->iRow, nRSpan, p->clientData); } p->iCol += nSpan; p->iMaxRow = MAX(p->iMaxRow, p->iRow + nRSpan - 1); } static int rowIterate(pTree, pNode, p) HtmlTree *pTree; HtmlNode *pNode; RowIterateContext *p; { int k; int ii; /* Either this is a synthetic node, or it's 'display' property * is set to "table-row". */ assert( 0 == HtmlNodeParent(pNode) || CSS_CONST_TABLE_ROW == DISPLAY(HtmlNodeComputedValues(pNode)) ); if (HtmlNodeIsText(pNode)) return 0; p->iCol = 0; for (ii = 0; ii < HtmlNodeNumChildren(pNode); ii++) { HtmlNode *pCell = HtmlNodeChild(pNode, ii); HtmlComputedValues *pV = HtmlNodeComputedValues(pCell); /* Throw away white-space children of the row node. */ if (HtmlNodeIsWhitespace(pCell)) continue; if (DISPLAY(pV) == CSS_CONST_TABLE_CELL) { /* Child has "display:table-cell". Good. */ cellIterate(pTree, pCell, p); } else { /* Have to create a fake node. Bad. */ int jj; HtmlElementNode sCell; memset(&sCell, 0, sizeof(HtmlElementNode)); for (jj = ii + 1; jj < HtmlNodeNumChildren(pNode); jj++) { HtmlNode *pNextRow = HtmlNodeChild(pNode, jj); HtmlComputedValues *pV2 = HtmlNodeComputedValues(pNextRow); if (DISPLAY(pV2) == CSS_CONST_TABLE_CELL) break; } sCell.node.iNode = -1; sCell.nChild = jj - ii; sCell.apChildren = &((HtmlElementNode *)pNode)->apChildren[ii]; cellIterate(pTree, (HtmlNode *)&sCell, p); HtmlLayoutInvalidateCache(pTree, (HtmlNode *)&sCell); ii = jj - 1; } } if (p->xRowCallback) { p->xRowCallback(pNode, p->iRow, p->clientData); } p->iRow++; for (k=0; k < p->nRowSpan; k++) { if (p->aRowSpan[k]) p->aRowSpan[k]--; } return 0; } static void rowGroupIterate(pTree, pNode, p) HtmlTree *pTree; HtmlNode *pNode; RowIterateContext *p; { int ii; if (!pNode) return; /* Either this is a synthetic node, or it's 'display' property * is set to one of "table-row-group", "table-footer-group" or * "table-header-group". */ assert( 0 == HtmlNodeParent(pNode) || CSS_CONST_TABLE_ROW_GROUP==DISPLAY(HtmlNodeComputedValues(pNode)) || CSS_CONST_TABLE_FOOTER_GROUP==DISPLAY(HtmlNodeComputedValues(pNode)) || CSS_CONST_TABLE_HEADER_GROUP==DISPLAY(HtmlNodeComputedValues(pNode)) ); for (ii = 0; ii < HtmlNodeNumChildren(pNode); ii++) { HtmlNode *pRow = HtmlNodeChild(pNode, ii); HtmlComputedValues *pV = HtmlNodeComputedValues(pRow); /* Throw away white-space node children of the node. */ if (HtmlNodeIsWhitespace(pRow)) continue; if (DISPLAY(pV) == CSS_CONST_TABLE_ROW) { /* Child has "display:table-row". Good. */ rowIterate(pTree, pRow, p); } else { /* Have to create a fake node. Bad. */ int jj; HtmlElementNode sRow; memset(&sRow, 0, sizeof(HtmlElementNode)); for (jj = ii + 1; jj < HtmlNodeNumChildren(pNode); jj++) { HtmlNode *pNextRow = HtmlNodeChild(pNode, jj); HtmlComputedValues *pV2 = HtmlNodeComputedValues(pNextRow); if (DISPLAY(pV2) == CSS_CONST_TABLE_ROW) break; } sRow.node.iNode = -1; sRow.nChild = jj - ii; sRow.apChildren = &((HtmlElementNode *)pNode)->apChildren[ii]; rowIterate(pTree, &sRow, p); assert(!sRow.pLayoutCache); ii = jj - 1; } } } /* *--------------------------------------------------------------------------- * * tableIterate -- * * Helper function for HtmlTableLayout, used to iterate through cells * of the table. For the table below, the iteration order is W, X, * Y, Z. * * /-------\ * | W | X | row number = 0 * |-------| * | Y | Z | row number = 1 * \-------/ * * For each cell, the function passed as the second argument is * invoked. The arguments are a pointer to the or node * that identifies the cell, the column number, the colspan, the row * number, the rowspan, and a copy of the pContext argument passed to * iterateTable(). * * After xCallback has been invoked for each cell in a row, the * row-callback (xRowCallback) is invoked for the row. The arguments * to xRowCallback are the node object, the row number and a * copy of the pContext argument passed to tableIterate(). * * TRANSIENT NODES: * * Sometimes, the nodes passed to the xCallback or xRowCallback * callback functions may be allocated on the stack, rather than * actually part of the document tree. This happens when implicit * nodes are inserted. * * Transient (stack) nodes can be identified by the following test: * * if (pNode->pParent == 0) { // Is a transient node } * * Because the node structure is allocated on the stack, it should * not be passed to HtmlDrawBox() etc. * * Results: * None. * * Side effects: * Whatever xCallback does. * *--------------------------------------------------------------------------- */ static void tableIterate(pTree, pNode, xCallback, xRowCallback, pContext) HtmlTree *pTree; HtmlNode *pNode; /* The node */ int (*xCallback)(HtmlNode *, int, int, int, int, void *); /* Callback */ int (*xRowCallback)(HtmlNode *, int, void *); /* Row Callback */ void *pContext; /* pContext of callbacks */ { int ii; HtmlNode *pHeader = 0; /* Table header (i.e. ) */ HtmlNode *pFooter = 0; /* Table footer (i.e. ) */ RowIterateContext sRowContext; memset(&sRowContext, 0, sizeof(RowIterateContext)); sRowContext.xRowCallback = xRowCallback; sRowContext.xCallback = xCallback; sRowContext.clientData = (ClientData)pContext; /* Search for the table header and footer blocks. */ for (ii = 0; ii < HtmlNodeNumChildren(pNode); ii++) { HtmlNode *pChild = HtmlNodeChild(pNode, ii); switch (DISPLAY(HtmlNodeComputedValues(pChild))) { case CSS_CONST_TABLE_FOOTER_GROUP: pFooter = (pFooter ? pFooter : pChild); break; case CSS_CONST_TABLE_HEADER_GROUP: pHeader = (pHeader ? pHeader : pChild); break; } } rowGroupIterate(pTree, pHeader, &sRowContext); for (ii = 0; ii < HtmlNodeNumChildren(pNode); ii++) { HtmlNode *pChild = HtmlNodeChild(pNode, ii); int eDisplay; if (pChild == pFooter || pChild == pHeader) continue; /* Throw away white-space node children of the table node. * Todo: Is this correct? */ if (HtmlNodeIsWhitespace(pChild)) continue; eDisplay = DISPLAY(HtmlNodeComputedValues(pChild)); if ( eDisplay == CSS_CONST_TABLE_ROW_GROUP || eDisplay == CSS_CONST_TABLE_FOOTER_GROUP || eDisplay == CSS_CONST_TABLE_HEADER_GROUP ) { rowGroupIterate(pTree, pChild, &sRowContext); } else { /* Create a transient node */ int jj; HtmlElementNode sRowGroup; for (jj = ii + 1; jj < HtmlNodeNumChildren(pNode); jj++) { HtmlNode *pSibling = HtmlNodeChild(pNode, jj); eDisplay = DISPLAY(HtmlNodeComputedValues(pSibling)); if ( eDisplay == CSS_CONST_TABLE_ROW_GROUP || eDisplay == CSS_CONST_TABLE_FOOTER_GROUP || eDisplay == CSS_CONST_TABLE_HEADER_GROUP ) break; } memset(&sRowGroup, 0, sizeof(HtmlElementNode)); sRowGroup.node.iNode = -1; sRowGroup.nChild = jj - ii; sRowGroup.apChildren = &((HtmlElementNode *)pNode)->apChildren[ii]; rowGroupIterate(pTree, &sRowGroup, &sRowContext); assert(!sRowGroup.pLayoutCache); ii = jj - 1; } } rowGroupIterate(pTree, pFooter, &sRowContext); while (sRowContext.iRow <= sRowContext.iMaxRow && xRowCallback) { xRowCallback(0, sRowContext.iRow, pContext); sRowContext.iRow++; } HtmlFree(sRowContext.aRowSpan); } static void logWidthStage(nStage, pStageLog, nWidth, aWidth) int nStage; Tcl_Obj *pStageLog; int nWidth; int *aWidth; { int ii; if (!pStageLog) return; Tcl_AppendToObj(pStageLog, ", , , or elements. * Since the parser just ignores tags that we don't know about, this * means that all children of the
    Stage ", -1); Tcl_AppendObjToObj(pStageLog, Tcl_NewIntObj(nStage)); for (ii = 0; ii < nWidth; ii++) { Tcl_AppendToObj(pStageLog, "", -1); Tcl_AppendObjToObj(pStageLog, Tcl_NewIntObj(aWidth[ii])); } } static void tableCalculateCellWidths(pData, availablewidth, isAuto) TableData *pData; int availablewidth; /* Total width available for cells */ int isAuto; /* True if the 'width' of the was "auto" */ { /* The values of the following variables are set in the "analysis loop" * (the first loop below) and thereafter left unchanged. */ int nPercentCol = 0; /* Number of percentage width columns */ double fTotalPercent = 0.0; /* Total of percentage widths */ int nExplicitCol = 0; /* Number of explicit pixel width columns */ int iMaxExplicit = 0; /* Total of max-content-width for explicit cols */ int nAutoCol = 0; /* Number of 'auto' width columns */ int iMaxAuto = 0; /* Total of max-content-width for all 'auto' cols */ int iMinAuto = 0; /* Total of min-content-width for all 'auto' cols */ int ii; int jj; int iRemaining = availablewidth; /* Local handles for the input arrays */ int *aMinWidth = pData->aMinWidth; int *aMaxWidth = pData->aMaxWidth; CellReqWidth *aReqWidth = pData->aReqWidth; /* Local handle for the output array */ int *aWidth = pData->aWidth; /* Log the inputs to this function. */ LayoutContext *pLayout = pData->pLayout; Tcl_Obj *pStageLog = 0; LOG { HtmlTree *pTree = pLayout->pTree; Tcl_Obj *pCmd = HtmlNodeCommand(pTree, pData->pNode); if (pCmd) { Tcl_Obj *pLog = Tcl_NewObj(); Tcl_IncrRefCount(pLog); Tcl_AppendToObj(pLog, "Inputs to column width algorithm: ", -1); Tcl_AppendToObj(pLog, "

    Available width is ", -1); Tcl_AppendObjToObj(pLog, Tcl_NewIntObj(availablewidth)); Tcl_AppendToObj(pLog, " (width property was ", -1); Tcl_AppendToObj(pLog, isAuto ? "auto" : "not auto", -1); Tcl_AppendToObj(pLog, ")

    ", -1); logWidthsToTable(pData, pLog); HtmlLog(pTree, "LAYOUTENGINE", "%s tableCalculateCellWidths() %s", Tcl_GetString(pCmd), Tcl_GetString(pLog) ); Tcl_DecrRefCount(pLog); pStageLog = Tcl_NewObj(); Tcl_IncrRefCount(pStageLog); } } /* This loop serves two purposes: * * 1. Allocate each column it's minimum content width. * 2. It is the "analysis loop" refered to above that populates * local variables used by later stages of the algorithm. */ for (ii = 0; ii < pData->nCol; ii++) { aWidth[ii] = aMinWidth[ii]; iRemaining -= aMinWidth[ii]; switch (aReqWidth[ii].eType) { case CELL_WIDTH_AUTO: iMaxAuto += aMaxWidth[ii]; iMinAuto += aMinWidth[ii]; nAutoCol++; break; case CELL_WIDTH_PIXELS: iMaxExplicit += aMaxWidth[ii]; nExplicitCol++; break; case CELL_WIDTH_PERCENT: nPercentCol++; fTotalPercent += aReqWidth[ii].x.fVal; break; } } logWidthStage(1, pStageLog, pData->nCol, aWidth); /* Allocate pixels to percentage width columns */ if (iRemaining > 0) { for (ii = 0; ii < pData->nCol; ii++) { if (aReqWidth[ii].eType == CELL_WIDTH_PERCENT) { int iReq = (50 + (aReqWidth[ii].x.fVal * availablewidth)) / 100; iReq = MAX(0, iReq - aWidth[ii]); aWidth[ii] += iReq; iRemaining -= iReq; } } if (fTotalPercent > 100.0) { int iRemove = (50 + ((fTotalPercent-100.0) * availablewidth)) / 100; for (ii = pData->nCol - 1; ii >= 0; ii--) { if (aReqWidth[ii].eType == CELL_WIDTH_PERCENT) { /* Apparently this is for Gecko compatibility. */ int rem = MIN(aWidth[ii], iRemove); iRemove -= rem; rem = MIN(aWidth[ii] - aMinWidth[ii], rem); iRemaining += rem; aWidth[ii] -= rem; } } } } logWidthStage(2, pStageLog, pData->nCol, aWidth); /* Allocate pixels to explicit width columns */ if (iRemaining > 0) { for (ii = 0; ii < pData->nCol; ii++) { if (aReqWidth[ii].eType == CELL_WIDTH_PIXELS) { int iReq = MAX(0, aReqWidth[ii].x.iVal - aWidth[ii]); aWidth[ii] += iReq; iRemaining -= iReq; } } } logWidthStage(3, pStageLog, pData->nCol, aWidth); /* Allocate pixels to auto width columns */ if (iRemaining > 0) { int iMA = iMaxAuto; iRemaining += iMinAuto; for (ii = 0; iMA > 0 && ii < pData->nCol; ii++) { if (aReqWidth[ii].eType == CELL_WIDTH_AUTO) { int w = MAX(aMinWidth[ii], iRemaining*aMaxWidth[ii]/iMA); aWidth[ii] = w; iRemaining -= w; iMA -= aMaxWidth[ii]; } } } logWidthStage(4, pStageLog, pData->nCol, aWidth); /* Force pixels into fixed columns (subject to max-width) */ if (iRemaining > 0) { int iME = iMaxExplicit; for (ii = 0; ii < pData->nCol; ii++) { if (aReqWidth[ii].eType == CELL_WIDTH_PIXELS) { int w = iRemaining * aMaxWidth[ii] / iME; iME -= aMaxWidth[ii]; iRemaining -= w; aWidth[ii] += w; } } } logWidthStage(5, pStageLog, pData->nCol, aWidth); /* Force pixels into percent columns (not subject to max-width!) */ if (iRemaining > 0 && fTotalPercent < 100.0) { float fTP = fTotalPercent; for (ii = 0; ii < pData->nCol; ii++) { if (aReqWidth[ii].eType == CELL_WIDTH_PERCENT) { int w = iRemaining * aReqWidth[ii].x.fVal / fTP; fTP -= aReqWidth[ii].x.fVal; iRemaining -= w; aWidth[ii] += w; } } } logWidthStage(6, pStageLog, pData->nCol, aWidth); /* Force pixels into any columns (not subject to max-width!) */ if (iRemaining > 0) { for (ii = 0; ii < pData->nCol; ii++) { int w = iRemaining / (pData->nCol - ii); iRemaining -= w; aWidth[ii] += w; } } logWidthStage(7, pStageLog, pData->nCol, aWidth); /* If too many pixels have been allocated, take some back from * the columns. By preference we take pixels from "auto" columns, * followed by "pixel width" columns and finally "percent width" * columns. * * In pseudo-tcl the outer loop would read: * * foreach jj {auto pixels percent} { * reduce_pixels_in_cols_of_type $jj * } */ assert(CELL_WIDTH_AUTO == 0); assert(CELL_WIDTH_PIXELS == 1); assert(CELL_WIDTH_PERCENT == 2); for (jj = 0; iRemaining < 0 && jj < 3; jj++) { /* Total allocated, less the total min-content-width, for the cols */ int iAllocLessMin = 0; for (ii = 0; ii < pData->nCol; ii++) { if (aReqWidth[ii].eType == jj) { iAllocLessMin += (aWidth[ii] - aMinWidth[ii]); } } for (ii = 0; iAllocLessMin > 0 && ii < pData->nCol; ii++){ if (aReqWidth[ii].eType == jj) { int iDiff = aWidth[ii] - aMinWidth[ii]; int iReduce = -1 * (iRemaining * iDiff) / iAllocLessMin; iRemaining += iReduce; iAllocLessMin -= iDiff; aWidth[ii] -= iReduce; } } logWidthStage(jj+8, pStageLog, pData->nCol, aWidth); } LOG { HtmlTree *pTree = pLayout->pTree; Tcl_Obj *pCmd = HtmlNodeCommand(pTree, pData->pNode); if (pCmd) { Tcl_Obj *pLog = Tcl_NewObj(); Tcl_IncrRefCount(pLog); Tcl_AppendToObj(pLog, "

    Summary of algorithm:

    ", -1); Tcl_AppendToObj(pLog, "
      " "
    1. Minimum content width allocation." "
    2. Percent width allocation." "
    3. Explicit pixel width allocation." "
    4. Auto width allocation." "
    5. Force pixels into explicit pixel width cols." "
    6. Force pixels into percent width cols." "
    7. Force pixels into auto width cols." "
    8. Reduce auto width cols. (optional)" "
    9. Reduce explicit pixel width cols. (optional)" "
    10. Reduce percent width cols. (optional)" "
    ", -1 ); Tcl_AppendToObj(pLog, "

    Results of column width algorithm:

    ", -1); Tcl_AppendToObj(pLog, "
    ", -1); for (ii = 0; ii < pData->nCol; ii++) { Tcl_AppendToObj(pLog, "", -1); Tcl_AppendObjToObj(pLog, pStageLog); Tcl_AppendToObj(pLog, "
    Col ", -1); Tcl_AppendObjToObj(pLog, Tcl_NewIntObj(ii)); } Tcl_AppendToObj(pLog, "
    ", -1); HtmlLog(pTree, "LAYOUTENGINE", "%s tableCalculateCellWidths() %s", Tcl_GetString(pCmd), Tcl_GetString(pLog) ); Tcl_DecrRefCount(pLog); } } } static int tableCalculateMaxWidth(pData) TableData *pData; { int *aMaxWidth = pData->aMaxWidth; int *aMinWidth = pData->aMinWidth; CellReqWidth *aReqWidth = pData->aReqWidth; int ii; int ret = 0; float fTotalPercent = 0.0; int iMaxNonPercent = 0; int iPercent = 0; int bConsiderPercent = 0; HtmlComputedValues *pV = HtmlNodeComputedValues(pData->pNode); for (ii = 0; ii < pData->nCol; ii++) { if (aReqWidth[ii].eType == CELL_WIDTH_PIXELS) { ret += MAX(aMinWidth[ii], aReqWidth[ii].x.iVal); } else { assert(aMaxWidth[ii] >= aMinWidth[ii]); ret += aMaxWidth[ii]; } if (aReqWidth[ii].eType == CELL_WIDTH_PERCENT) { float percent = MIN(aReqWidth[ii].x.fVal, 100.0 - fTotalPercent); int w = (aMaxWidth[ii] * 100.0) / MAX(percent, 1.0); iPercent = MAX(iPercent, w); fTotalPercent += percent; bConsiderPercent = 1; } else { iMaxNonPercent += aMaxWidth[ii]; } } #if 0 /* TODO: Including this block breaks the google-groups message page. */ for (p = HtmlNodeParent(pData->pNode); p; p = HtmlNodeParent(p)) { HtmlComputedValues *pComputed = HtmlNodeComputedValues(p); if ( PIXELVAL(pComputed, WIDTH, 0) != PIXELVAL_AUTO || pComputed->ePosition != CSS_CONST_STATIC ) { break; } if ( pComputed->eDisplay == CSS_CONST_TABLE || pComputed->eDisplay == CSS_CONST_TABLE_CELL || pComputed->eDisplay == CSS_CONST_TABLE_ROW ) { bConsiderPercent = 0; break; } } #endif if (bConsiderPercent) { if (fTotalPercent <= 99.0) { iMaxNonPercent = iMaxNonPercent * 100.0 / (100.0 - fTotalPercent); } else if (iMaxNonPercent > 0) { /* If control flows to here, there exists the following: * * + There are one or columns with percentage widths, and * the percentage widths sum to more than 100%. * + There is at least one other column. * * Return something really large for the maximum width in this * case, as the correct rendering is to make the table consume * the full width of the containing block. */ iMaxNonPercent = 10000; } ret = MAX(iMaxNonPercent, ret); ret = MAX(iPercent, ret); } ret = MAX(ret, PIXELVAL(pV, WIDTH, PIXELVAL_AUTO)); return ret; } /* *--------------------------------------------------------------------------- * * HtmlTableLayout -- * * Lay out a table node. * * Todo: Update this comment. * * This is an incomplete implementation of HTML tables - it does not * support the
    node should have tag-type * . Omitting , and is not such a big deal * since it is optional to format these elements differently anyway, * but and are fairly important. * * The table layout algorithm used is described in section 17.5.2.2 of * the CSS 2.1 spec. * * When this function is called, pBox->iContaining contains the width * available to the table content - not including any margin, border or * padding on the table itself. Any pixels allocated between the edge of * the table and the leftmost or rightmost cell due to 'border-spacing' is * included in pBox->iContaining. If the table element has a computed value * for width other than 'auto', then pBox->iContaining is the calculated * 'width' value. Otherwise it is the width available according to the * width of the containing block. * * Results: * None. * * Side effects: * None. * *--------------------------------------------------------------------------- */ int HtmlTableLayout(pLayout, pBox, pNode) LayoutContext *pLayout; BoxContext *pBox; HtmlNode *pNode; /* The node to layout */ { HtmlTree *pTree = pLayout->pTree; HtmlComputedValues *pV = HtmlNodeComputedValues(pNode); int nCol = 0; /* Number of columns in this table */ int i; int availwidth; /* Total width available for cells */ int *aMinWidth = 0; /* Minimum width for each column */ int *aMaxWidth = 0; /* Minimum width for each column */ int *aWidth = 0; /* Actual width for each column */ int *aY = 0; /* Top y-coord for each row */ TableCell *aCell = 0; /* Array of nCol cells used during drawing */ TableData data; CellReqWidth *aReqWidth = 0; CellReqWidth *aSingleReqWidth = 0; memset(&data, 0, sizeof(struct TableData)); data.pLayout = pLayout; data.pNode = pNode; pBox->iContaining = MAX(pBox->iContaining, 0); /* ??? */ assert(pBox->iContaining>=0); assert(pV->eDisplay==CSS_CONST_TABLE); /* Read the value of the 'border-spacing' property. 'border-spacing' may * not take a percentage value, so there is no need to use PIXELVAL(). */ data.border_spacing = pV->iBorderSpacing; /* First step is to figure out how many columns this table has. * There are two ways to do this - by looking at COL or COLGROUP * children of the table, or by counting the cells in each rows. * Technically, we should use the first method if one or more COL or * COLGROUP elements exist. For now though, always use the second * method. */ tableIterate(pTree, pNode, tableCountCells, tableCountRows, &data); nCol = data.nCol; LOG { Tcl_Obj *pCmd = HtmlNodeCommand(pTree, pNode); if (pCmd) { HtmlTree *pTree = pLayout->pTree; HtmlLog(pTree, "LAYOUTENGINE", "%s HtmlTableLayout() " "Dimensions are %dx%d", Tcl_GetString(pCmd), data.nCol, data.nRow ); } } /* Allocate arrays for the minimum and maximum widths of each column */ aMinWidth = (int *)HtmlClearAlloc(0, nCol*sizeof(int)); aMaxWidth = (int *)HtmlClearAlloc(0, nCol*sizeof(int)); aWidth = (int *)HtmlClearAlloc(0, nCol*sizeof(int)); aReqWidth = (CellReqWidth *)HtmlClearAlloc(0, nCol*sizeof(CellReqWidth)); aSingleReqWidth = (CellReqWidth *)HtmlClearAlloc(0, nCol*sizeof(CellReqWidth)); aY = (int *)HtmlClearAlloc(0, (data.nRow+1)*sizeof(int)); aCell = (TableCell *)HtmlClearAlloc(0, data.nCol*sizeof(TableCell)); data.aMaxWidth = aMaxWidth; data.aMinWidth = aMinWidth; data.aWidth = aWidth; data.aReqWidth = aReqWidth; data.aSingleReqWidth = aSingleReqWidth; /* Calculate the minimum, maximum, and requested percentage widths of * each column. The first pass only considers cells that span a single * column. In this case the min/max width of each column is the maximum of * the min/max widths for all cells in the column. * * If the table contains one or more cells that span more than one * column, we make a second pass. The min/max widths are increased, * if necessary, to account for the multi-column cell. In this case, * the width of each column that the cell spans is increased by * the same amount (plus or minus a pixel to account for integer * rounding). */ tableIterate(pTree, pNode, tableColWidthSingleSpan, 0, &data); memcpy(aReqWidth, aSingleReqWidth, nCol*sizeof(CellReqWidth)); tableIterate(pTree, pNode, tableColWidthMultiSpan, 0, &data); pBox->width = 0; availwidth = (pBox->iContaining - (nCol+1) * data.border_spacing); switch (pLayout->minmaxTest) { case 0: tableCalculateCellWidths(&data, availwidth, 0); for (i = 0; i < nCol; i++) { pBox->width += aWidth[i]; } data.aY = aY; data.aCell = aCell; data.pBox = pBox; tableIterate(pTree, pNode, tableDrawCells, tableDrawRow, &data); pBox->height = data.aY[data.nRow]; break; case MINMAX_TEST_MIN: for (i = 0; i < nCol; i++) { pBox->width += aMinWidth[i]; } break; case MINMAX_TEST_MAX: { int minwidth = 0; pBox->width = tableCalculateMaxWidth(&data); pBox->width = MIN(pBox->width, availwidth); for (i = 0; i < nCol; i++) { minwidth += aMinWidth[i]; } pBox->width = MAX(pBox->width, minwidth); break; } default: assert(!"Bad value for LayoutContext.minmaxTest"); } pBox->width += (data.border_spacing * (nCol+1)); HtmlFree(aMinWidth); HtmlFree(aMaxWidth); HtmlFree(aWidth); HtmlFree(aY); HtmlFree(aCell); HtmlFree(aReqWidth); HtmlFree(aSingleReqWidth); HtmlComputedValuesRelease(pTree, data.pDefaultProperties); CHECK_INTEGER_PLAUSIBILITY(pBox->width); CHECK_INTEGER_PLAUSIBILITY(pBox->height); CHECK_INTEGER_PLAUSIBILITY(pBox->vc.bottom); CHECK_INTEGER_PLAUSIBILITY(pBox->vc.right); LOG { Tcl_Obj *pCmd = HtmlNodeCommand(pTree, pNode); if (pCmd) { HtmlTree *pTree = pLayout->pTree; HtmlLog(pTree, "LAYOUTENGINE", "%s HtmlTableLayout() " "Content size is %dx%d", Tcl_GetString(pCmd), pBox->width, pBox->height ); } } return TCL_OK; } tkHTML-4ee7aaa953d6cb59/src/htmltagdb.c000064400000000000000000000214221151224263100170170ustar00nobodynobody /* * htmltagdb.c --- * * This file implements the interface used by other modules to the * HtmlMarkupMap array. Right now this is partially here, and partially * in htmlparse.c. But the idea is that it should all be here soon. * *-------------------------------------------------------------------------- * Copyright (c) 2005 Eolas Technologies Inc. * All rights reserved. * * This Open Source project was made possible through the financial support * of Eolas Technologies Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ static const char rcsid[] = "$Id: htmltagdb.c,v 1.11 2007/11/11 11:00:48 danielk1977 Exp $"; #include "html.h" #include #include #include /* * Public interface to code in this file: * * HtmlMarkupName() * HtmlMarkupFlags() * HtmlMarkup() */ extern HtmlTokenMap HtmlMarkupMap[]; /* The hash table for HTML markup names. ** ** If an HTML markup name hashes to H, then apMap[H] will point to ** a linked list of sgMap structure, one of which will describe the ** the particular markup (if it exists.) */ static HtmlTokenMap *apMap[HTML_MARKUP_HASH_SIZE]; /* Hash a markup name ** ** HTML markup is case insensitive, so this function will give the ** same hash regardless of the case of the markup name. ** ** The value returned is an integer between 0 and HTML_MARKUP_HASH_SIZE-1, ** inclusive. */ static int HtmlHash(htmlPtr, zName) void *htmlPtr; const char *zName; { int h = 0; char c; while ((c = *zName) != 0) { if (isupper(c)) { c = tolower(c); } h = h << 5 ^ h ^ c; zName++; } if (h < 0) { h = -h; } return h % HTML_MARKUP_HASH_SIZE; } /* ** Convert a string to all lower-case letters. */ static void ToLower(z) char *z; { while (*z) { if (isupper(*z)) *z = tolower(*z); z++; } } static int textContent(pTree, pNode, tag) HtmlTree *pTree; HtmlNode *pNode; int tag; { if (tag == Html_Space || tag == Html_Text) { return TAG_OK; } return TAG_CLOSE; } /* *--------------------------------------------------------------------------- * * HtmlMarkup -- * * Results: * None. * * Side effects: * None. * *--------------------------------------------------------------------------- */ HtmlTokenMap * HtmlMarkup(markup) int markup; { if (markup == Html_Text || markup == Html_Space) { static HtmlTokenMap textmapentry = { "text", Html_Text, HTMLTAG_INLINE, textContent, 0 }; return &textmapentry; } else if (markup > 0) { int i = markup-Html_A; assert(i=0 && i=0 && ipCollide) { if (stricmp(pMap->zName, zType) == 0) { return pMap; } } strncpy(buf, zType, 255); buf[255] = 0; return NULL; } /* Initialize the escape sequence hash table */ void HtmlHashInit(htmlPtr, start) void *htmlPtr; int start; { static int isInit = 0; int i; /* For looping thru the list of markup names */ int h; /* The hash on a markup name */ if (isInit) return; for (i = start; i < HTML_MARKUP_COUNT; i++) { h = HtmlHash(htmlPtr, HtmlMarkupMap[i].zName); HtmlMarkupMap[i].pCollide = apMap[h]; apMap[h] = &HtmlMarkupMap[i]; } #ifdef TEST HtmlHashStats(htmlPtr); #endif isInit = 1; } HtmlAttributes * HtmlAttributesNew(argc, argv, arglen, doEscape) int argc; char const **argv; int *arglen; int doEscape; { HtmlAttributes *pMarkup = 0; if (argc > 1) { int nByte; int j; char *zBuf; int nAttr = argc / 2; nByte = sizeof(HtmlAttributes); for (j = 0; j < argc; j++) { nByte += arglen[j] + 1; } nByte += sizeof(struct HtmlAttribute) * (argc - 1); pMarkup = (HtmlAttributes *)HtmlAlloc("HtmlAttributes", nByte); pMarkup->nAttr = nAttr; zBuf = (char *)(&pMarkup->a[nAttr]); for (j=0; j < nAttr; j++) { int idx = (j * 2); pMarkup->a[j].zName = zBuf; memcpy(zBuf, argv[idx], arglen[idx]); zBuf[arglen[idx]] = '\0'; if (doEscape) { HtmlTranslateEscapes(zBuf); ToLower(zBuf); } zBuf += (arglen[idx] + 1); pMarkup->a[j].zValue = zBuf; memcpy(zBuf, argv[idx+1], arglen[idx+1]); zBuf[arglen[idx+1]] = '\0'; if (doEscape) HtmlTranslateEscapes(zBuf); zBuf += (arglen[idx+1] + 1); } } return pMarkup; } /* ** Convert a markup name into a type integer */ int HtmlNameToType(htmlPtr, zType) void *htmlPtr; char *zType; { HtmlTokenMap *pMap = HtmlHashLookup(htmlPtr, zType); return pMap ? pMap->type : Html_Unknown; } /* ** Convert a type into a symbolic name */ const char * HtmlTypeToName(htmlPtr, eTag) void *htmlPtr; int eTag; { if (eTag >= Html_A && eTag < Html_TypeCount) { HtmlTokenMap *pMap = &HtmlMarkupMap[eTag - Html_A]; return pMap->zName; } else { return "???"; } } tkHTML-4ee7aaa953d6cb59/src/htmltcl.c000064400000000000000000002640071151224263100165300ustar00nobodynobody/* *-------------------------------------------------------------------------- * Copyright (c) 2005 Dan Kennedy. * All rights reserved. * * This Open Source project was made possible through the financial support * of Eolas Technologies Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of Eolas Technologies Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ static char const rcsid[] = "@(#) $Id: htmltcl.c,v 1.207 2008/01/16 06:29:27 danielk1977 Exp $"; #include #include #include #include #include #include #include #include "html.h" #include "restrack.h" #include "swproc.h" #include #include "htmldefaultstyle.c" #define LOG if (pTree->options.logcmd) #define SafeCheck(interp,str) if (Tcl_IsSafe(interp)) { \ Tcl_AppendResult(interp, str, " invalid in safe interp", 0); \ return TCL_ERROR; \ } /* We need to get at the TkBindEventProc() function, which is in the * internal stubs table for Tk. So create this structure and hope that * it is compatible enough. */ struct MyTkIntStubs { int magic; void *hooks; void (*zero)(void); void (*one)(void); void (*two)(void); void (*three)(void); void (*tkBindEventProc)(Tk_Window winPtr, XEvent *eventPtr); /* 4 */ }; extern struct MyTkIntStubs *tkIntStubsPtr; #ifndef NDEBUG static int allocCmd(clientData, interp, objc, objv) ClientData clientData; /* The HTML widget data structure */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument strings. */ { return Rt_AllocCommand(0, interp, objc, objv); } static int heapdebugCmd(clientData, interp, objc, objv) ClientData clientData; /* The HTML widget data structure */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument strings. */ { return HtmlHeapDebug(0, interp, objc, objv); } static int hashstatsCmd(clientData, interp, objc, objv) ClientData clientData; /* The HTML widget data structure */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument strings. */ { HtmlTree *pTree = (HtmlTree *)clientData; Tcl_HashEntry *p; Tcl_HashSearch search; int nObj = 0; int nRef = 0; char zRes[128]; for ( p = Tcl_FirstHashEntry(&pTree->aValues, &search); p; p = Tcl_NextHashEntry(&search) ) { HtmlComputedValues *pV = (HtmlComputedValues *)Tcl_GetHashKey(&pTree->aValues, p); nObj++; nRef += pV->nRef; } sprintf(zRes, "%d %d", nObj, nRef); Tcl_SetResult(interp, zRes, TCL_VOLATILE); return TCL_OK; } #endif struct SubCmd { const char *zName; Tcl_ObjCmdProc *xFunc; }; typedef struct SubCmd SubCmd; /* *--------------------------------------------------------------------------- * * HtmlLog -- * HtmlTimer -- * * This function is used by various parts of the widget to output internal * information that may be useful in debugging. * * The first argument is the HtmlTree structure. The second is a string * identifying the sub-system logging the message. The third argument is a * printf() style format string and subsequent arguments are substituted * into it to form the logged message. * * If -logcmd is set to an empty string, this function is a no-op. * Otherwise, the name of the subsystem and the formatted error message are * appended to the value of the -logcmd option and the result executed as a * Tcl script. * * This function is replaced with an empty macro if NDEBUG is defined at * compilation time. If the "-logcmd" option is set to an empty string it * returns very quickly. * * Results: * None. * * Side effects: * Invokes the -logcmd script, if it is not "". * *--------------------------------------------------------------------------- */ void logCommon( HtmlTree *pTree, Tcl_Obj *pLogCmd, CONST char *zSubject, CONST char *zFormat, va_list ap ) { if (pLogCmd) { char *zDyn = 0; char zStack[200]; char *zBuf = zStack; int nBuf; Tcl_Obj *pCmd; nBuf = vsnprintf(zBuf, 200, zFormat, ap); if (nBuf >= 200) { zDyn = HtmlAlloc(0, nBuf + 10); zBuf = zDyn; nBuf = vsnprintf(zBuf, nBuf + 1, zFormat, ap); } pCmd = Tcl_DuplicateObj(pLogCmd); Tcl_IncrRefCount(pCmd); Tcl_ListObjAppendElement(0, pCmd, Tcl_NewStringObj(zSubject, -1)); Tcl_ListObjAppendElement(0, pCmd, Tcl_NewStringObj(zBuf, nBuf)); if (Tcl_EvalObjEx(pTree->interp, pCmd, TCL_GLOBAL_ONLY)) { Tcl_BackgroundError(pTree->interp); } Tcl_DecrRefCount(pCmd); HtmlFree(zDyn); } } void HtmlTimer(HtmlTree *pTree, CONST char *zSubject, CONST char *zFormat, ...) { va_list ap; va_start(ap, zFormat); logCommon(pTree, pTree->options.timercmd, zSubject, zFormat, ap); } void HtmlLog(HtmlTree *pTree, CONST char *zSubject, CONST char *zFormat, ...) { va_list ap; va_start(ap, zFormat); logCommon(pTree, pTree->options.logcmd, zSubject, zFormat, ap); } /* *--------------------------------------------------------------------------- * * doLoadDefaultStyle -- * * Load the default-style sheet into the current stylesheet configuration. * The text of the default stylesheet is stored in the -defaultstyle * option. * * This function is called once when the widget is created and each time * [.html reset] is called thereafter. * * Results: * None. * * Side effects: * Loads the default style. * *--------------------------------------------------------------------------- */ static void doLoadDefaultStyle(pTree) HtmlTree *pTree; { Tcl_Obj *pObj = pTree->options.defaultstyle; Tcl_Obj *pId = Tcl_NewStringObj("agent", 5); assert(pObj); Tcl_IncrRefCount(pId); HtmlStyleParse(pTree, pObj, pId, 0, 0, 0); Tcl_DecrRefCount(pId); } /* *--------------------------------------------------------------------------- * * doSingleScrollCallback -- * * Helper function for doScrollCallback(). * * Results: * None. * * Side effects: * May invoke the script in *pScript. * *--------------------------------------------------------------------------- */ static void doSingleScrollCallback(interp, pScript, iOffScreen, iTotal, iPage) Tcl_Interp *interp; Tcl_Obj *pScript; int iOffScreen; int iTotal; int iPage; { if (pScript) { double fArg1; double fArg2; int rc; Tcl_Obj *pEval; if (iTotal == 0){ fArg1 = 0.0; fArg2 = 1.0; } else { fArg1 = (double)iOffScreen / (double)iTotal; fArg2 = (double)(iOffScreen + iPage) / (double)iTotal; fArg2 = MIN(1.0, fArg2); } pEval = Tcl_DuplicateObj(pScript); Tcl_IncrRefCount(pEval); Tcl_ListObjAppendElement(interp, pEval, Tcl_NewDoubleObj(fArg1)); Tcl_ListObjAppendElement(interp, pEval, Tcl_NewDoubleObj(fArg2)); rc = Tcl_EvalObjEx(interp, pEval, TCL_EVAL_DIRECT|TCL_EVAL_GLOBAL); if (TCL_OK != rc) { Tcl_BackgroundError(interp); } Tcl_DecrRefCount(pEval); } } /* *--------------------------------------------------------------------------- * * doScrollCallback -- * * Invoke both the -xscrollcommand and -yscrollcommand scripts (unless they * are set to empty strings). The arguments passed to the two scripts are * calculated based on the current values of HtmlTree.iScrollY, * HtmlTree.iScrollX and HtmlTree.canvas. * * Results: * None. * * Side effects: * May invoke either or both of the -xscrollcommand and -yscrollcommand * scripts. * *--------------------------------------------------------------------------- */ static void doScrollCallback(pTree) HtmlTree *pTree; { Tcl_Interp *interp = pTree->interp; Tk_Window win = pTree->tkwin; Tcl_Obj *pScrollCommand; int iOffScreen; int iTotal; int iPage; if (!Tk_IsMapped(win)) return; pScrollCommand = pTree->options.yscrollcommand; iOffScreen = pTree->iScrollY; iTotal = pTree->canvas.bottom; iPage = Tk_Height(win); doSingleScrollCallback(interp, pScrollCommand, iOffScreen, iTotal, iPage); pScrollCommand = pTree->options.xscrollcommand; iOffScreen = pTree->iScrollX; iTotal = pTree->canvas.right; iPage = Tk_Width(win); doSingleScrollCallback(interp, pScrollCommand, iOffScreen, iTotal, iPage); } /* *--------------------------------------------------------------------------- * * HtmlCheckRestylePoint -- * * Check that for each node in the tree one of the following is true: * * 1. The node is a text node, or * 2. The node has a computed style (HtmlElementNode.pComputed!=0), or * 3. The node is HtmlTree.cb.pRestyle, or * 4. The node is a descendant of a pRestyle or a descendent of * a right-sibling of pRestyle. * * Results: * None. * * Side effects: * *--------------------------------------------------------------------------- */ #ifndef NDEBUG static int checkRestylePointCb(pTree, pNode, clientData) HtmlTree *pTree; HtmlNode *pNode; ClientData clientData; { HtmlNode *pParent; HtmlNode *p; /* Condition 1 */ if (HtmlNodeIsText(pNode)) goto ok_out; /* Condition 2 */ if (HtmlNodeComputedValues(pNode)) goto ok_out; /* Condition 3 */ if (pNode==pTree->cb.pRestyle) goto ok_out; /* Condition 4 */ assert(pTree->cb.pRestyle); pParent = HtmlNodeParent(pTree->cb.pRestyle); for (p = pNode; p && HtmlNodeParent(p) != pParent; p = HtmlNodeParent(p)); assert(p); for ( ; p && p != pTree->cb.pRestyle; p = HtmlNodeLeftSibling(p)); assert(p); ok_out: return HTML_WALK_DESCEND; } void HtmlCheckRestylePoint(pTree) HtmlTree *pTree; { HtmlWalkTree(pTree, 0, checkRestylePointCb, 0); } #endif /* #ifndef NDEBUG */ static void callbackHandler(ClientData clientData); static void runDynamicStyleEngine(ClientData clientData); static void runStyleEngine(ClientData clientData); static void runLayoutEngine(ClientData clientData); #if defined(TKHTML_ENABLE_PROFILE) #define INSTRUMENTED(name, id) \ static void real_ ## name (ClientData); \ static void name (clientData) \ ClientData clientData; \ { \ HtmlTree *p = (HtmlTree *)clientData; \ HtmlInstrumentCall(p->pInstrumentData, id, real_ ## name, clientData); \ } \ static void real_ ## name (clientData) \ ClientData clientData; #else #define INSTRUMENTED(name, id) \ static void name (clientData) \ ClientData clientData; #endif INSTRUMENTED(runDynamicStyleEngine, HTML_INSTRUMENT_DYNAMIC_STYLE_ENGINE) { HtmlTree *pTree = (HtmlTree *)clientData; assert(pTree->cb.pDynamic); HtmlCssCheckDynamic(pTree); } INSTRUMENTED(runStyleEngine, HTML_INSTRUMENT_STYLE_ENGINE) { HtmlTree *pTree = (HtmlTree *)clientData; HtmlNode *pRestyle = pTree->cb.pRestyle; pTree->cb.pRestyle = 0; assert(pTree->cb.pSnapshot); assert(pRestyle); HtmlStyleApply(pTree, pRestyle); HtmlRestackNodes(pTree); HtmlCheckRestylePoint(pTree); if (!pTree->options.imagecache) { HtmlImageServerDoGC(pTree); } } INSTRUMENTED(runLayoutEngine, HTML_INSTRUMENT_LAYOUT_ENGINE) { HtmlTree *pTree = (HtmlTree *)clientData; HtmlDamage *pD; assert(pTree->cb.pSnapshot); if (!pTree->options.enablelayout) return; pD = pTree->cb.pDamage; HtmlLayout(pTree); if (0 && pTree->cb.isForce) { pTree->cb.flags |= HTML_SCROLL; } if (!pTree->cb.pSnapshot) { pTree->cb.flags |= HTML_NODESCROLL; } doScrollCallback(pTree); } /* *--------------------------------------------------------------------------- * * callbackHandler -- * * This is called, usually from an idle-callback handler, to update * the widget display. This may involve all manner of stuff, depending * on the bits set in the HtmlTree.cb.flags mask. Basically, it * is a 5 step process: * * 1. Dynamic * 2. Style engine, * 3. Layout engine, * 4. Repair, * 5. Scroll * * Results: * None. * * Side effects: * None. * *--------------------------------------------------------------------------- */ INSTRUMENTED(callbackHandler, HTML_INSTRUMENT_CALLBACK) { HtmlTree *pTree = (HtmlTree *)clientData; HtmlCallback *p = &pTree->cb; int offscreen; int force_redraw = 0; assert( !pTree->pRoot || HtmlNodeComputedValues(pTree->pRoot) || pTree->cb.pRestyle==pTree->pRoot ); HtmlCheckRestylePoint(pTree); HtmlLog(pTree, "CALLBACK", "flags=( %s%s%s%s%s) pDynamic=%s pRestyle=%s scroll=(+%d+%d) ", (p->flags & HTML_DYNAMIC ? "Dynamic " : ""), (p->flags & HTML_RESTYLE ? "Style " : ""), (p->flags & HTML_LAYOUT ? "Layout " : ""), (p->flags & HTML_DAMAGE ? "Damage " : ""), (p->flags & HTML_SCROLL ? "Scroll " : ""), (p->pDynamic?Tcl_GetString(HtmlNodeCommand(pTree,p->pDynamic)):"N/A"), (p->pRestyle?Tcl_GetString(HtmlNodeCommand(pTree,p->pRestyle)):"N/A"), p->iScrollX, p->iScrollY ); assert(!pTree->cb.inProgress); pTree->cb.inProgress = 1; /* If the HTML_DYNAMIC flag is set, then call HtmlCssCheckDynamic() * to recalculate all the dynamic CSS rules that may apply to * the sub-tree rooted at HtmlCallback.pDynamic. CssCheckDynamic() * calls HtmlCallbackRestyle() if any computed style values are * modified (setting the HTML_RESTYLE flag). */ if (pTree->cb.flags & HTML_DYNAMIC) { runDynamicStyleEngine(clientData); } HtmlCheckRestylePoint(pTree); pTree->cb.flags &= ~HTML_DYNAMIC; /* If the HtmlCallback.pRestyle variable is set, then recalculate * style information for the sub-tree rooted at HtmlCallback.pRestyle, * and the sub-trees rooted at all right-siblings of pRestyle. * Note that restyling a node may invoke the -imagecmd callback. * * Todo: This seems dangerous. What happens if the -imagecmd calls * [.html parse] or something? */ if (pTree->cb.flags & HTML_RESTYLE) { runStyleEngine(clientData); } pTree->cb.flags &= ~HTML_RESTYLE; /* If the HTML_LAYOUT flag is set, run the layout engine. If the layout * engine is run, then also set the HTML_SCROLL bit in the * HtmlCallback.flags bitmask. This ensures that the entire display is * redrawn and that the Tk windows for any replaced nodes are correctly * mapped, unmapped or moved. */ assert(pTree->cb.pDamage == 0 || pTree->cb.flags & HTML_DAMAGE); if (pTree->cb.flags & HTML_LAYOUT) { runLayoutEngine(clientData); } pTree->cb.flags &= ~HTML_LAYOUT; if (pTree->cb.pSnapshot) { HtmlCanvasSnapshot *pSnapshot = 0; HtmlDrawSnapshotDamage(pTree, pTree->cb.pSnapshot, &pSnapshot); HtmlDrawSnapshotFree(pTree, pTree->cb.pSnapshot); HtmlDrawSnapshotFree(pTree, pSnapshot); pTree->cb.pSnapshot = 0; } if (pTree->cb.isForce) { assert(pTree->cb.inProgress); pTree->cb.inProgress = 0; return; } /* If the HTML_DAMAGE flag is set, repaint one or more window regions. */ assert(pTree->cb.pDamage == 0 || pTree->cb.flags & HTML_DAMAGE); if (pTree->cb.flags & HTML_DAMAGE) { HtmlDamage *pD = pTree->cb.pDamage; if (pD && ( (pTree->cb.flags & HTML_SCROLL)==0 || pD->x != 0 || pD->y != 0 || pD->w < Tk_Width(pTree->tkwin) || pD->h < Tk_Height(pTree->tkwin) )) { pTree->cb.pDamage = 0; while (pD) { HtmlDamage *pNext = pD->pNext; HtmlLog(pTree, "ACTION", "Repair: %dx%d +%d+%d", pD->w, pD->h, pD->x, pD->y ); HtmlWidgetRepair(pTree, pD->x, pD->y, pD->w, pD->h, 1); HtmlFree(pD); pD = pNext; } } } /* If the HTML_SCROLL flag is set, scroll the viewport. */ if (pTree->cb.flags & HTML_SCROLL) { clock_t scrollClock = 0; HtmlLog(pTree, "ACTION", "SetViewport: x=%d y=%d force=%d isFixed=%d", p->iScrollX, p->iScrollY, force_redraw, pTree->isFixed ); scrollClock = clock(); HtmlWidgetSetViewport(pTree, p->iScrollX, p->iScrollY, 0); scrollClock = clock() - scrollClock; HtmlLog(pTree, "TIMING", "SetViewport: clicks=%d", scrollClock); } if (pTree->cb.flags & (HTML_SCROLL)) { doScrollCallback(pTree); } pTree->cb.flags = 0; assert(pTree->cb.inProgress); pTree->cb.inProgress = 0; if (pTree->cb.pDamage) { pTree->cb.flags = HTML_DAMAGE; Tcl_DoWhenIdle(callbackHandler, (ClientData)pTree); } offscreen = MAX(0, MIN(pTree->canvas.bottom - Tk_Height(pTree->tkwin), pTree->iScrollY) ); if (offscreen != pTree->iScrollY) { HtmlCallbackScrollY(pTree, offscreen); } offscreen = MAX(0, MIN(pTree->canvas.right - Tk_Width(pTree->tkwin), pTree->iScrollX) ); if (offscreen != pTree->iScrollX) { HtmlCallbackScrollX(pTree, offscreen); } } static void delayCallbackHandler(clientData) ClientData clientData; { HtmlTree *pTree = (HtmlTree *)clientData; pTree->delayToken = 0; if (pTree->cb.flags) { callbackHandler(clientData); } } /* *--------------------------------------------------------------------------- * * HtmlCallbackForce -- * * If there is a callback scheduled, execute it now instead of waiting * for the idle loop. * * An exception: If the only reason for the callback is widget damage * (a repaint-area callback), don't run it. * * Results: * None. * * Side effects: * None. * *--------------------------------------------------------------------------- */ void HtmlCallbackForce(pTree) HtmlTree *pTree; { if ( (pTree->cb.flags & ~(HTML_DAMAGE|HTML_SCROLL|HTML_NODESCROLL)) && (!pTree->cb.inProgress) ) { ClientData clientData = (ClientData)pTree; assert(!pTree->cb.isForce); pTree->cb.isForce++; callbackHandler(clientData); pTree->cb.isForce--; assert(pTree->cb.isForce >= 0); if (pTree->cb.flags == 0) { Tcl_CancelIdleCall(callbackHandler, clientData); } } } /* *--------------------------------------------------------------------------- * * upgradeRestylePoint -- * * Results: * True if argument pNode is located in the document tree, or false * if it is located in some orphan tree. * * Side effects: * None. * *--------------------------------------------------------------------------- */ static int upgradeRestylePoint(ppRestyle, pNode) HtmlNode **ppRestyle; HtmlNode *pNode; { HtmlNode *pA; HtmlNode *pB; assert(pNode && ppRestyle); /* Do nothing if pNode is part of an orphan tree */ for (pA = pNode; pA; pA = HtmlNodeParent(pA)) { if (pA->iNode == HTML_NODE_ORPHAN) return 0; } for (pA = *ppRestyle; pA; pA = HtmlNodeParent(pA)) { HtmlNode *pParentA = HtmlNodeParent(pA); for (pB = pNode; pB; pB = HtmlNodeParent(pB)) { if (pB == pA) { *ppRestyle = pB; return 1; } if (HtmlNodeParent(pB) == pParentA) { int i; for (i = 0; i < HtmlNodeNumChildren(pParentA); i++) { HtmlNode *pChild = HtmlNodeChild(pParentA, i); if (pChild == pB || pChild == pA) { *ppRestyle = pChild; return 1; } } assert(!"Cannot happen"); } } } assert(!*ppRestyle); *ppRestyle = pNode; return 1; } static void snapshotLayout(pTree) HtmlTree *pTree; { if (pTree->cb.pSnapshot == 0) { pTree->cb.pSnapshot = HtmlDrawSnapshot(pTree, 0); } } static void snapshotZero(pTree) HtmlTree *pTree; { HtmlNodeReplacement *p; HtmlDrawSnapshotFree(pTree, pTree->cb.pSnapshot); pTree->cb.pSnapshot = HtmlDrawSnapshotZero(pTree); for (p = pTree->pMapped; p ; p = p->pNext) { p->iCanvasX = -10000; p->iCanvasY = -10000; } } /* *--------------------------------------------------------------------------- * * HtmlCallbackRestyle -- * * Next widget idle-callback, recalculate style information for the * sub-tree rooted at pNode. This function is a no-op if (pNode==0). * If pNode is the root of the document, then the list of dynamic * conditions (HtmlNode.pDynamic) that apply to each node is also * recalculated. * * Results: * None. * * Side effects: * May modify HtmlTree.cb and/or register for an idle callback with * the Tcl event loop. * *--------------------------------------------------------------------------- */ void HtmlCallbackRestyle(pTree, pNode) HtmlTree *pTree; HtmlNode *pNode; { if (pNode) { snapshotLayout(pTree); if (upgradeRestylePoint(&pTree->cb.pRestyle, pNode)) { if (!pTree->cb.flags) { Tcl_DoWhenIdle(callbackHandler, (ClientData)pTree); } pTree->cb.flags |= HTML_RESTYLE; assert(pTree->cb.pSnapshot); } } /* This is also where the text-representation of the document is * invalidated. If the style of a node is to change, or a new node * that has no style is added, then the current text-representation * is clearly suspect. */ HtmlTextInvalidate(pTree); HtmlCssSearchInvalidateCache(pTree); } /* *--------------------------------------------------------------------------- * * HtmlCallbackDynamic -- * * Next widget idle-callback, check if any dynamic CSS conditions * attached to nodes that are part of the sub-tree rooted at pNode * have changed. If so, restyle the affected nodes. This function * is a no-op if (pNode==0). * * Results: * None. * * Side effects: * May modify HtmlTree.cb and/or register for an idle callback with * the Tcl event loop. * *--------------------------------------------------------------------------- */ void HtmlCallbackDynamic(pTree, pNode) HtmlTree *pTree; HtmlNode *pNode; { if (pNode) { if (upgradeRestylePoint(&pTree->cb.pDynamic, pNode)) { if (!pTree->cb.flags) { Tcl_DoWhenIdle(callbackHandler, (ClientData)pTree); } pTree->cb.flags |= HTML_DYNAMIC; } } } /* *--------------------------------------------------------------------------- * * HtmlCallbackLayout -- * * Ensure the layout of node pNode is recalculated next idle * callback. This is a no-op if (pNode==0). * * Results: * None. * * Side effects: * May modify HtmlTree.cb and/or register for an idle callback with * the Tcl event loop. May expire layout-caches belonging to pNode * and it's ancestor nodes. * *--------------------------------------------------------------------------- */ void HtmlCallbackLayout(pTree, pNode) HtmlTree *pTree; HtmlNode *pNode; { if (pNode) { HtmlNode *p; snapshotLayout(pTree); if (!pTree->cb.flags) { Tcl_DoWhenIdle(callbackHandler, (ClientData)pTree); } pTree->cb.flags |= HTML_LAYOUT; assert(pTree->cb.pSnapshot); for (p = pNode; p; p = HtmlNodeParent(p)) { HtmlLayoutInvalidateCache(pTree, p); } pTree->isBboxOk = 0; } } static int setSnapshotId(pTree, pNode) HtmlTree *pTree; HtmlNode *pNode; { pNode->iSnapshot = pTree->iLastSnapshotId; return HTML_WALK_DESCEND; } void HtmlCallbackDamageNode(pTree, pNode) HtmlTree *pTree; HtmlNode *pNode; { if (pTree->cb.pSnapshot) { if (pNode->iSnapshot != pTree->iLastSnapshotId){ HtmlWalkTree(pTree, pNode, setSnapshotId, 0); } } else { int x, y, w, h; HtmlWidgetNodeBox(pTree, pNode, &x, &y, &w, &h); HtmlCallbackDamage(pTree, x-pTree->iScrollX, y-pTree->iScrollY, w, h); } } /* *--------------------------------------------------------------------------- * * HtmlCallbackDamage -- * * Schedule a region to be repainted during the next callback. * The x and y arguments are relative to the viewport, not the * document origin. * * Results: * None. * * Side effects: * None. * *--------------------------------------------------------------------------- */ void HtmlCallbackDamage(pTree, x, y, w, h) HtmlTree *pTree; int x; int y; int w; int h; { HtmlDamage *pNew; HtmlDamage *p; /* Clip the values to the viewport */ if (x < 0) {w += x; x = 0;} if (y < 0) {h += y; y = 0;} w = MIN(w, Tk_Width(pTree->tkwin) - x); h = MIN(h, Tk_Height(pTree->tkwin) - y); /* If the damaged region is not currently visible, do nothing */ if (w <= 0 || h <= 0) { return; } /* Loop through the current list of damaged rectangles. If possible * clip the new damaged region so that the same part of the display * is not painted more than once. */ for (p = pTree->cb.pDamage; p; p = p->pNext) { /* Check if region p completely encapsulates the new region. If so, * we need do nothing. */ assert(pTree->cb.flags & HTML_DAMAGE); if ( p->x <= x && p->y <= y && (p->x + p->w) >= (x + w) && (p->y + p->h) >= (y + h) ) { return; } } #if 0 if (pTree->cb.flags & HTML_DAMAGE) { int x2 = MAX(x + w, pTree->cb.x + pTree->cb.w); int y2 = MAX(y + h, pTree->cb.y + pTree->cb.h); pTree->cb.x = MIN(pTree->cb.x, x); pTree->cb.y = MIN(pTree->cb.y, y); pTree->cb.w = x2 - pTree->cb.x; pTree->cb.h = y2 - pTree->cb.y; } else { pTree->cb.x = x; pTree->cb.y = y; pTree->cb.w = w; pTree->cb.h = h; } assert(pTree->cb.x >= 0); assert(pTree->cb.y >= 0); assert(pTree->cb.w > 0); assert(pTree->cb.h > 0); #endif pNew = HtmlNew(HtmlDamage); pNew->x = x; pNew->y = y; pNew->w = w; pNew->h = h; pNew->pNext = pTree->cb.pDamage; pTree->cb.pDamage = pNew; if (!pTree->cb.flags) { Tcl_DoWhenIdle(callbackHandler, (ClientData)pTree); } pTree->cb.flags |= HTML_DAMAGE; } void HtmlCallbackScrollY(pTree, y) HtmlTree *pTree; int y; { if (!pTree->cb.flags) { Tcl_DoWhenIdle(callbackHandler, (ClientData)pTree); } pTree->cb.flags |= HTML_SCROLL; pTree->cb.iScrollY = y; } void HtmlCallbackScrollX(pTree, x) HtmlTree *pTree; int x; { if (!pTree->cb.flags) { Tcl_DoWhenIdle(callbackHandler, (ClientData)pTree); } pTree->cb.flags |= HTML_SCROLL; pTree->cb.iScrollX = x; } /* *--------------------------------------------------------------------------- * * cleanupHandlerTable -- * * This function is called to delete the contents of one of the * HtmlTree.aScriptHandler, aNodeHandler or aParseHandler tables. * It is called as the tree is being deleted. * * Results: * None. * * Side effects: * None. * *--------------------------------------------------------------------------- */ static void cleanupHandlerTable(pHash) Tcl_HashTable *pHash; { Tcl_HashEntry *pEntry; Tcl_HashSearch search; for ( pEntry = Tcl_FirstHashEntry(pHash, &search); pEntry; pEntry = Tcl_NextHashEntry(&search) ) { Tcl_DecrRefCount((Tcl_Obj *)Tcl_GetHashValue(pEntry)); } Tcl_DeleteHashTable(pHash); } /* *--------------------------------------------------------------------------- * * deleteWidget -- * * destroy $html * * Results: * None. * * Side effects: * None. * *--------------------------------------------------------------------------- */ static void deleteWidget(clientData) ClientData clientData; { HtmlDamage *pDamage; HtmlTree *pTree = (HtmlTree *)clientData; HtmlTreeClear(pTree); /* Delete the contents of the three "handler" hash tables */ cleanupHandlerTable(&pTree->aNodeHandler); cleanupHandlerTable(&pTree->aAttributeHandler); cleanupHandlerTable(&pTree->aParseHandler); cleanupHandlerTable(&pTree->aScriptHandler); /* Clear any widget tags */ HtmlTagCleanupTree(pTree); /* Clear the remaining colors etc. from the styler code hash tables */ HtmlComputedValuesCleanupTables(pTree); /* Delete the image-server */ HtmlImageServerDoGC(pTree); HtmlImageServerShutdown(pTree); /* Delete the search cache. */ HtmlCssSearchShutdown(pTree); /* Cancel any pending idle callback */ Tcl_CancelIdleCall(callbackHandler, (ClientData)pTree); if (pTree->delayToken) { Tcl_DeleteTimerHandler(pTree->delayToken); } pTree->delayToken = 0; while ((pDamage = pTree->cb.pDamage)) { pTree->cb.pDamage = pDamage->pNext; HtmlFree(pDamage); } /* Atoms table */ Tcl_DeleteHashTable(&pTree->aAtom); /* Delete the structure itself */ HtmlFree(pTree); } /* *--------------------------------------------------------------------------- * * widgetCmdDel -- * * This command is invoked by Tcl when a widget object command is * deleted. This can happen under two circumstances: * * * A script deleted the command. In this case we should delete * the widget window (and everything else via the window event * callback) as well. * * A script deleted the widget window. In this case we need * do nothing. * * Results: * None. * * Side effects: * None. * *--------------------------------------------------------------------------- */ static void widgetCmdDel(clientData) ClientData clientData; { HtmlTree *pTree = (HtmlTree *)clientData; if( !pTree->isDeleted ){ pTree->cmd = 0; Tk_DestroyWindow(pTree->tkwin); } } /* *--------------------------------------------------------------------------- * * eventHandler -- * * Results: * None. * * Side effects: * None. * *--------------------------------------------------------------------------- */ static void eventHandler(clientData, pEvent) ClientData clientData; XEvent *pEvent; { HtmlTree *pTree = (HtmlTree *)clientData; switch (pEvent->type) { case ConfigureNotify: { /* XConfigureEvent *p = (XConfigureEvent*)pEvent; */ int iWidth = Tk_Width(pTree->tkwin); int iHeight = Tk_Height(pTree->tkwin); HtmlLog(pTree, "EVENT", "ConfigureNotify: width=%dpx", iWidth); if ( iWidth != pTree->iCanvasWidth || iHeight != pTree->iCanvasHeight ) { HtmlCallbackLayout(pTree, pTree->pRoot); snapshotZero(pTree); HtmlCallbackDamage(pTree, 0, 0, iWidth, iHeight); } break; } case UnmapNotify: { break; } case DestroyNotify: { pTree->isDeleted = 1; Tcl_DeleteCommandFromToken(pTree->interp, pTree->cmd); deleteWidget(pTree); break; } } } static void docwinEventHandler(clientData, pEvent) ClientData clientData; XEvent *pEvent; { HtmlTree *pTree = (HtmlTree *)clientData; switch (pEvent->type) { case Expose: { XExposeEvent *p = (XExposeEvent *)pEvent; HtmlLog(pTree, "EVENT", "Docwin Expose: x=%d y=%d width=%d height=%d", p->x, p->y, p->width, p->height ); HtmlCallbackDamage(pTree, p->x + Tk_X(pTree->docwin), p->y + Tk_Y(pTree->docwin), p->width, p->height ); break; } case ButtonPress: case ButtonRelease: case MotionNotify: case LeaveNotify: case EnterNotify: /* I am not a bad person. But sometimes people make me do * bad things. This here is a bad thing. The idea is to * have mouse related events delivered to the html widget * window, not this document window. Then, before returning, * mess up the internals of the event so that the processing * in Tk_BindEvent() ignores it. */ pEvent->xmotion.window = Tk_WindowId(pTree->tkwin); pEvent->xmotion.x += Tk_X(pTree->docwin); pEvent->xmotion.y += Tk_Y(pTree->docwin); tkIntStubsPtr->tkBindEventProc(pTree->tkwin, pEvent); pEvent->type = EnterNotify; pEvent->xcrossing.detail = NotifyInferior; break; } } static int relayoutCb(pTree, pNode, clientData) HtmlTree *pTree; HtmlNode *pNode; ClientData clientData; { HtmlCallbackLayout(pTree, pNode); return HTML_WALK_DESCEND; } static int worldChangedCb(pTree, pNode, clientData) HtmlTree *pTree; HtmlNode *pNode; ClientData clientData; { if (!HtmlNodeIsText(pNode)) { HtmlElementNode *pElem = (HtmlElementNode *)pNode; HtmlLayoutInvalidateCache(pTree, pNode); HtmlNodeClearStyle(pTree, pElem); HtmlDrawCanvasItemRelease(pTree, pElem->pBox); pElem->pBox = 0; pTree->isBboxOk = 0; } return HTML_WALK_DESCEND; } void HtmlNodeClearRecursive(pTree, pNode) HtmlTree *pTree; HtmlNode *pNode; { HtmlWalkTree(pTree, pNode, worldChangedCb, 0); } /* *--------------------------------------------------------------------------- * * configureCmd -- * * Implementation of the standard Tk "configure" command. * * configure -OPTION VALUE ?-OPTION VALUE? ... * * TODO: Handle configure of the forms: * configure -OPTION * configure * * Results: * Standard tcl result. * * Side effects: * May set values of HtmlTree.options struct. May call * Tk_GeometryRequest(). * *--------------------------------------------------------------------------- */ static int configureCmd(clientData, interp, objc, objv) ClientData clientData; /* The HTML widget */ Tcl_Interp *interp; /* The interpreter */ int objc; /* Number of arguments */ Tcl_Obj *const *objv; /* List of all arguments */ { static const char *azModes[] = {"quirks","almost standards","standards",0}; static const char *azParseModes[] = {"html","xhtml","xml",0}; /* * Mask bits for options declared in htmlOptionSpec. */ #define GEOMETRY_MASK 0x00000001 #define FT_MASK 0x00000002 #define DS_MASK 0x00000004 #define S_MASK 0x00000008 #define F_MASK 0x00000010 #define L_MASK 0x00000020 /* * Macros to generate static Tk_OptionSpec structures for the * htmlOptionSpec() array. */ #define PIXELS(v, s1, s2, s3) \ {TK_OPTION_PIXELS, "-" #v, s1, s2, s3, -1, \ Tk_Offset(HtmlOptions, v), 0, 0, 0} #define GEOMETRY(v, s1, s2, s3) \ {TK_OPTION_PIXELS, "-" #v, s1, s2, s3, -1, \ Tk_Offset(HtmlOptions, v), 0, 0, GEOMETRY_MASK} #define STRING(v, s1, s2, s3) \ {TK_OPTION_STRING, "-" #v, s1, s2, s3, \ Tk_Offset(HtmlOptions, v), -1, TK_OPTION_NULL_OK, 0, 0} #define STRINGT(v, s1, s2, s3, t) \ {TK_OPTION_STRING_TABLE, "-" #v, s1, s2, s3, -1, \ Tk_Offset(HtmlOptions, v), 0, (ClientData)t, 0} #define BOOLEAN(v, s1, s2, s3, flags) \ {TK_OPTION_BOOLEAN, "-" #v, s1, s2, s3, -1, \ Tk_Offset(HtmlOptions, v), 0, 0, flags} #define OBJ(v, s1, s2, s3, f) \ {TK_OPTION_STRING, "-" #v, s1, s2, s3, \ Tk_Offset(HtmlOptions, v), -1, 0, 0, f} #define DOUBLE(v, s1, s2, s3, f) \ {TK_OPTION_DOUBLE, "-" #v, s1, s2, s3, -1, \ Tk_Offset(HtmlOptions, v), 0, 0, f} /* Option table definition for the html widget. */ static Tk_OptionSpec htmlOptionSpec[] = { /* Standard geometry and scrolling interface - same as canvas, text */ GEOMETRY(height, "height", "Height", "600"), GEOMETRY(width, "width", "Width", "800"), PIXELS (yscrollincrement, "yScrollIncrement", "ScrollIncrement", "20"), PIXELS (xscrollincrement, "xScrollIncrement", "ScrollIncrement", "20"), STRING (xscrollcommand, "xScrollCommand", "ScrollCommand", ""), STRING (yscrollcommand, "yScrollCommand", "ScrollCommand", ""), /* Non-debugging, non-standard options in alphabetical order. */ OBJ (defaultstyle, "defaultStyle", "DefaultStyle", HTML_DEFAULT_CSS, 0), DOUBLE (fontscale, "fontScale", "FontScale", "1.0", F_MASK), OBJ (fonttable, "fontTable", "FontTable", "8 9 10 11 13 15 17", FT_MASK), BOOLEAN (forcefontmetrics, "forceFontMetrics", "ForceFontMetrics", "1", F_MASK), BOOLEAN (forcewidth, "forceWidth", "ForceWidth", "0", L_MASK), BOOLEAN (imagecache, "imageCache", "ImageCache", "1", S_MASK), BOOLEAN (imagepixmapify, "imagePixmapify", "ImagePixmapify", "0", 0), STRING (imagecmd, "imageCmd", "ImageCmd", ""), STRINGT (mode, "mode", "Mode", "standards", azModes), STRINGT (parsemode, "parsemode", "Parsemode", "html", azParseModes), BOOLEAN (shrink, "shrink", "Shrink", "0", S_MASK), DOUBLE (zoom, "zoom", "Zoom", "1.0", F_MASK), /* Debugging options */ BOOLEAN (enablelayout, "enableLayout", "EnableLayout", "1", S_MASK), BOOLEAN (layoutcache, "layoutCache", "LayoutCache", "1", L_MASK), STRING (logcmd, "logCmd", "LogCmd", ""), STRING (timercmd, "timerCmd", "TimerCmd", ""), {TK_OPTION_END, 0, 0, 0, 0, 0, 0, 0, 0} }; #undef PIXELS #undef STRING #undef BOOLEAN HtmlTree *pTree = (HtmlTree *)clientData; char *pOptions = (char *)&pTree->options; Tk_Window win = pTree->tkwin; Tk_OptionTable otab = pTree->optionTable; Tk_SavedOptions saved; int mask = 0; int init = 0; /* True if Tk_InitOptions() is called */ int rc; if (!otab) { pTree->optionTable = Tk_CreateOptionTable(interp, htmlOptionSpec); Tk_InitOptions(interp, pOptions, pTree->optionTable, win); init = 1; otab = pTree->optionTable; } rc = Tk_SetOptions( interp, pOptions, otab, objc-2, &objv[2], win, (init?0:&saved), &mask ); if (TCL_OK == rc) { /* Hard-coded minimum values for width and height */ pTree->options.height = MAX(pTree->options.height, 0); pTree->options.width = MAX(pTree->options.width, 0); if (init || (mask & GEOMETRY_MASK)) { int w = pTree->options.width; int h = pTree->options.height; Tk_GeometryRequest(pTree->tkwin, w, h); } if (init || mask & FT_MASK) { int nSize; Tcl_Obj **apSize; int aFontSize[7]; Tcl_Obj *pFT = pTree->options.fonttable; if ( Tcl_ListObjGetElements(interp, pFT, &nSize, &apSize) || nSize != 7 || Tcl_GetIntFromObj(interp, apSize[0], &aFontSize[0]) || Tcl_GetIntFromObj(interp, apSize[1], &aFontSize[1]) || Tcl_GetIntFromObj(interp, apSize[2], &aFontSize[2]) || Tcl_GetIntFromObj(interp, apSize[3], &aFontSize[3]) || Tcl_GetIntFromObj(interp, apSize[4], &aFontSize[4]) || Tcl_GetIntFromObj(interp, apSize[5], &aFontSize[5]) || Tcl_GetIntFromObj(interp, apSize[6], &aFontSize[6]) ) { Tcl_ResetResult(interp); Tcl_AppendResult(interp, "expected list of 7 integers but got ", "\"", Tcl_GetString(pFT), "\"", 0 ); rc = TCL_ERROR; } else { memcpy(pTree->aFontSizeTable, aFontSize, sizeof(aFontSize)); mask |= S_MASK; HtmlComputedValuesFreePrototype(pTree); } } if (mask & (S_MASK|F_MASK)) { HtmlImageServerSuspendGC(pTree); HtmlDrawCleanup(pTree, &pTree->canvas); HtmlDrawSnapshotFree(pTree, pTree->cb.pSnapshot); pTree->cb.pSnapshot = 0; HtmlCallbackRestyle(pTree, pTree->pRoot); HtmlWalkTree(pTree, pTree->pRoot, worldChangedCb, 0); HtmlCallbackDamage(pTree, 0, 0, Tk_Width(win), Tk_Height(win)); #ifndef NDEBUG if (1) { Tcl_HashSearch search; assert(0 == Tcl_FirstHashEntry(&pTree->aValues, &search)); } #endif } if (mask & F_MASK) { /* This happens when one of the font related options changes. * The key here is that the font cache (HtmlTree.aFont) must * be completely empty before we rerun the styler. Otherwise * fonts returned by the cache will match the old -fontscale * and -fonttable options. */ HtmlFontCacheClear(pTree, 1); } if (mask & L_MASK) { /* This happens when the -forcewidth option is set. In this * case we need to rebuild the layout. */ HtmlCallbackLayout(pTree, pTree->pRoot); } if (rc != TCL_OK) { assert(!init); Tk_RestoreSavedOptions(&saved); } else if (!init) { Tk_FreeSavedOptions(&saved); } } return rc; #undef GEOMETRY_MASK #undef FT_MASK } /* *--------------------------------------------------------------------------- * * cgetCmd -- * * Standard Tk "cget" command for querying options. * * cget -OPTION * * Results: * None. * * Side effects: * None. * *--------------------------------------------------------------------------- */ static int cgetCmd(clientData, interp, objc, objv) ClientData clientData; /* The HTML widget */ Tcl_Interp *interp; /* The interpreter */ int objc; /* Number of arguments */ Tcl_Obj *const *objv; /* List of all arguments */ { HtmlTree *pTree = (HtmlTree *)clientData; Tcl_Obj *pRet; Tk_OptionTable otab = pTree->optionTable; Tk_Window win = pTree->tkwin; char *pOptions = (char *)&pTree->options; assert(otab); if (objc != 3) { Tcl_WrongNumArgs(interp, 2, objv, "-OPTION"); return TCL_ERROR; } pRet = Tk_GetOptionValue(interp, pOptions, otab, objv[2], win); if( pRet ) { Tcl_SetObjResult(interp, pRet); } else { char * zOpt = Tcl_GetString(objv[2]); Tcl_AppendResult( interp, "unknown option \"", zOpt, "\"", 0); return TCL_ERROR; } return TCL_OK; } /* *--------------------------------------------------------------------------- * * resetCmd -- * * widget reset * * Reset the widget so that no document or stylesheet is loaded. * * Results: * None. * * Side effects: * None. * *--------------------------------------------------------------------------- */ static int resetCmd(clientData, interp, objc, objv) ClientData clientData; /* The HTML widget */ Tcl_Interp *interp; /* The interpreter */ int objc; /* Number of arguments */ Tcl_Obj *const *objv; /* List of all arguments */ { HtmlTree *pTree = (HtmlTree *)clientData; Tk_Window win = pTree->tkwin; HtmlTreeClear(pTree); HtmlImageServerDoGC(pTree); if (pTree->options.imagecache) { HtmlImageServerSuspendGC(pTree); } assert(HtmlImageServerCount(pTree) == 0); HtmlCallbackScrollY(pTree, 0); HtmlCallbackScrollX(pTree, 0); HtmlCallbackDamage(pTree, 0, 0, Tk_Width(win), Tk_Height(win)); doLoadDefaultStyle(pTree); pTree->isParseFinished = 0; pTree->isSequenceOk = 1; if (pTree->eWriteState == HTML_WRITE_WAIT || pTree->eWriteState == HTML_WRITE_NONE ) { pTree->eWriteState = HTML_WRITE_NONE; } else { pTree->eWriteState = HTML_WRITE_INHANDLERRESET; } return TCL_OK; } /* *--------------------------------------------------------------------------- * * relayoutCmd -- * * $html relayout ?-layout|-style? ?NODE? * * * Results: * None. * * Side effects: * None. * *--------------------------------------------------------------------------- */ static int relayoutCmd(clientData, interp, objc, objv) ClientData clientData; /* The HTML widget */ Tcl_Interp *interp; /* The interpreter */ int objc; /* Number of arguments */ Tcl_Obj *const *objv; /* List of all arguments */ { HtmlTree *pTree = (HtmlTree *)clientData; if (objc == 2) { HtmlCallbackRestyle(pTree, pTree->pRoot); HtmlWalkTree(pTree, pTree->pRoot, relayoutCb, 0); } else { char *zArg3 = ((objc >= 3) ? Tcl_GetString(objv[2]) : 0); char *zArg4 = ((objc >= 4) ? Tcl_GetString(objv[3]) : 0); HtmlNode *pNode; pNode = HtmlNodeGetPointer(pTree, zArg4 ? zArg4 : zArg3); if (!zArg4) { HtmlCallbackRestyle(pTree, pNode); HtmlCallbackLayout(pTree, pNode); } else if (0 == strcmp(zArg3, "-layout")) { HtmlCallbackLayout(pTree, pNode); } else if (0 == strcmp(zArg3, "-style")) { HtmlCallbackRestyle(pTree, pNode); } else { Tcl_AppendResult(interp, "Bad option \"", zArg3, "\": must be -layout or -style", 0 ); return TCL_ERROR; } } return TCL_OK; } /* *--------------------------------------------------------------------------- * * parseCmd -- * * $widget parse ?-final? HTML-TEXT * * Appends the given HTML text to the end of any HTML text that may have * been inserted by prior calls to this command. See Tkhtml man page for * further details. * * Results: * None. * * Side effects: * *--------------------------------------------------------------------------- */ static int parseCmd(clientData, interp, objc, objv) ClientData clientData; /* The HTML widget */ Tcl_Interp *interp; /* The interpreter */ int objc; /* Number of arguments */ Tcl_Obj *const *objv; /* List of all arguments */ { HtmlTree *pTree = (HtmlTree *)clientData; int isFinal; char *zHtml; int nHtml; int eWriteState; Tcl_Obj *aObj[2]; SwprocConf aConf[3] = { {SWPROC_SWITCH, "final", "0", "1"}, /* -final */ {SWPROC_ARG, 0, 0, 0}, /* HTML-TEXT */ {SWPROC_END, 0, 0, 0} }; if ( SwprocRt(interp, (objc - 2), &objv[2], aConf, aObj) || Tcl_GetBooleanFromObj(interp, aObj[0], &isFinal) ) { return TCL_ERROR; } /* zHtml = Tcl_GetByteArrayFromObj(aObj[1], &nHtml); */ zHtml = Tcl_GetStringFromObj(aObj[1], &nHtml); assert(Tcl_IsShared(aObj[1])); Tcl_DecrRefCount(aObj[0]); Tcl_DecrRefCount(aObj[1]); if (pTree->isParseFinished) { const char *zWidget = Tcl_GetString(objv[0]); Tcl_ResetResult(interp); Tcl_AppendResult(interp, "Cannot call [", zWidget, " parse]" "until after [", zWidget, "] reset", 0 ); return TCL_ERROR; } /* Add the new text to the internal cache of the document. */ eWriteState = pTree->eWriteState; HtmlTokenizerAppend(pTree, zHtml, nHtml, isFinal); assert(eWriteState == HTML_WRITE_NONE || pTree->eWriteState == eWriteState); if ( eWriteState != HTML_WRITE_INHANDLERRESET && pTree->eWriteState == HTML_WRITE_INHANDLERRESET ) { /* This case occurs when a node or script handler callback invokes * the [reset] method on this widget. The script-handler may then * go on to call [parse], which is the tricky bit... */ int nCount = 0; while (pTree->eWriteState == HTML_WRITE_INHANDLERRESET && nCount<100) { assert(pTree->nParsed == 0); pTree->eWriteState = HTML_WRITE_NONE; if (pTree->pDocument) { HtmlTokenizerAppend(pTree, "", 0, pTree->isParseFinished); } nCount++; } if (nCount==100){ Tcl_ResetResult(interp); Tcl_AppendResult(interp, "infinite loop: " "caused by node-handler calling [reset], [parse].", 0 ); return TCL_ERROR; } isFinal = pTree->isParseFinished; } if (isFinal) { HtmlInitTree(pTree); pTree->isParseFinished = 1; if (pTree->eWriteState == HTML_WRITE_NONE) { HtmlFinishNodeHandlers(pTree); } } HtmlCheckRestylePoint(pTree); return TCL_OK; } /* *--------------------------------------------------------------------------- * * preloadCmd -- * * $widget preload URI * * Preload the image located at the specified URI. * * Results: * None. * * Side effects: * *--------------------------------------------------------------------------- */ static int preloadCmd(clientData, interp, objc, objv) ClientData clientData; /* The HTML widget */ Tcl_Interp *interp; /* The interpreter */ int objc; /* Number of arguments */ Tcl_Obj *const *objv; /* List of all arguments */ { HtmlTree *pTree = (HtmlTree *)clientData; HtmlImage2 *pImg2 = 0; if (objc != 3) { Tcl_WrongNumArgs(interp, 2, objv, "URI"); return TCL_ERROR; } pImg2 = HtmlImageServerGet(pTree->pImageServer, Tcl_GetString(objv[2])); HtmlImageFree(pImg2); Tcl_ResetResult(interp); return TCL_OK; } /* *--------------------------------------------------------------------------- * * fragmentCmd -- * * $widget fragment HTML-TEXT * * Parse the supplied markup test and return a list of node handles. * * Results: * List of node-handles. * * Side effects: * *--------------------------------------------------------------------------- */ static int fragmentCmd(clientData, interp, objc, objv) ClientData clientData; /* The HTML widget */ Tcl_Interp *interp; /* The interpreter */ int objc; /* Number of arguments */ Tcl_Obj *const *objv; /* List of all arguments */ { HtmlTree *pTree = (HtmlTree *)clientData; if (objc != 3) { Tcl_WrongNumArgs(interp, 2, objv, "HTML-TEXT"); return TCL_ERROR; } HtmlParseFragment(pTree, Tcl_GetString(objv[2])); return TCL_OK; } /* *--------------------------------------------------------------------------- * * viewCommon -- * * Results: * None. * * Side effects: * *--------------------------------------------------------------------------- */ static int viewCommon(pTree, isXview, objc, objv) HtmlTree *pTree; int isXview; /* True for [xview], zero for [yview] */ int objc; Tcl_Obj * CONST objv[]; { Tcl_Interp *interp = pTree->interp; Tk_Window win = pTree->tkwin; int iUnitPixels; /* Value of -[xy]scrollincrement in pixels */ int iPagePixels; /* Width or height of the viewport */ int iMovePixels; /* Width or height of canvas */ int iOffScreen; /* Current scroll position */ double aRet[2]; Tcl_Obj *pRet; Tcl_Obj *pScrollCommand; if (isXview) { iPagePixels = Tk_Width(win); iUnitPixels = pTree->options.xscrollincrement; iMovePixels = pTree->canvas.right; iOffScreen = pTree->iScrollX; pScrollCommand = pTree->options.xscrollcommand; } else { iPagePixels = Tk_Height(win); iUnitPixels = pTree->options.yscrollincrement; iMovePixels = pTree->canvas.bottom; iOffScreen = pTree->iScrollY; pScrollCommand = pTree->options.yscrollcommand; } if (objc > 2) { double fraction; int count; int iNewVal = 0; /* New value of iScrollY or iScrollX */ HtmlCallbackForce(pTree); /* The [widget yview] command also supports "scroll-to-node" */ if (!isXview && objc == 3) { const char *zCmd = Tcl_GetString(objv[2]); HtmlNode *pNode = HtmlNodeGetPointer(pTree, zCmd); if (!pNode) { return TCL_ERROR; } iNewVal = HtmlWidgetNodeTop(pTree, pNode); iMovePixels = pTree->canvas.bottom; } else { int eType; /* One of the TK_SCROLL_ symbols */ eType = Tk_GetScrollInfoObj(interp, objc, objv, &fraction, &count); switch (eType) { case TK_SCROLL_MOVETO: iNewVal = (int)((double)iMovePixels * fraction); break; case TK_SCROLL_PAGES: iNewVal = iOffScreen + ((count * iPagePixels) * 0.9); break; case TK_SCROLL_UNITS: iNewVal = iOffScreen + (count * iUnitPixels); break; case TK_SCROLL_ERROR: return TCL_ERROR; default: assert(!"Not possible"); } } /* Clip the new scrolling value for the window size */ iNewVal = MIN(iNewVal, iMovePixels - iPagePixels); iNewVal = MAX(iNewVal, 0); if (isXview) { HtmlCallbackScrollX(pTree, iNewVal); } else { HtmlCallbackScrollY(pTree, iNewVal); } } /* Construct the Tcl result for this command. */ if (iMovePixels <= iPagePixels) { aRet[0] = 0.0; aRet[1] = 1.0; } else { assert(iMovePixels > 0); assert(iOffScreen >= 0); assert(iPagePixels >= 0); aRet[0] = (double)iOffScreen / (double)iMovePixels; aRet[1] = (double)(iOffScreen + iPagePixels) / (double)iMovePixels; aRet[1] = MIN(aRet[1], 1.0); } pRet = Tcl_NewObj(); Tcl_ListObjAppendElement(interp, pRet, Tcl_NewDoubleObj(aRet[0])); Tcl_ListObjAppendElement(interp, pRet, Tcl_NewDoubleObj(aRet[1])); Tcl_SetObjResult(interp, pRet); return TCL_OK; } /* *--------------------------------------------------------------------------- * * xviewCmd -- * yviewCmd -- * * Results: * None. * * Side effects: * *--------------------------------------------------------------------------- */ static int xviewCmd(clientData, interp, objc, objv) ClientData clientData; /* The HTML widget */ Tcl_Interp *interp; /* The interpreter */ int objc; /* Number of arguments */ Tcl_Obj *const *objv; /* List of all arguments */ { return viewCommon((HtmlTree *)clientData, 1, objc, objv); } static int yviewCmd(clientData, interp, objc, objv) ClientData clientData; /* The HTML widget */ Tcl_Interp *interp; /* The interpreter */ int objc; /* Number of arguments */ Tcl_Obj *const *objv; /* List of all arguments */ { return viewCommon((HtmlTree *)clientData, 0, objc, objv); } /* *--------------------------------------------------------------------------- * * writeCmd -- * * $widget write wait * $widget write text TEXT * $widget write continue * * Results: * None. * * Side effects: * None. * *--------------------------------------------------------------------------- */ static int writeCmd(clientData, interp, objc, objv) ClientData clientData; /* The HTML widget data structure */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument strings. */ { HtmlTree *pTree = (HtmlTree *)clientData; int eChoice; int rc = TCL_ERROR; enum SubOptType { OPT_WAIT, OPT_TEXT, OPT_CONTINUE }; struct SubOpt { char *zSubOption; /* Name of sub-command */ enum SubOptType eType; /* Corresponding OPT_XXX value */ int iExtraArgs; /* Number of args following sub-command */ char *zWrongNumArgsTail; /* 4th arg to Tcl_WrongNumArgs() */ } aSub[] = { {"wait", OPT_WAIT, 0, ""}, {"text", OPT_TEXT, 1, "TEXT"}, {"continue", OPT_CONTINUE, 0, ""}, {0, 0, 0} }; /* All commands must consist of at least three words - the widget name, * "write", and the sub-command name. Otherwise, it's a Tcl error. */ if (objc < 3) { Tcl_WrongNumArgs(interp, 2, objv, "OPTION"); return TCL_ERROR; } if (Tcl_GetIndexFromObjStruct( interp, objv[2], aSub, sizeof(struct SubOpt), "option", 0, &eChoice) ){ return TCL_ERROR; } if ((objc - 3) != aSub[eChoice].iExtraArgs) { Tcl_WrongNumArgs(interp, 3, objv, aSub[eChoice].zWrongNumArgsTail); return TCL_ERROR; } assert(pTree->interp == interp); switch (aSub[eChoice].eType) { case OPT_WAIT: rc = HtmlWriteWait(pTree); break; case OPT_TEXT: rc = HtmlWriteText(pTree, objv[3]); break; case OPT_CONTINUE: rc = HtmlWriteContinue(pTree); break; default: assert(!"Cannot happen"); } return rc; } /* *--------------------------------------------------------------------------- * * handlerCmd -- * * $widget handler [node|attribute|script|parse] TAG SCRIPT * * Results: * None. * * Side effects: * None. * *--------------------------------------------------------------------------- */ static int handlerCmd(clientData, interp, objc, objv) ClientData clientData; /* The HTML widget data structure */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument strings. */ { int tag; Tcl_Obj *pScript; Tcl_HashEntry *pEntry; Tcl_HashTable *pHash = 0; int newentry; HtmlTree *pTree = (HtmlTree *)clientData; char *zTag; enum HandlerType { HANDLER_ATTRIBUTE, HANDLER_NODE, HANDLER_SCRIPT, HANDLER_PARSE }; static const struct HandlerSubCommand { const char *zCommand; enum HandlerType eSymbol; } aSubCommand[] = { {"attribute", HANDLER_ATTRIBUTE}, {"node", HANDLER_NODE}, {"script", HANDLER_SCRIPT}, {"parse", HANDLER_PARSE}, {0, 0} }; int iChoice; if (objc!=5) { Tcl_WrongNumArgs(interp, 3, objv, "TAG SCRIPT"); return TCL_ERROR; } if (Tcl_GetIndexFromObjStruct(interp, objv[2], aSubCommand, sizeof(struct HandlerSubCommand), "option", 0, &iChoice) ){ return TCL_ERROR; } zTag = Tcl_GetString(objv[3]); tag = HtmlNameToType(0, zTag); if (tag==Html_Unknown) { Tcl_AppendResult(interp, "Unknown tag type: ", zTag, 0); return TCL_ERROR; } switch ((enum HandlerType)iChoice) { case HANDLER_ATTRIBUTE: pHash = &pTree->aAttributeHandler; break; case HANDLER_NODE: pHash = &pTree->aNodeHandler; break; case HANDLER_PARSE: pHash = &pTree->aParseHandler; break; case HANDLER_SCRIPT: pHash = &pTree->aScriptHandler; if (0 == zTag[0]) { tag = Html_Text; } else if ('/' == zTag[0]) { tag = HtmlNameToType(0, &zTag[1]); if (tag != Html_Unknown) tag = tag * -1; } break; } assert(pHash); pScript = objv[4]; if (Tcl_GetCharLength(pScript) == 0) { pEntry = Tcl_FindHashEntry(pHash, (char *)((size_t) tag)); if (pEntry) { Tcl_DeleteHashEntry(pEntry); } } else { pEntry = Tcl_CreateHashEntry(pHash,(char*)((size_t) tag),&newentry); if (!newentry) { Tcl_Obj *pOld = (Tcl_Obj *)Tcl_GetHashValue(pEntry); Tcl_DecrRefCount(pOld); } Tcl_IncrRefCount(pScript); Tcl_SetHashValue(pEntry, (ClientData)pScript); } return TCL_OK; } /* *--------------------------------------------------------------------------- * * styleCmd -- * * $widget style ?options? HTML-TEXT * * -importcmd IMPORT-CMD * -id ID * -urlcmd URL-CMD * * Results: * Tcl result (i.e. TCL_OK, TCL_ERROR). * * Side effects: * *--------------------------------------------------------------------------- */ static int styleCmd(clientData, interp, objc, objv) ClientData clientData; /* The HTML widget data structure */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument strings. */ { SwprocConf aConf[5 + 1] = { {SWPROC_OPT, "id", "author", 0}, /* -id */ {SWPROC_OPT, "importcmd", 0, 0}, /* -importcmd */ {SWPROC_OPT, "urlcmd", 0, 0}, /* -urlcmd */ {SWPROC_OPT, "errorvar", 0, 0}, /* -errorvar */ {SWPROC_ARG, 0, 0, 0}, /* STYLE-SHEET-TEXT */ {SWPROC_END, 0, 0, 0} }; Tcl_Obj *apObj[5]; int rc = TCL_OK; int n; HtmlTree *pTree = (HtmlTree *)clientData; /* First assert() that the sizes of the aConf and apObj array match. Then * call SwprocRt() to parse the arguments. If the parse is successful then * apObj[] contains the following: * * apObj[0] -> Value passed to -id option (or default "author") * apObj[1] -> Value passed to -importcmd option (or default "") * apObj[2] -> Value passed to -urlcmd option (or default "") * apObj[3] -> Variable to store error log in * apObj[4] -> Text of stylesheet to parse * * Pass these on to the HtmlStyleParse() command to actually parse the * stylesheet. */ assert(sizeof(apObj)/sizeof(apObj[0])+1 == sizeof(aConf)/sizeof(aConf[0])); if (TCL_OK != SwprocRt(interp, objc - 2, &objv[2], aConf, apObj)) { return TCL_ERROR; } Tcl_GetStringFromObj(apObj[4], &n); if (n > 0) { rc = HtmlStyleParse(pTree,apObj[4],apObj[0],apObj[1],apObj[2],apObj[3]); } else { /* For a zero length stylesheet, we don't need to run the parser. * But we do need to set the error-log variable to an empty string * if one was specified. */ if (apObj[3]) { Tcl_ObjSetVar2(interp, apObj[3], 0, Tcl_NewObj(), 0); } } /* Clean up object references created by SwprocRt() */ SwprocCleanup(apObj, sizeof(apObj)/sizeof(Tcl_Obj *)); if (rc == TCL_OK) { HtmlCallbackRestyle(pTree, pTree->pRoot); } return rc; } static int tagAddCmd(clientData, interp, objc, objv) ClientData clientData; /* The HTML widget data structure */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument strings. */ { return HtmlTagAddRemoveCmd(clientData, interp, objc, objv, HTML_TAG_ADD); } static int tagRemoveCmd(clientData, interp, objc, objv) ClientData clientData; /* The HTML widget data structure */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument strings. */ { return HtmlTagAddRemoveCmd(clientData, interp, objc, objv, HTML_TAG_REMOVE); } static int tagCfgCmd(clientData, interp, objc, objv) ClientData clientData; /* The HTML widget data structure */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument strings. */ { return HtmlTagConfigureCmd(clientData, interp, objc, objv); } static int tagDeleteCmd(clientData, interp, objc, objv) ClientData clientData; /* The HTML widget data structure */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument strings. */ { return HtmlTagDeleteCmd(clientData, interp, objc, objv); } static int callSubCmd(aSub, iIdx, clientData, interp, objc, objv) SubCmd *aSub; int iIdx; ClientData clientData; /* The HTML widget data structure */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument strings. */ { int iChoice; assert(objc >= iIdx); if (iIdx == objc) { Tcl_WrongNumArgs(interp, objc, objv, "SUB-COMMAND"); return TCL_ERROR; } if (Tcl_GetIndexFromObjStruct(interp, objv[iIdx], aSub, sizeof(SubCmd), "sub-command", 0, &iChoice) ){ return TCL_ERROR; } return aSub[iChoice].xFunc(clientData, interp, objc, objv); } static int tagCmd(clientData, interp, objc, objv) ClientData clientData; /* The HTML widget data structure */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument strings. */ { SubCmd aSub[] = { { "add" , tagAddCmd }, { "remove" , tagRemoveCmd }, { "configure", tagCfgCmd }, { "delete" , tagDeleteCmd }, { 0, 0 } }; return callSubCmd(aSub, 2, clientData, interp, objc, objv); } static int textTextCmd(clientData, interp, objc, objv) ClientData clientData; /* The HTML widget data structure */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument strings. */ { return HtmlTextTextCmd(clientData, interp, objc, objv); } static int textIndexCmd(clientData, interp, objc, objv) ClientData clientData; /* The HTML widget data structure */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument strings. */ { return HtmlTextIndexCmd(clientData, interp, objc, objv); } static int textBboxCmd(clientData, interp, objc, objv) ClientData clientData; /* The HTML widget data structure */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument strings. */ { return HtmlTextBboxCmd(clientData, interp, objc, objv); } static int textOffsetCmd(clientData, interp, objc, objv) ClientData clientData; /* The HTML widget data structure */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument strings. */ { return HtmlTextOffsetCmd(clientData, interp, objc, objv); } static int textCmd(clientData, interp, objc, objv) ClientData clientData; /* The HTML widget data structure */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument strings. */ { SubCmd aSub[] = { { "text", textTextCmd }, { "index", textIndexCmd }, { "bbox", textBboxCmd }, { "offset", textOffsetCmd }, { 0 , 0 } }; return callSubCmd(aSub, 2, clientData, interp, objc, objv); } static int forceCmd(clientData, interp, objc, objv) ClientData clientData; /* The HTML widget data structure */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument strings. */ { HtmlCallbackForce((HtmlTree *)clientData); return TCL_OK; } static int delayCmd(clientData, interp, objc, objv) ClientData clientData; /* The HTML widget data structure */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument strings. */ { HtmlTree *pTree = (HtmlTree *)clientData; int iMilli; Tcl_TimerToken t; if (objc != 3) { Tcl_WrongNumArgs(interp, 2, objv, "MILLI-SECONDS"); return TCL_ERROR; } if (TCL_OK != Tcl_GetIntFromObj(interp, objv[2], &iMilli)) { return TCL_ERROR; } if (pTree->delayToken) { Tcl_DeleteTimerHandler(pTree->delayToken); } pTree->delayToken = 0; if (iMilli > 0) { t = Tcl_CreateTimerHandler(iMilli, delayCallbackHandler, clientData); pTree->delayToken = t; } else if (pTree->cb.flags) { Tcl_DoWhenIdle(callbackHandler, clientData); } return TCL_OK; } /* *--------------------------------------------------------------------------- * * imageCmd -- * nodeCmd -- * primitivesCmd -- * * New versions of gcc don't allow pointers to non-local functions to * be used as constant initializers (which we need to do in the * aSubcommand[] array inside widgetCmd(). So the following * functions are wrappers around Tcl_ObjCmdProc functions implemented * in other files. * * Results: * Tcl result (i.e. TCL_OK, TCL_ERROR). * * Side effects: * Whatever the called function does. * *--------------------------------------------------------------------------- */ static int imageCmd(clientData, interp, objc, objv) ClientData clientData; /* The HTML widget data structure */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument strings. */ { return HtmlLayoutImage(clientData, interp, objc, objv); } static int nodeCmd(clientData, interp, objc, objv) ClientData clientData; /* The HTML widget data structure */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument strings. */ { HtmlInitTree((HtmlTree *)clientData); return HtmlLayoutNode(clientData, interp, objc, objv); } static int primitivesCmd(clientData, interp, objc, objv) ClientData clientData; /* The HTML widget data structure */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument strings. */ { return HtmlLayoutPrimitives(clientData, interp, objc, objv); } static int imagesCmd(clientData, interp, objc, objv) ClientData clientData; /* The HTML widget data structure */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument strings. */ { return HtmlImageServerReport(clientData, interp, objc, objv); } static int searchCmd(clientData, interp, objc, objv) ClientData clientData; /* The HTML widget data structure */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument strings. */ { return HtmlCssSearch(clientData, interp, objc, objv); } static int styleconfigCmd(clientData, interp, objc, objv) ClientData clientData; /* The HTML widget data structure */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument strings. */ { return HtmlCssStyleConfigDump(clientData, interp, objc, objv); } static int stylereportCmd(clientData, interp, objc, objv) ClientData clientData; /* The HTML widget data structure */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument strings. */ { return HtmlCssStyleReport(clientData, interp, objc, objv); } /* *--------------------------------------------------------------------------- * * bboxCmd -- * * html bbox ?node-handle? * * Results: * Tcl result (i.e. TCL_OK, TCL_ERROR). * * Side effects: * *--------------------------------------------------------------------------- */ static int bboxCmd(clientData, interp, objc, objv) ClientData clientData; /* The HTML widget data structure */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument strings. */ { return HtmlWidgetBboxCmd(clientData, interp, objc, objv); #if 0 HtmlNode *pNode; int x, y, w, h; HtmlTree *pTree = (HtmlTree *)clientData; Tcl_Obj *pRet = Tcl_NewObj(); if (objc != 2 && objc != 3) { Tcl_WrongNumArgs(interp, 2, objv, "?NODE-HANDLE?"); return TCL_ERROR; } if (objc == 3) { pNode = HtmlNodeGetPointer(pTree, Tcl_GetString(objv[2])); if (!pNode) return TCL_ERROR; } else { pNode = pTree->pRoot; } HtmlWidgetNodeBox(pTree, pNode, &x, &y, &w, &h); if (w > 0 && h > 0) { Tcl_ListObjAppendElement(0, pRet, Tcl_NewIntObj(x)); Tcl_ListObjAppendElement(0, pRet, Tcl_NewIntObj(y)); Tcl_ListObjAppendElement(0, pRet, Tcl_NewIntObj(x + w)); Tcl_ListObjAppendElement(0, pRet, Tcl_NewIntObj(y + h)); } Tcl_SetObjResult(interp, pRet); return TCL_OK; #endif } /* *--------------------------------------------------------------------------- * * widgetCmd -- * * This is the C function invoked for a widget command. * * Results: * Tcl result. * * Side effects: * Whatever the command does. * *--------------------------------------------------------------------------- */ int widgetCmd(clientData, interp, objc, objv) ClientData clientData; /* The HTML widget data structure */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument strings. */ { /* The following array defines all the built-in widget commands. This * function just parses the first one or two arguments and vectors control * to one of the command service routines defined in the following array. */ SubCmd aSub[] = { {"bbox", bboxCmd}, {"cget", cgetCmd}, {"configure", configureCmd}, {"fragment", fragmentCmd}, {"handler", handlerCmd}, {"image", imageCmd}, {"node", nodeCmd}, {"parse", parseCmd}, {"preload", preloadCmd}, {"reset", resetCmd}, {"search", searchCmd}, {"style", styleCmd}, {"tag", tagCmd}, {"text", textCmd}, {"write", writeCmd}, {"xview", xviewCmd}, {"yview", yviewCmd}, /* The following are for debugging only. May change at any time. * They are not included in the documentation. Just don't touch Ok? :) */ {"_delay", delayCmd}, {"_force", forceCmd}, {"_images", imagesCmd}, {"_primitives", primitivesCmd}, {"_relayout", relayoutCmd}, {"_styleconfig", styleconfigCmd}, {"_stylereport", stylereportCmd}, #ifndef NDEBUG {"_hashstats", hashstatsCmd}, #endif { 0, 0} }; return callSubCmd(aSub, 1, clientData, interp, objc, objv); } /* *--------------------------------------------------------------------------- * * newWidget -- * * Create a new Html widget command: * * html PATH ?? * * Results: * None. * * Side effects: * None. * *--------------------------------------------------------------------------- */ static int newWidget(clientData, interp, objc, objv) ClientData clientData; /* The HTML widget data structure */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument strings. */ { HtmlTree *pTree; CONST char *zCmd; int rc; Tk_Window mainwin; /* Main window of application */ Tcl_HashKeyType *pType; if (objc<2) { Tcl_WrongNumArgs(interp, 1, objv, "WINDOW-PATH ?OPTIONS?"); return TCL_ERROR; } zCmd = Tcl_GetString(objv[1]); pTree = HtmlNew(HtmlTree); /* Create the Tk window. */ mainwin = Tk_MainWindow(interp); pTree->tkwin = Tk_CreateWindowFromPath(interp, mainwin, zCmd, NULL); if (!pTree->tkwin) { HtmlFree(pTree); return TCL_ERROR; } Tk_SetClass(pTree->tkwin, "Html"); pTree->docwin = Tk_CreateWindow(interp, pTree->tkwin, "document", NULL); if (!pTree->docwin) { Tk_DestroyWindow(pTree->tkwin); HtmlFree(pTree); return TCL_ERROR; } Tk_MakeWindowExist(pTree->docwin); Tk_ResizeWindow(pTree->docwin, 30000, 30000); Tk_MapWindow(pTree->docwin); pTree->interp = interp; Tcl_InitHashTable(&pTree->aParseHandler, TCL_ONE_WORD_KEYS); Tcl_InitHashTable(&pTree->aScriptHandler, TCL_ONE_WORD_KEYS); Tcl_InitHashTable(&pTree->aNodeHandler, TCL_ONE_WORD_KEYS); Tcl_InitHashTable(&pTree->aAttributeHandler, TCL_ONE_WORD_KEYS); Tcl_InitHashTable(&pTree->aOrphan, TCL_ONE_WORD_KEYS); Tcl_InitHashTable(&pTree->aTag, TCL_STRING_KEYS); pTree->cmd = Tcl_CreateObjCommand(interp,zCmd,widgetCmd,pTree,widgetCmdDel); pType = HtmlCaseInsenstiveHashType(); Tcl_InitCustomHashTable(&pTree->aAtom, TCL_CUSTOM_TYPE_KEYS, pType); HtmlCssSearchInit(pTree); /* Initialise the hash tables used by styler code */ HtmlComputedValuesSetupTables(pTree); /* Set up an event handler for the widget window */ Tk_CreateEventHandler(pTree->tkwin, ExposureMask|StructureNotifyMask|VisibilityChangeMask, eventHandler, (ClientData)pTree ); Tk_CreateEventHandler(pTree->docwin, ExposureMask|ButtonMotionMask|ButtonPressMask| ButtonReleaseMask|PointerMotionMask|PointerMotionHintMask| Button1MotionMask|Button2MotionMask|Button3MotionMask| Button4MotionMask|Button5MotionMask|ButtonMotionMask, docwinEventHandler, (ClientData)pTree ); /* Create the image-server */ HtmlImageServerInit(pTree); /* TODO: Handle the case where configureCmd() returns an error. */ rc = configureCmd(pTree, interp, objc, objv); if (rc != TCL_OK) { Tk_DestroyWindow(pTree->tkwin); return TCL_ERROR; } assert(!pTree->options.logcmd); assert(!pTree->options.timercmd); /* Load the default style-sheet, ready for the first document. */ doLoadDefaultStyle(pTree); pTree->isSequenceOk = 1; #ifdef TKHTML_ENABLE_PROFILE if (1) { Tcl_CmdInfo cmdinfo; Tcl_GetCommandInfo(interp, "::tkhtml::instrument", &cmdinfo); pTree->pInstrumentData = cmdinfo.objClientData; } #endif /* Return the name of the widget just created. */ Tcl_SetObjResult(interp, objv[1]); return TCL_OK; } /* *--------------------------------------------------------------------------- * * htmlstyleCmd -- * * ::tkhtml::htmlstyle ?-quirks? * * Results: * Built-in html style-sheet, including quirks if the -quirks option * was specified. * * Side effects: * None. * *--------------------------------------------------------------------------- */ static int htmlstyleCmd(clientData, interp, objc, objv) ClientData clientData; /* The HTML widget data structure */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument strings. */ { if (objc > 1 && objc != 2 && strcmp(Tcl_GetString(objv[1]), "-quirks")) { Tcl_WrongNumArgs(interp, 1, objv, "?-quirks?"); return TCL_ERROR; } Tcl_SetResult(interp, HTML_DEFAULT_CSS, TCL_STATIC); if (objc == 2) { Tcl_AppendResult(interp, HTML_DEFAULT_QUIRKS, 0); } return TCL_OK; } /* *--------------------------------------------------------------------------- * * htmlVersionCmd -- * * ::tkhtml::version * * Results: * Returns a string containing the versions of the *.c files used * to build the library * * Side effects: * None. * *--------------------------------------------------------------------------- */ static int htmlVersionCmd(clientData, interp, objc, objv) ClientData clientData; /* The HTML widget data structure */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument strings. */ { if (objc > 1) { Tcl_WrongNumArgs(interp, 1, objv, ""); return TCL_ERROR; } Tcl_SetResult(interp, HTML_SOURCE_FILES, TCL_STATIC); return TCL_OK; } static int htmlDecodeCmd(clientData, interp, objc, objv) ClientData clientData; /* The HTML widget data structure */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument strings. */ { return HtmlDecode(clientData, interp, objc, objv); } static int htmlEncodeCmd(clientData, interp, objc, objv) ClientData clientData; /* The HTML widget data structure */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument strings. */ { return HtmlEncode(clientData, interp, objc, objv); } static int htmlEscapeCmd(clientData, interp, objc, objv) ClientData clientData; /* The HTML widget data structure */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument strings. */ { return HtmlEscapeUriComponent(clientData, interp, objc, objv); } static int htmlUriCmd(clientData, interp, objc, objv) ClientData clientData; /* The HTML widget data structure */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument strings. */ { return HtmlCreateUri(clientData, interp, objc, objv); } /* *--------------------------------------------------------------------------- * * htmlByteOffsetCmd -- * htmlCharOffsetCmd -- * * ::tkhtml::charoffset STRING BYTE-OFFSET * ::tkhtml::byteoffset STRING CHAR-OFFSET * * Results: * * Side effects: * None. * *--------------------------------------------------------------------------- */ static int htmlByteOffsetCmd(clientData, interp, objc, objv) ClientData clientData; Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument strings. */ { int iCharOffset; int iRet; char *zArg; if (objc != 3) { Tcl_WrongNumArgs(interp, 1, objv, "STRING CHAR-OFFSET"); return TCL_ERROR; } if (Tcl_GetIntFromObj(interp, objv[2], &iCharOffset)) return TCL_ERROR; zArg = Tcl_GetString(objv[1]); iRet = (Tcl_UtfAtIndex(zArg, iCharOffset) - zArg); Tcl_SetObjResult(interp, Tcl_NewIntObj(iRet)); return TCL_OK; } static int htmlCharOffsetCmd(clientData, interp, objc, objv) ClientData clientData; Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument strings. */ { int iByteOffset; int iRet; char *zArg; if (objc != 3) { Tcl_WrongNumArgs(interp, 1, objv, "STRING BYTE-OFFSET"); return TCL_ERROR; } if (Tcl_GetIntFromObj(interp, objv[2], &iByteOffset)) return TCL_ERROR; zArg = Tcl_GetString(objv[1]); iRet = Tcl_NumUtfChars(zArg, iByteOffset); Tcl_SetObjResult(interp, Tcl_NewIntObj(iRet)); return TCL_OK; } /* * Define the DLL_EXPORT macro, which must be set to something or other in * order to export the Tkhtml_Init and Tkhtml_SafeInit symbols from a win32 * DLL file. I don't entirely understand the ins and outs of this, the * block below was copied verbatim from another program. */ #if INTERFACE #define DLL_EXPORT #endif #if defined(USE_TCL_STUBS) && defined(__WIN32__) # undef DLL_EXPORT # define DLL_EXPORT __declspec(dllexport) #endif #ifndef DLL_EXPORT #define DLL_EXPORT #endif /* *--------------------------------------------------------------------------- * * Tkhtml_Init -- * * Load the package into an interpreter. * * Results: * Tcl result. * * Side effects: * Loads the tkhtml package into interpreter interp. * *--------------------------------------------------------------------------- */ DLL_EXPORT int Tkhtml_Init(interp) Tcl_Interp *interp; { int rc; /* Require stubs libraries version 8.4 or greater. */ #ifdef USE_TCL_STUBS if (Tcl_InitStubs(interp, "8.4", 0) == 0) { return TCL_ERROR; } if (Tk_InitStubs(interp, "8.4", 0) == 0) { return TCL_ERROR; } #endif if (0 == Tcl_PkgRequire(interp, "Tk", "8.4", 0)) { return TCL_ERROR; } Tcl_PkgProvide(interp, "Tkhtml", "3.0"); Tcl_CreateObjCommand(interp, "html", newWidget, 0, 0); Tcl_CreateObjCommand(interp, "::tkhtml::htmlstyle", htmlstyleCmd, 0, 0); Tcl_CreateObjCommand(interp, "::tkhtml::version", htmlVersionCmd, 0, 0); Tcl_CreateObjCommand(interp, "::tkhtml::decode", htmlDecodeCmd, 0, 0); Tcl_CreateObjCommand(interp, "::tkhtml::encode", htmlEncodeCmd, 0, 0); Tcl_CreateObjCommand(interp, "::tkhtml::escape_uri", htmlEscapeCmd, 0, 0); Tcl_CreateObjCommand(interp, "::tkhtml::uri", htmlUriCmd, 0, 0); Tcl_CreateObjCommand(interp, "::tkhtml::byteoffset", htmlByteOffsetCmd,0,0); Tcl_CreateObjCommand(interp, "::tkhtml::charoffset", htmlCharOffsetCmd,0,0); #ifndef NDEBUG Tcl_CreateObjCommand(interp, "::tkhtml::htmlalloc", allocCmd, 0, 0); Tcl_CreateObjCommand(interp, "::tkhtml::heapdebug", heapdebugCmd, 0, 0); #endif SwprocInit(interp); HtmlInstrumentInit(interp); rc = Tcl_EvalEx(interp, HTML_DEFAULT_TCL, -1, TCL_EVAL_GLOBAL); assert(rc == TCL_OK); return TCL_OK; } /* *--------------------------------------------------------------------------- * * Tkhtml_SafeInit -- * * Load the package into a safe interpreter. * * Note that this function has to be below the Tkhtml_Init() * implementation. Otherwise the Tkhtml_Init() invocation in this * function counts as an implicit declaration which causes problems for * MSVC somewhere on down the line. * * Results: * Tcl result. * * Side effects: * Loads the tkhtml package into interpreter interp. * *--------------------------------------------------------------------------- */ DLL_EXPORT int Tkhtml_SafeInit(interp) Tcl_Interp *interp; { return Tkhtml_Init(interp); } tkHTML-4ee7aaa953d6cb59/src/htmltest.c000064400000000000000000000052671151224263100167260ustar00nobodynobodystatic char const rcsid[] = "@(#) $Id: htmltest.c,v 1.15 2005/03/23 01:36:54 danielk1977 Exp $"; /* ** This file contains the TestPoint routines used for profiling ** and coverage analysis of the code. ** ** This source code is released into the public domain by the author, ** D. Richard Hipp, on 2002 December 17. Instead of a license, here ** is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. */ /* ** A macro named "TestPoint" is defined which increments a counter ** whenever it is encountered. This is very efficient, and should ** not impact performance of the system. For delivery, the macro ** can be nulled out by recompiling without the COVERAGE_TEST macro ** defined. ** ** See also the "renumber.c" program which can be used ** to assign unique numbers to all of the TestPoint(0) macros. */ #include "tcl.h" #include "html.h" #if INTERFACE #endif /* INTERFACE */ /* ** The following global array keeps track of the number of visits to ** each testpoint. The size of the array must be set manually to the ** be at least one greater than the largest TestPoint number. */ #if defined(COVERAGE_TEST) int HtmlTPArray[2000]; #endif /* Needed by the EslTestPointDump routine */ #include /* ** Recursion depth */ #if defined(DEBUG) int HtmlDepth = 0; #endif #if INTERFACE #if defined(DEBUG) #define HtmlPush HtmlDepth+=2 #define HtmlPop HtmlDepth-=2 #else #define HtmlPush #define HtmlPop #endif #endif /* This function is called to print the values of all elements of the ** TP_Array to the given file. Values are printed in decimal, one per line. */ void HtmlTestPointDump(filename) char *filename; { #if defined(COVERAGE_TEST) FILE *fp; fp = fopen(filename, "a"); if (fp) { int i; for (i = 0; i < sizeof(HtmlTPArray) / sizeof(HtmlTPArray[0]); i++) { if (HtmlTPArray[i] > 0) { fprintf(fp, "%d %d\n", i, HtmlTPArray[i]); } } } fclose(fp); #endif } /* This function reports an error to stderr when code that is marked ** UNTESTED gets executed. */ void HtmlTPUntested(zFile, line) const char *zFile; int line; { #ifndef USE_TCL_STUBS fprintf(stderr, "Untested HTML Widget code executed in file %s line %d\n", zFile, line); #endif } /* This function reports an error to stderr when safety code that should ** never execute is called. */ void HtmlTPCantHappen(zFile, line) const char *zFile; int line; { #ifndef USE_TCL_STUBS fprintf(stderr, "Unplanned behavior in the HTML Widget in file %s line %d\n", zFile, line); #endif } tkHTML-4ee7aaa953d6cb59/src/htmltext.c000064400000000000000000002225621151224263100167320ustar00nobodynobody/* *-------------------------------------------------------------------------- * Copyright (c) 2006 Dan Kennedy. * All rights reserved. * * This Open Source project was made possible through the financial support * of Eolas Technologies Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of Eolas Technologies Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include "html.h" #define ISNEWLINE(x) ((x) == '\n' || (x) == '\r') #define ISTAB(x) ((x) == '\t') #define ISSPACE(x) isspace((unsigned char)(x)) /* * This file implements the experimental [tag] widget method. The * following summarizes the interface supported: * * html tag add TAGNAME FROM-NODE FROM-INDEX TO-NODE TO-INDEX * html tag remove TAGNAME FROM-NODE FROM-INDEX TO-NODE TO-INDEX * html tag delete TAGNAME * html tag configure TAGNAME ?-fg COLOR? ?-bg COLOR? * * This file exports the following functions: * * HtmlTranslateEscapes() * Translates Html escapes (i.e. " "). * * HtmlTagAddRemoveCmd() * Implementation of [pathName tag add] and [pathName tag remove] * * HtmlTagDeleteCmd() * Implementation of [pathName tag delete] * * HtmlTagConfigureCmd() * Implementation of [pathName tag configured] * * HtmlTagCleanupNode() * HtmlTagCleanupTree() * Respectively called when an HtmlNode or HtmlTree structure is being * deallocated to free outstanding tag related stuff. * * * Also: * * HtmlTextTextCmd() * HtmlTextBboxCmd() * HtmlTextOffsetCmd() * HtmlTextIndexCmd() */ /****************** Begin Escape Sequence Translator *************/ /* ** The next section of code implements routines used to translate ** the '&' escape sequences of SGML to individual characters. ** Examples: ** ** & & ** < < ** > > **   nonbreakable space */ /* Each escape sequence is recorded as an instance of the following ** structure */ struct sgEsc { char *zName; /* The name of this escape sequence. ex: "amp" */ char value[8]; /* The value for this sequence. ex: "&" */ struct sgEsc *pNext; /* Next sequence with the same hash on zName */ }; /* The following is a table of all escape sequences. Add new sequences ** by adding entries to this table. */ static struct sgEsc esc_sequences[] = { {"nbsp", "\xC2\xA0", 0}, /* Unicode code-point 160 */ {"iexcl", "\xC2\xA1", 0}, /* Unicode code-point 161 */ {"cent", "\xC2\xA2", 0}, /* Unicode code-point 162 */ {"pound", "\xC2\xA3", 0}, /* Unicode code-point 163 */ {"curren", "\xC2\xA4", 0}, /* Unicode code-point 164 */ {"yen", "\xC2\xA5", 0}, /* Unicode code-point 165 */ {"brvbar", "\xC2\xA6", 0}, /* Unicode code-point 166 */ {"sect", "\xC2\xA7", 0}, /* Unicode code-point 167 */ {"uml", "\xC2\xA8", 0}, /* Unicode code-point 168 */ {"copy", "\xC2\xA9", 0}, /* Unicode code-point 169 */ {"ordf", "\xC2\xAA", 0}, /* Unicode code-point 170 */ {"laquo", "\xC2\xAB", 0}, /* Unicode code-point 171 */ {"not", "\xC2\xAC", 0}, /* Unicode code-point 172 */ {"shy", "\xC2\xAD", 0}, /* Unicode code-point 173 */ {"reg", "\xC2\xAE", 0}, /* Unicode code-point 174 */ {"macr", "\xC2\xAF", 0}, /* Unicode code-point 175 */ {"deg", "\xC2\xB0", 0}, /* Unicode code-point 176 */ {"plusmn", "\xC2\xB1", 0}, /* Unicode code-point 177 */ {"sup2", "\xC2\xB2", 0}, /* Unicode code-point 178 */ {"sup3", "\xC2\xB3", 0}, /* Unicode code-point 179 */ {"acute", "\xC2\xB4", 0}, /* Unicode code-point 180 */ {"micro", "\xC2\xB5", 0}, /* Unicode code-point 181 */ {"para", "\xC2\xB6", 0}, /* Unicode code-point 182 */ {"middot", "\xC2\xB7", 0}, /* Unicode code-point 183 */ {"cedil", "\xC2\xB8", 0}, /* Unicode code-point 184 */ {"sup1", "\xC2\xB9", 0}, /* Unicode code-point 185 */ {"ordm", "\xC2\xBA", 0}, /* Unicode code-point 186 */ {"raquo", "\xC2\xBB", 0}, /* Unicode code-point 187 */ {"frac14", "\xC2\xBC", 0}, /* Unicode code-point 188 */ {"frac12", "\xC2\xBD", 0}, /* Unicode code-point 189 */ {"frac34", "\xC2\xBE", 0}, /* Unicode code-point 190 */ {"iquest", "\xC2\xBF", 0}, /* Unicode code-point 191 */ {"Agrave", "\xC3\x80", 0}, /* Unicode code-point 192 */ {"Aacute", "\xC3\x81", 0}, /* Unicode code-point 193 */ {"Acirc", "\xC3\x82", 0}, /* Unicode code-point 194 */ {"Atilde", "\xC3\x83", 0}, /* Unicode code-point 195 */ {"Auml", "\xC3\x84", 0}, /* Unicode code-point 196 */ {"Aring", "\xC3\x85", 0}, /* Unicode code-point 197 */ {"AElig", "\xC3\x86", 0}, /* Unicode code-point 198 */ {"Ccedil", "\xC3\x87", 0}, /* Unicode code-point 199 */ {"Egrave", "\xC3\x88", 0}, /* Unicode code-point 200 */ {"Eacute", "\xC3\x89", 0}, /* Unicode code-point 201 */ {"Ecirc", "\xC3\x8A", 0}, /* Unicode code-point 202 */ {"Euml", "\xC3\x8B", 0}, /* Unicode code-point 203 */ {"Igrave", "\xC3\x8C", 0}, /* Unicode code-point 204 */ {"Iacute", "\xC3\x8D", 0}, /* Unicode code-point 205 */ {"Icirc", "\xC3\x8E", 0}, /* Unicode code-point 206 */ {"Iuml", "\xC3\x8F", 0}, /* Unicode code-point 207 */ {"ETH", "\xC3\x90", 0}, /* Unicode code-point 208 */ {"Ntilde", "\xC3\x91", 0}, /* Unicode code-point 209 */ {"Ograve", "\xC3\x92", 0}, /* Unicode code-point 210 */ {"Oacute", "\xC3\x93", 0}, /* Unicode code-point 211 */ {"Ocirc", "\xC3\x94", 0}, /* Unicode code-point 212 */ {"Otilde", "\xC3\x95", 0}, /* Unicode code-point 213 */ {"Ouml", "\xC3\x96", 0}, /* Unicode code-point 214 */ {"times", "\xC3\x97", 0}, /* Unicode code-point 215 */ {"Oslash", "\xC3\x98", 0}, /* Unicode code-point 216 */ {"Ugrave", "\xC3\x99", 0}, /* Unicode code-point 217 */ {"Uacute", "\xC3\x9A", 0}, /* Unicode code-point 218 */ {"Ucirc", "\xC3\x9B", 0}, /* Unicode code-point 219 */ {"Uuml", "\xC3\x9C", 0}, /* Unicode code-point 220 */ {"Yacute", "\xC3\x9D", 0}, /* Unicode code-point 221 */ {"THORN", "\xC3\x9E", 0}, /* Unicode code-point 222 */ {"szlig", "\xC3\x9F", 0}, /* Unicode code-point 223 */ {"agrave", "\xC3\xA0", 0}, /* Unicode code-point 224 */ {"aacute", "\xC3\xA1", 0}, /* Unicode code-point 225 */ {"acirc", "\xC3\xA2", 0}, /* Unicode code-point 226 */ {"atilde", "\xC3\xA3", 0}, /* Unicode code-point 227 */ {"auml", "\xC3\xA4", 0}, /* Unicode code-point 228 */ {"aring", "\xC3\xA5", 0}, /* Unicode code-point 229 */ {"aelig", "\xC3\xA6", 0}, /* Unicode code-point 230 */ {"ccedil", "\xC3\xA7", 0}, /* Unicode code-point 231 */ {"egrave", "\xC3\xA8", 0}, /* Unicode code-point 232 */ {"eacute", "\xC3\xA9", 0}, /* Unicode code-point 233 */ {"ecirc", "\xC3\xAA", 0}, /* Unicode code-point 234 */ {"euml", "\xC3\xAB", 0}, /* Unicode code-point 235 */ {"igrave", "\xC3\xAC", 0}, /* Unicode code-point 236 */ {"iacute", "\xC3\xAD", 0}, /* Unicode code-point 237 */ {"icirc", "\xC3\xAE", 0}, /* Unicode code-point 238 */ {"iuml", "\xC3\xAF", 0}, /* Unicode code-point 239 */ {"eth", "\xC3\xB0", 0}, /* Unicode code-point 240 */ {"ntilde", "\xC3\xB1", 0}, /* Unicode code-point 241 */ {"ograve", "\xC3\xB2", 0}, /* Unicode code-point 242 */ {"oacute", "\xC3\xB3", 0}, /* Unicode code-point 243 */ {"ocirc", "\xC3\xB4", 0}, /* Unicode code-point 244 */ {"otilde", "\xC3\xB5", 0}, /* Unicode code-point 245 */ {"ouml", "\xC3\xB6", 0}, /* Unicode code-point 246 */ {"divide", "\xC3\xB7", 0}, /* Unicode code-point 247 */ {"oslash", "\xC3\xB8", 0}, /* Unicode code-point 248 */ {"ugrave", "\xC3\xB9", 0}, /* Unicode code-point 249 */ {"uacute", "\xC3\xBA", 0}, /* Unicode code-point 250 */ {"ucirc", "\xC3\xBB", 0}, /* Unicode code-point 251 */ {"uuml", "\xC3\xBC", 0}, /* Unicode code-point 252 */ {"yacute", "\xC3\xBD", 0}, /* Unicode code-point 253 */ {"thorn", "\xC3\xBE", 0}, /* Unicode code-point 254 */ {"yuml", "\xC3\xBF", 0}, /* Unicode code-point 255 */ {"quot", "\x22", 0}, /* Unicode code-point 34 */ {"amp", "\x26", 0}, /* Unicode code-point 38 */ {"lt", "\x3C", 0}, /* Unicode code-point 60 */ {"gt", "\x3E", 0}, /* Unicode code-point 62 */ {"OElig", "\xC5\x92", 0}, /* Unicode code-point 338 */ {"oelig", "\xC5\x93", 0}, /* Unicode code-point 339 */ {"Scaron", "\xC5\xA0", 0}, /* Unicode code-point 352 */ {"scaron", "\xC5\xA1", 0}, /* Unicode code-point 353 */ {"Yuml", "\xC5\xB8", 0}, /* Unicode code-point 376 */ {"circ", "\xCB\x86", 0}, /* Unicode code-point 710 */ {"tilde", "\xCB\x9C", 0}, /* Unicode code-point 732 */ {"ensp", "\xE2\x80\x82", 0}, /* Unicode code-point 8194 */ {"emsp", "\xE2\x80\x83", 0}, /* Unicode code-point 8195 */ {"thinsp", "\xE2\x80\x89", 0}, /* Unicode code-point 8201 */ {"zwnj", "\xE2\x80\x8C", 0}, /* Unicode code-point 8204 */ {"zwj", "\xE2\x80\x8D", 0}, /* Unicode code-point 8205 */ {"lrm", "\xE2\x80\x8E", 0}, /* Unicode code-point 8206 */ {"rlm", "\xE2\x80\x8F", 0}, /* Unicode code-point 8207 */ {"ndash", "\xE2\x80\x93", 0}, /* Unicode code-point 8211 */ {"mdash", "\xE2\x80\x94", 0}, /* Unicode code-point 8212 */ {"lsquo", "\xE2\x80\x98", 0}, /* Unicode code-point 8216 */ {"rsquo", "\xE2\x80\x99", 0}, /* Unicode code-point 8217 */ {"sbquo", "\xE2\x80\x9A", 0}, /* Unicode code-point 8218 */ {"ldquo", "\xE2\x80\x9C", 0}, /* Unicode code-point 8220 */ {"rdquo", "\xE2\x80\x9D", 0}, /* Unicode code-point 8221 */ {"bdquo", "\xE2\x80\x9E", 0}, /* Unicode code-point 8222 */ {"dagger", "\xE2\x80\xA0", 0}, /* Unicode code-point 8224 */ {"Dagger", "\xE2\x80\xA1", 0}, /* Unicode code-point 8225 */ {"permil", "\xE2\x80\xB0", 0}, /* Unicode code-point 8240 */ {"lsaquo", "\xE2\x80\xB9", 0}, /* Unicode code-point 8249 */ {"rsaquo", "\xE2\x80\xBA", 0}, /* Unicode code-point 8250 */ {"euro", "\xE2\x82\xAC", 0}, /* Unicode code-point 8364 */ {"fnof", "\xC6\x92", 0}, /* Unicode code-point 402 */ {"Alpha", "\xCE\x91", 0}, /* Unicode code-point 913 */ {"Beta", "\xCE\x92", 0}, /* Unicode code-point 914 */ {"Gamma", "\xCE\x93", 0}, /* Unicode code-point 915 */ {"Delta", "\xCE\x94", 0}, /* Unicode code-point 916 */ {"Epsilon", "\xCE\x95", 0}, /* Unicode code-point 917 */ {"Zeta", "\xCE\x96", 0}, /* Unicode code-point 918 */ {"Eta", "\xCE\x97", 0}, /* Unicode code-point 919 */ {"Theta", "\xCE\x98", 0}, /* Unicode code-point 920 */ {"Iota", "\xCE\x99", 0}, /* Unicode code-point 921 */ {"Kappa", "\xCE\x9A", 0}, /* Unicode code-point 922 */ {"Lambda", "\xCE\x9B", 0}, /* Unicode code-point 923 */ {"Mu", "\xCE\x9C", 0}, /* Unicode code-point 924 */ {"Nu", "\xCE\x9D", 0}, /* Unicode code-point 925 */ {"Xi", "\xCE\x9E", 0}, /* Unicode code-point 926 */ {"Omicron", "\xCE\x9F", 0}, /* Unicode code-point 927 */ {"Pi", "\xCE\xA0", 0}, /* Unicode code-point 928 */ {"Rho", "\xCE\xA1", 0}, /* Unicode code-point 929 */ {"Sigma", "\xCE\xA3", 0}, /* Unicode code-point 931 */ {"Tau", "\xCE\xA4", 0}, /* Unicode code-point 932 */ {"Upsilon", "\xCE\xA5", 0}, /* Unicode code-point 933 */ {"Phi", "\xCE\xA6", 0}, /* Unicode code-point 934 */ {"Chi", "\xCE\xA7", 0}, /* Unicode code-point 935 */ {"Psi", "\xCE\xA8", 0}, /* Unicode code-point 936 */ {"Omega", "\xCE\xA9", 0}, /* Unicode code-point 937 */ {"alpha", "\xCE\xB1", 0}, /* Unicode code-point 945 */ {"beta", "\xCE\xB2", 0}, /* Unicode code-point 946 */ {"gamma", "\xCE\xB3", 0}, /* Unicode code-point 947 */ {"delta", "\xCE\xB4", 0}, /* Unicode code-point 948 */ {"epsilon", "\xCE\xB5", 0}, /* Unicode code-point 949 */ {"zeta", "\xCE\xB6", 0}, /* Unicode code-point 950 */ {"eta", "\xCE\xB7", 0}, /* Unicode code-point 951 */ {"theta", "\xCE\xB8", 0}, /* Unicode code-point 952 */ {"iota", "\xCE\xB9", 0}, /* Unicode code-point 953 */ {"kappa", "\xCE\xBA", 0}, /* Unicode code-point 954 */ {"lambda", "\xCE\xBB", 0}, /* Unicode code-point 955 */ {"mu", "\xCE\xBC", 0}, /* Unicode code-point 956 */ {"nu", "\xCE\xBD", 0}, /* Unicode code-point 957 */ {"xi", "\xCE\xBE", 0}, /* Unicode code-point 958 */ {"omicron", "\xCE\xBF", 0}, /* Unicode code-point 959 */ {"pi", "\xCF\x80", 0}, /* Unicode code-point 960 */ {"rho", "\xCF\x81", 0}, /* Unicode code-point 961 */ {"sigmaf", "\xCF\x82", 0}, /* Unicode code-point 962 */ {"sigma", "\xCF\x83", 0}, /* Unicode code-point 963 */ {"tau", "\xCF\x84", 0}, /* Unicode code-point 964 */ {"upsilon", "\xCF\x85", 0}, /* Unicode code-point 965 */ {"phi", "\xCF\x86", 0}, /* Unicode code-point 966 */ {"chi", "\xCF\x87", 0}, /* Unicode code-point 967 */ {"psi", "\xCF\x88", 0}, /* Unicode code-point 968 */ {"omega", "\xCF\x89", 0}, /* Unicode code-point 969 */ {"thetasym", "\xCF\x91", 0}, /* Unicode code-point 977 */ {"upsih", "\xCF\x92", 0}, /* Unicode code-point 978 */ {"piv", "\xCF\x96", 0}, /* Unicode code-point 982 */ {"bull", "\xE2\x80\xA2", 0}, /* Unicode code-point 8226 */ {"hellip", "\xE2\x80\xA6", 0}, /* Unicode code-point 8230 */ {"prime", "\xE2\x80\xB2", 0}, /* Unicode code-point 8242 */ {"Prime", "\xE2\x80\xB3", 0}, /* Unicode code-point 8243 */ {"oline", "\xE2\x80\xBE", 0}, /* Unicode code-point 8254 */ {"frasl", "\xE2\x81\x84", 0}, /* Unicode code-point 8260 */ {"weierp", "\xE2\x84\x98", 0}, /* Unicode code-point 8472 */ {"image", "\xE2\x84\x91", 0}, /* Unicode code-point 8465 */ {"real", "\xE2\x84\x9C", 0}, /* Unicode code-point 8476 */ {"trade", "\xE2\x84\xA2", 0}, /* Unicode code-point 8482 */ {"alefsym", "\xE2\x84\xB5", 0}, /* Unicode code-point 8501 */ {"larr", "\xE2\x86\x90", 0}, /* Unicode code-point 8592 */ {"uarr", "\xE2\x86\x91", 0}, /* Unicode code-point 8593 */ {"rarr", "\xE2\x86\x92", 0}, /* Unicode code-point 8594 */ {"darr", "\xE2\x86\x93", 0}, /* Unicode code-point 8595 */ {"harr", "\xE2\x86\x94", 0}, /* Unicode code-point 8596 */ {"crarr", "\xE2\x86\xB5", 0}, /* Unicode code-point 8629 */ {"lArr", "\xE2\x87\x90", 0}, /* Unicode code-point 8656 */ {"uArr", "\xE2\x87\x91", 0}, /* Unicode code-point 8657 */ {"rArr", "\xE2\x87\x92", 0}, /* Unicode code-point 8658 */ {"dArr", "\xE2\x87\x93", 0}, /* Unicode code-point 8659 */ {"hArr", "\xE2\x87\x94", 0}, /* Unicode code-point 8660 */ {"forall", "\xE2\x88\x80", 0}, /* Unicode code-point 8704 */ {"part", "\xE2\x88\x82", 0}, /* Unicode code-point 8706 */ {"exist", "\xE2\x88\x83", 0}, /* Unicode code-point 8707 */ {"empty", "\xE2\x88\x85", 0}, /* Unicode code-point 8709 */ {"nabla", "\xE2\x88\x87", 0}, /* Unicode code-point 8711 */ {"isin", "\xE2\x88\x88", 0}, /* Unicode code-point 8712 */ {"notin", "\xE2\x88\x89", 0}, /* Unicode code-point 8713 */ {"ni", "\xE2\x88\x8B", 0}, /* Unicode code-point 8715 */ {"prod", "\xE2\x88\x8F", 0}, /* Unicode code-point 8719 */ {"sum", "\xE2\x88\x91", 0}, /* Unicode code-point 8721 */ {"minus", "\xE2\x88\x92", 0}, /* Unicode code-point 8722 */ {"lowast", "\xE2\x88\x97", 0}, /* Unicode code-point 8727 */ {"radic", "\xE2\x88\x9A", 0}, /* Unicode code-point 8730 */ {"prop", "\xE2\x88\x9D", 0}, /* Unicode code-point 8733 */ {"infin", "\xE2\x88\x9E", 0}, /* Unicode code-point 8734 */ {"ang", "\xE2\x88\xA0", 0}, /* Unicode code-point 8736 */ {"and", "\xE2\x88\xA7", 0}, /* Unicode code-point 8743 */ {"or", "\xE2\x88\xA8", 0}, /* Unicode code-point 8744 */ {"cap", "\xE2\x88\xA9", 0}, /* Unicode code-point 8745 */ {"cup", "\xE2\x88\xAA", 0}, /* Unicode code-point 8746 */ {"int", "\xE2\x88\xAB", 0}, /* Unicode code-point 8747 */ {"there4", "\xE2\x88\xB4", 0}, /* Unicode code-point 8756 */ {"sim", "\xE2\x88\xBC", 0}, /* Unicode code-point 8764 */ {"cong", "\xE2\x89\x85", 0}, /* Unicode code-point 8773 */ {"asymp", "\xE2\x89\x88", 0}, /* Unicode code-point 8776 */ {"ne", "\xE2\x89\xA0", 0}, /* Unicode code-point 8800 */ {"equiv", "\xE2\x89\xA1", 0}, /* Unicode code-point 8801 */ {"le", "\xE2\x89\xA4", 0}, /* Unicode code-point 8804 */ {"ge", "\xE2\x89\xA5", 0}, /* Unicode code-point 8805 */ {"sub", "\xE2\x8A\x82", 0}, /* Unicode code-point 8834 */ {"sup", "\xE2\x8A\x83", 0}, /* Unicode code-point 8835 */ {"nsub", "\xE2\x8A\x84", 0}, /* Unicode code-point 8836 */ {"sube", "\xE2\x8A\x86", 0}, /* Unicode code-point 8838 */ {"supe", "\xE2\x8A\x87", 0}, /* Unicode code-point 8839 */ {"oplus", "\xE2\x8A\x95", 0}, /* Unicode code-point 8853 */ {"otimes", "\xE2\x8A\x97", 0}, /* Unicode code-point 8855 */ {"perp", "\xE2\x8A\xA5", 0}, /* Unicode code-point 8869 */ {"sdot", "\xE2\x8B\x85", 0}, /* Unicode code-point 8901 */ {"lceil", "\xE2\x8C\x88", 0}, /* Unicode code-point 8968 */ {"rceil", "\xE2\x8C\x89", 0}, /* Unicode code-point 8969 */ {"lfloor", "\xE2\x8C\x8A", 0}, /* Unicode code-point 8970 */ {"rfloor", "\xE2\x8C\x8B", 0}, /* Unicode code-point 8971 */ {"lang", "\xE2\x8C\xA9", 0}, /* Unicode code-point 9001 */ {"rang", "\xE2\x8C\xAA", 0}, /* Unicode code-point 9002 */ {"loz", "\xE2\x97\x8A", 0}, /* Unicode code-point 9674 */ {"spades", "\xE2\x99\xA0", 0}, /* Unicode code-point 9824 */ {"clubs", "\xE2\x99\xA3", 0}, /* Unicode code-point 9827 */ {"hearts", "\xE2\x99\xA5", 0}, /* Unicode code-point 9829 */ {"diams", "\xE2\x99\xA6", 0}, /* Unicode code-point 9830 */ /* Non-standard. But very common. */ {"quote", "\"", 0}, {"apos", "'", 0}, }; /* The size of the handler hash table. For best results this should ** be a prime number which is about the same size as the number of ** escape sequences known to the system. */ #define ESC_HASH_SIZE (sizeof(esc_sequences)/sizeof(esc_sequences[0])+7) /* The hash table ** ** If the name of an escape sequences hashes to the value H, then ** apEscHash[H] will point to a linked list of Esc structures, one of ** which will be the Esc structure for that escape sequence. */ static struct sgEsc *apEscHash[ESC_HASH_SIZE]; /* Hash a escape sequence name. The value returned is an integer ** between 0 and ESC_HASH_SIZE-1, inclusive. */ static int EscHash(zName) const char *zName; { int h = 0; /* The hash value to be returned */ char c; /* The next character in the name * being hashed */ while ((c = *zName) != 0) { h = h << 5 ^ h ^ c; zName++; } if (h < 0) { h = -h; } else { } return h % ESC_HASH_SIZE; } #ifdef TEST /* ** Compute the longest and average collision chain length for the ** escape sequence hash table */ static void EscHashStats(void) { int i; int sum = 0; int max = 0; int cnt; int notempty = 0; struct sgEsc *p; for (i = 0; i < sizeof(esc_sequences) / sizeof(esc_sequences[0]); i++) { cnt = 0; p = apEscHash[i]; if (p) notempty++; while (p) { cnt++; p = p->pNext; } sum += cnt; if (cnt > max) max = cnt; } printf("Longest chain=%d avg=%g slots=%d empty=%d (%g%%)\n", max, (double) sum / (double) notempty, i, i - notempty, 100.0 * (i - notempty) / (double) i); } #endif /* Initialize the escape sequence hash table */ static void EscInit() { int i; /* For looping thru the list of escape * sequences */ int h; /* The hash on a sequence */ for (i = 0; i < sizeof(esc_sequences) / sizeof(esc_sequences[i]); i++) { /* #ifdef TCL_UTF_MAX */ #if 0 { int c = esc_sequences[i].value[0]; Tcl_UniCharToUtf(c, esc_sequences[i].value); } #endif h = EscHash(esc_sequences[i].zName); esc_sequences[i].pNext = apEscHash[h]; apEscHash[h] = &esc_sequences[i]; } #ifdef TEST EscHashStats(); #endif } /* ** This table translates the non-standard microsoft characters between ** 0x80 and 0x9f into plain ASCII so that the characters will be visible ** on Unix systems. Care is taken to translate the characters ** into values less than 0x80, to avoid UTF-8 problems. */ #ifndef __WIN32__ static char acMsChar[] = { /* * 0x80 */ 'C', /* * 0x81 */ ' ', /* * 0x82 */ ',', /* * 0x83 */ 'f', /* * 0x84 */ '"', /* * 0x85 */ '.', /* * 0x86 */ '*', /* * 0x87 */ '*', /* * 0x88 */ '^', /* * 0x89 */ '%', /* * 0x8a */ 'S', /* * 0x8b */ '<', /* * 0x8c */ 'O', /* * 0x8d */ ' ', /* * 0x8e */ 'Z', /* * 0x8f */ ' ', /* * 0x90 */ ' ', /* * 0x91 */ '\'', /* * 0x92 */ '\'', /* * 0x93 */ '"', /* * 0x94 */ '"', /* * 0x95 */ '*', /* * 0x96 */ '-', /* * 0x97 */ '-', /* * 0x98 */ '~', /* * 0x99 */ '@', /* * 0x9a */ 's', /* * 0x9b */ '>', /* * 0x9c */ 'o', /* * 0x9d */ ' ', /* * 0x9e */ 'z', /* * 0x9f */ 'Y', }; #endif static int translateNumericEscape(z, pI) char *z; int *pI; /* IN/OUT: Index into string z */ { char *zLocal = &z[*pI]; int base = 10; int iRet = 10; if (*zLocal == 'x' || *zLocal == 'X') { /* Hexadecimal number */ base = 16; zLocal++; } iRet = strtol(zLocal, &zLocal, base); /* Gobble up a trailing semi-colon */ if (*zLocal == ';') { zLocal++; } *pI = (zLocal - z); return iRet; } /* Translate escape sequences in the string "z". "z" is overwritten ** with the translated sequence. ** ** Unrecognized escape sequences are unaltered. ** ** Example: ** ** input = "AT&T > MCI" ** output = "AT&T > MCI" */ void HtmlTranslateEscapes(z) char *z; { int from; /* Read characters from this position * in z[] */ int to; /* Write characters into this position * in z[] */ int h; /* A hash on the escape sequence */ struct sgEsc *p; /* For looping down the escape * sequence collision chain */ static int isInit = 0; /* True after initialization */ from = to = 0; if (!isInit) { EscInit(); isInit = 1; } while (z[from]) { if (z[from] == '&') { if (z[from + 1] == '#') { int i = from + 2; int v = translateNumericEscape(z, &i); /* * On Unix systems, translate the non-standard microsoft ** * characters in the range of 0x80 to 0x9f into something ** * we can see. */ #ifndef __WIN32__ if (v >= 0x80 && v < 0xa0) { v = acMsChar[v & 0x1f]; } #endif /* * Put the character in the output stream in place of ** the * "�". How we do this depends on whether or ** not we * are using UTF-8. */ #ifdef TCL_UTF_MAX { int j, n; char value[8]; n = Tcl_UniCharToUtf(v, value); for (j = 0; j < n; j++) { z[to++] = value[j]; } } #else z[to++] = v; #endif from = i; } else { int i = from + 1; int c; while (z[i] && isalnum(z[i])) { i++; } c = z[i]; z[i] = 0; h = EscHash(&z[from + 1]); p = apEscHash[h]; while (p && strcmp(p->zName, &z[from + 1]) != 0) { p = p->pNext; } z[i] = c; if (p) { int j; for (j = 0; p->value[j]; j++) { z[to++] = p->value[j]; } from = i; if (c == ';') { from++; } } else { z[to++] = z[from++]; } } /* * On UNIX systems, look for the non-standard microsoft * characters ** between 0x80 and 0x9f and translate them into * printable ASCII ** codes. Separate algorithms are required to * do this for plain ** ascii and for utf-8. */ #ifndef __WIN32__ #ifdef TCL_UTF_MAX } else if ((z[from] & 0x80) != 0) { Tcl_UniChar c; int n; n = Tcl_UtfToUniChar(&z[from], &c); if (c >= 0x80 && c < 0xa0) { z[to++] = acMsChar[c & 0x1f]; from += n; } else { while (n--) z[to++] = z[from++]; } #else /* if !defined(TCL_UTF_MAX) */ } else if (((unsigned char) z[from]) >= 0x80 && ((unsigned char) z[from]) < 0xa0) { z[to++] = acMsChar[z[from++] & 0x1f]; #endif /* TCL_UTF_MAX */ #endif /* __WIN32__ */ } else { z[to++] = z[from++]; } } z[to] = 0; } static HtmlWidgetTag * getWidgetTag(pTree, zTag, pIsNew) HtmlTree *pTree; const char *zTag; int *pIsNew; { Tcl_HashEntry *pEntry; int isNew; HtmlWidgetTag *pTag; pEntry = Tcl_CreateHashEntry(&pTree->aTag, zTag, &isNew); if (isNew) { Tk_OptionTable otab = pTree->tagOptionTable; static Tk_OptionSpec ospec[] = { {TK_OPTION_COLOR, "-foreground", "", "", "white", -1, \ Tk_Offset(HtmlWidgetTag, foreground), 0, 0, 0}, {TK_OPTION_COLOR, "-background", "", "", "black", -1, \ Tk_Offset(HtmlWidgetTag, background), 0, 0, 0}, {TK_OPTION_SYNONYM, "-bg", 0, 0, 0, 0, -1, 0, "-background", 0}, {TK_OPTION_SYNONYM, "-fg", 0, 0, 0, 0, -1, 0, "-foreground", 0}, {TK_OPTION_END, 0, 0, 0, 0, 0, 0, 0, 0} }; pTag = (HtmlWidgetTag *)HtmlClearAlloc("", sizeof(HtmlWidgetTag)); Tcl_SetHashValue(pEntry, pTag); if (0 == otab) { pTree->tagOptionTable = Tk_CreateOptionTable(pTree->interp, ospec); otab = pTree->tagOptionTable; assert(otab); } Tk_InitOptions(pTree->interp, (char *)pTag, otab, pTree->tkwin); assert(pTag->foreground && pTag->background); } else { pTag = (HtmlWidgetTag *)Tcl_GetHashValue(pEntry); } if (pIsNew) { *pIsNew = isNew; } return pTag; } static HtmlNode * orderIndexPair(ppA, piA, ppB, piB) HtmlNode **ppA; int *piA; HtmlNode **ppB; int *piB; { HtmlNode *pA; HtmlNode *pB; HtmlNode *pParent; int nDepthA = 0; int nDepthB = 0; int ii; int swap = 0; for(pA = HtmlNodeParent(*ppA); pA; pA = HtmlNodeParent(pA)) nDepthA++; for(pB = HtmlNodeParent(*ppB); pB; pB = HtmlNodeParent(pB)) nDepthB++; pA = *ppA; pB = *ppB; for(ii = 0; ii < (nDepthA - nDepthB); ii++) pA = HtmlNodeParent(pA); for(ii = 0; ii < (nDepthB - nDepthA); ii++) pB = HtmlNodeParent(pB); if (pA == pB) { if (nDepthA == nDepthB) { /* In this case *ppA and *ppB are the same node */ swap = (*piA > *piB); } else { /* One of (*ppA, *ppB) is a descendant of the other */ swap = (nDepthA > nDepthB); } pParent = pA; } else { while (HtmlNodeParent(pA) != HtmlNodeParent(pB)) { pA = HtmlNodeParent(pA); pB = HtmlNodeParent(pB); assert(pA && pB && pA != pB); } pParent = HtmlNodeParent(pA); for (ii = 0; ; ii++) { HtmlNode *pChild = HtmlNodeChild(pParent, ii); assert(ii < HtmlNodeNumChildren(pParent) && pChild); if (pChild == pA) break; if (pChild == pB) { swap = 1; break; } } } if (swap) { HtmlNode *p; int i; p = *ppB; *ppB = *ppA; *ppA = p; i = *piB; *piB = *piA; *piA = i; } return pParent; } /* *--------------------------------------------------------------------------- * * removeTagFromNode -- * * Results: * Returns non-zero if one or more characters of this node were tagged. * * Side effects: * None. * *--------------------------------------------------------------------------- */ static int removeTagFromNode(pTextNode, pTag) HtmlTextNode *pTextNode; HtmlWidgetTag *pTag; { int eRet = 0; HtmlTaggedRegion *pTagged = pTextNode->pTagged; if (pTagged) { HtmlTaggedRegion **pPtr = &pTextNode->pTagged; while (pTagged) { if (pTagged->pTag == pTag) { *pPtr = pTagged->pNext; HtmlFree(pTagged); eRet = 1; } else { pPtr = &pTagged->pNext; } pTagged = *pPtr; } } #ifndef NDEBUG for (pTagged = pTextNode->pTagged; pTagged ; pTagged = pTagged->pNext) { assert(pTagged->pTag != pTag); } #endif return eRet; } static HtmlTaggedRegion * findTagInNode(pTextNode, pTag, ppPtr) HtmlTextNode *pTextNode; HtmlWidgetTag *pTag; HtmlTaggedRegion ***ppPtr; { HtmlTaggedRegion *pTagged; HtmlTaggedRegion **pPtr = &pTextNode->pTagged; for (pTagged = pTextNode->pTagged; pTagged; pTagged = pTagged->pNext) { if (pTagged->pTag == pTag) { *ppPtr = pPtr; return pTagged; } pPtr = &pTagged->pNext; } *ppPtr = pPtr; return 0; } typedef struct TagOpData TagOpData; struct TagOpData { HtmlNode *pFrom; int iFrom; HtmlNode *pTo; int iTo; int eSeenFrom; /* True after pFrom has been traversed */ HtmlWidgetTag *pTag; int isAdd; /* True for [add] false for [remove] */ HtmlNode *pFirst; HtmlNode *pLast; int iFirst; int iLast; }; #define OVERLAP_NONE 1 #define OVERLAP_SUPER 2 #define OVERLAP_SUB 3 #define OVERLAP_FROM 4 #define OVERLAP_TO 5 #define OVERLAP_EXACT 6 static int getOverlap(pTagged, iFrom, iTo) HtmlTaggedRegion *pTagged; int iFrom; int iTo; { assert(iFrom <= iTo); assert(pTagged->iFrom <= pTagged->iTo); if (iFrom == pTagged->iFrom && iTo == pTagged->iTo) { return OVERLAP_EXACT; } if (iFrom <= pTagged->iFrom && iTo >= pTagged->iTo) { return OVERLAP_SUPER; } if (iFrom >= pTagged->iFrom && iTo <= pTagged->iTo) { return OVERLAP_SUB; } if (iFrom > pTagged->iTo || iTo < pTagged->iFrom) { return OVERLAP_NONE; } if (iFrom > pTagged->iFrom) { assert(iFrom <= pTagged->iTo); assert(iTo > pTagged->iTo); return OVERLAP_TO; } assert(iTo >= pTagged->iFrom); assert(iTo < pTagged->iTo); assert(iFrom < pTagged->iFrom); return OVERLAP_FROM; } static int tagAddRemoveCallback(pTree, pNode, clientData) HtmlTree *pTree; HtmlNode *pNode; ClientData clientData; { TagOpData *pData = (TagOpData *)clientData; HtmlTextNode *pTextNode = HtmlNodeAsText(pNode); if (pNode == pData->pFrom) { assert(0 == pData->eSeenFrom); pData->eSeenFrom = 1; } if (pTextNode && pData->eSeenFrom) { HtmlTaggedRegion *pTagged; HtmlTaggedRegion **pPtr; int iFrom = 0; int iTo = 1000000; if (pNode == pData->pFrom) iFrom = pData->iFrom; if (pNode == pData->pTo) iTo = pData->iTo; assert(iFrom <= iTo); pTagged = findTagInNode(pTextNode, pData->pTag, &pPtr); assert(*pPtr == pTagged); switch (pData->isAdd) { case HTML_TAG_ADD: while (pTagged && pTagged->pTag == pData->pTag) { int e = getOverlap(pTagged, iFrom, iTo); pPtr = &pTagged->pNext; if (e != OVERLAP_NONE) { if (0 == pData->pFirst) { if (e == OVERLAP_SUPER || e == OVERLAP_FROM) { pData->pFirst = pNode; pData->iFirst = iFrom; } else if (e == OVERLAP_TO) { pData->pFirst = pNode; pData->iFirst = pTagged->iTo; } } if (e == OVERLAP_TO || e == OVERLAP_SUPER) { pData->pLast = pNode; pData->iLast = iTo; } if (e == OVERLAP_FROM) { pData->pLast = pNode; pData->iLast = pTagged->iFrom; } pTagged->iFrom = MIN(pTagged->iFrom, iFrom); pTagged->iTo = MAX(pTagged->iTo, iTo); break; } pTagged = *pPtr; } if (!pTagged || pTagged->pTag != pData->pTag) { HtmlTaggedRegion *pNew = (HtmlTaggedRegion *) HtmlClearAlloc("", sizeof(HtmlTaggedRegion)); pNew->iFrom = iFrom; pNew->iTo = iTo; pNew->pNext = pTagged; pNew->pTag = pData->pTag; if (!pData->pFirst) { pData->pFirst = pNode; pData->iFirst = iFrom; } pData->pLast = pNode; pData->iLast = iTo; *pPtr = pNew; } break; case HTML_TAG_REMOVE: while (pTagged && pTagged->pTag == pData->pTag) { int eOverlap = getOverlap(pTagged, iFrom, iTo); switch (eOverlap) { case OVERLAP_EXACT: case OVERLAP_SUPER: { /* Delete the whole list entry */ *pPtr = pTagged->pNext; HtmlFree(pTagged); break; }; case OVERLAP_TO: pTagged->iTo = iFrom; pPtr = &pTagged->pNext; break; case OVERLAP_FROM: pTagged->iFrom = iTo; pPtr = &pTagged->pNext; break; case OVERLAP_NONE: /* Do nothing */ pPtr = &pTagged->pNext; break; case OVERLAP_SUB: { HtmlTaggedRegion *pNew = (HtmlTaggedRegion *) HtmlClearAlloc("", sizeof(HtmlTaggedRegion)); pNew->iFrom = iTo; pNew->iTo = pTagged->iTo; pNew->pTag = pData->pTag; pNew->pNext = pTagged->pNext; pTagged->pNext = pNew; pTagged->iTo = iFrom; pPtr = &pNew->pNext; break; } } pTagged = *pPtr; } break; } } if (pNode == pData->pTo) { return HTML_WALK_ABANDON; } return HTML_WALK_DESCEND; } int HtmlTagAddRemoveCmd(clientData, interp, objc, objv, isAdd) ClientData clientData; /* The HTML widget */ Tcl_Interp *interp; /* The interpreter */ int objc; /* Number of arguments */ Tcl_Obj *CONST objv[]; /* List of all arguments */ int isAdd; { HtmlTree *pTree = (HtmlTree *)clientData; HtmlNode *pParent; HtmlWidgetTag *pTag; TagOpData sData; memset(&sData, 0, sizeof(TagOpData)); assert(isAdd == HTML_TAG_REMOVE || isAdd == HTML_TAG_ADD); if (objc != 8) { Tcl_WrongNumArgs(interp, 3, objv, "TAGNAME FROM-NODE FROM-INDEX TO-NODE TO-INDEX" ); return TCL_ERROR; } if ( 0 == (sData.pFrom=HtmlNodeGetPointer(pTree, Tcl_GetString(objv[4]))) || TCL_OK != Tcl_GetIntFromObj(interp, objv[5], &sData.iFrom) || 0 == (sData.pTo=HtmlNodeGetPointer(pTree, Tcl_GetString(objv[6]))) || TCL_OK != Tcl_GetIntFromObj(interp, objv[7], &sData.iTo) ) { return TCL_ERROR; } /* If either node is an orphan node, throw a Tcl exception. */ if (HtmlNodeIsOrphan(sData.pFrom)) { Tcl_AppendResult(interp, Tcl_GetString(objv[4]), " is an orphan", 0); return TCL_ERROR; } if (HtmlNodeIsOrphan(sData.pTo)) { Tcl_AppendResult(interp, Tcl_GetString(objv[6]), " is an orphan", 0); return TCL_ERROR; } pTag = getWidgetTag(pTree, Tcl_GetString(objv[3]), 0); sData.pTag = pTag; sData.isAdd = isAdd; pParent = orderIndexPair(&sData.pFrom,&sData.iFrom,&sData.pTo,&sData.iTo); HtmlWalkTree(pTree, pParent, tagAddRemoveCallback, &sData); if (isAdd == HTML_TAG_REMOVE) { HtmlWidgetDamageText(pTree, sData.pFrom, sData.iFrom, sData.pTo, sData.iTo ); } else if (sData.pFirst) { assert(sData.pLast); HtmlWidgetDamageText(pTree, sData.pFirst, sData.iFirst, sData.pLast, sData.iLast ); } return TCL_OK; } int HtmlTagConfigureCmd(clientData, interp, objc, objv) ClientData clientData; /* The HTML widget */ Tcl_Interp *interp; /* The interpreter */ int objc; /* Number of arguments */ Tcl_Obj *CONST objv[]; /* List of all arguments */ { HtmlTree *pTree = (HtmlTree *)clientData; Tk_OptionTable otab; HtmlWidgetTag *pTag; Tk_Window win = pTree->tkwin; int isNew; if (objc < 4) { Tcl_WrongNumArgs(interp, 3, objv, "TAGNAME ?options?"); return TCL_ERROR; } pTag = getWidgetTag(pTree, Tcl_GetString(objv[3]), &isNew); otab = pTree->tagOptionTable; assert(otab); Tk_SetOptions(interp, (char *)pTag, otab, objc - 4, &objv[4], win, 0, 0); if (!isNew) { /* Redraw the whole viewport. Todo: Update only the tagged regions */ HtmlCallbackDamage(pTree, 0, 0, 1000000, 1000000); } return TCL_OK; } struct TagDeleteContext { HtmlWidgetTag *pTag; int nOcc; }; typedef struct TagDeleteContext TagDeleteContext; static int tagDeleteCallback(pTree, pNode, clientData) HtmlTree *pTree; HtmlNode *pNode; ClientData clientData; { HtmlTextNode *pTextNode = HtmlNodeAsText(pNode); if (pTextNode) { TagDeleteContext *p = (TagDeleteContext *)clientData; p->nOcc += removeTagFromNode(pTextNode, p->pTag); } return HTML_WALK_DESCEND; } int HtmlTagDeleteCmd(clientData, interp, objc, objv) ClientData clientData; /* The HTML widget */ Tcl_Interp *interp; /* The interpreter */ int objc; /* Number of arguments */ Tcl_Obj *CONST objv[]; /* List of all arguments */ { const char *zTag; Tcl_HashEntry *pEntry; HtmlTree *pTree = (HtmlTree *)clientData; TagDeleteContext context = {0, 0}; if (objc != 4) { Tcl_WrongNumArgs(interp, 3, objv, "TAGNAME"); return TCL_ERROR; } zTag = Tcl_GetString(objv[3]); pEntry = Tcl_FindHashEntry(&pTree->aTag, zTag); if (pEntry) { HtmlWidgetTag *pTag = (HtmlWidgetTag *)Tcl_GetHashValue(pEntry); context.pTag = pTag; HtmlWalkTree(pTree, 0, tagDeleteCallback, (ClientData)&context); HtmlFree(pTag); Tcl_DeleteHashEntry(pEntry); } /* Redraw the whole viewport. Todo: Update only the required regions */ if (context.nOcc) { HtmlCallbackDamage(pTree, 0, 0, 1000000, 1000000); } return TCL_OK; } void HtmlTagCleanupNode(pTextNode) HtmlTextNode *pTextNode; { HtmlTaggedRegion *pTagged = pTextNode->pTagged; while (pTagged) { HtmlTaggedRegion *pNext = pTagged->pNext; HtmlFree(pTagged); pTagged = pNext; } pTextNode->pTagged = 0; } void HtmlTagCleanupTree(pTree) HtmlTree *pTree; { Tcl_HashEntry *pEntry; Tcl_HashSearch search; pEntry = Tcl_FirstHashEntry(&pTree->aTag, &search); for ( ; pEntry; pEntry = Tcl_NextHashEntry(&search)) { HtmlWidgetTag *pTag = (HtmlWidgetTag *)Tcl_GetHashValue(pEntry); Tk_FreeConfigOptions((char *)pTag, pTree->tagOptionTable, pTree->tkwin); HtmlFree(pTag); } Tcl_DeleteHashTable(&pTree->aTag); } /* * The following two structs are used together to create a data-structure * to store the text-representation of the document. * */ typedef struct HtmlTextMapping HtmlTextMapping; struct HtmlTextMapping { HtmlTextNode *pTextNode; int iStrIndex; /* Character offset in HtmlText.pObj */ int iNodeIndex; /* Byte offset in HtmlTextNode.zText */ HtmlTextMapping *pNext; }; struct HtmlText { Tcl_Obj *pObj; HtmlTextMapping *pMapping; }; typedef struct HtmlTextInit HtmlTextInit; struct HtmlTextInit { HtmlText *pText; int eState; int iIdx; }; #define SEEN_TEXT 0 #define SEEN_SPACE 1 #define SEEN_BLOCK 2 static void addTextMapping(pText, pTextNode, iNodeIndex, iStrIndex) HtmlText *pText; HtmlTextNode *pTextNode; int iNodeIndex; int iStrIndex; { HtmlTextMapping *p; p = (HtmlTextMapping *)HtmlAlloc("HtmlTextMapping",sizeof(HtmlTextMapping)); p->iStrIndex = iStrIndex; p->iNodeIndex = iNodeIndex; p->pTextNode = pTextNode; p->pNext = pText->pMapping; pText->pMapping = p; } static void initHtmlText_TextNode(pTree, pTextNode, pInit) HtmlTree *pTree; HtmlTextNode *pTextNode; HtmlTextInit *pInit; { HtmlNode *pNode = &pTextNode->node; int isPre = (HtmlNodeComputedValues(pNode)->eWhitespace == CSS_CONST_PRE); HtmlTextIter sIter; if (pInit->eState == SEEN_BLOCK) { Tcl_AppendToObj(pInit->pText->pObj, "\n", 1); pInit->iIdx++; } for ( HtmlTextIterFirst(pTextNode, &sIter); HtmlTextIterIsValid(&sIter); HtmlTextIterNext(&sIter) ) { int eType = HtmlTextIterType(&sIter); int nData = HtmlTextIterLength(&sIter); char const * zData = HtmlTextIterData(&sIter); switch (eType) { case HTML_TEXT_TOKEN_NEWLINE: case HTML_TEXT_TOKEN_SPACE: if (isPre) { int ii; const char *zWhite; zWhite = (eType==HTML_TEXT_TOKEN_SPACE ? " " : "\n"); for (ii = 0; ii < nData; ii++) { Tcl_AppendToObj(pInit->pText->pObj, zWhite, 1); } pInit->iIdx += nData; pInit->eState = SEEN_TEXT; } else { pInit->eState = MAX(pInit->eState, SEEN_SPACE); } break; case HTML_TEXT_TOKEN_TEXT: if (pInit->iIdx > 0 && pInit->eState == SEEN_SPACE) { Tcl_AppendToObj(pInit->pText->pObj, " ", 1); pInit->iIdx++; } addTextMapping(pTree->pText, pTextNode, (zData - pTextNode->zText), pInit->iIdx ); Tcl_AppendToObj(pInit->pText->pObj, zData, nData); pInit->eState = SEEN_TEXT; assert(nData >= 0); pInit->iIdx += Tcl_NumUtfChars(zData, nData); break; default: assert(!"Bad return value from HtmlTextIterType()"); } } } static void initHtmlText_Elem(pTree, pElem, pInit) HtmlTree *pTree; HtmlElementNode *pElem; HtmlTextInit *pInit; { HtmlNode *pNode = &pElem->node; int eDisplay = HtmlNodeComputedValues(pNode)->eDisplay; int ii; /* If the element has "display:none" or a replacement window, do * not consider any text children to be part of the text * rendering of the document. */ if ( (eDisplay == CSS_CONST_NONE) || (pElem->pReplacement && pElem->pReplacement->win) ) { return; } if (eDisplay != CSS_CONST_INLINE) { pInit->eState = SEEN_BLOCK; } for (ii = 0; ii < HtmlNodeNumChildren(pNode); ii++) { HtmlNode *p = HtmlNodeChild(pNode, ii); if (HtmlNodeIsText(p)) { initHtmlText_TextNode(pTree, HtmlNodeAsText(p), pInit); } else { initHtmlText_Elem(pTree, HtmlNodeAsElement(p), pInit); } } if (eDisplay != CSS_CONST_INLINE) { pInit->eState = SEEN_BLOCK; } } /* *--------------------------------------------------------------------------- * * initHtmlText -- * * This function is called to initialise the HtmlText data structure * at HtmlTree.pText. If the data structure is already initialised * this function is a no-op. * * Results: * None. * * Side effects: * None. * *--------------------------------------------------------------------------- */ static void initHtmlText(pTree) HtmlTree *pTree; { if (!pTree->pText) { HtmlTextInit sInit; HtmlCallbackForce(pTree); pTree->pText = (HtmlText *)HtmlClearAlloc(0, sizeof(HtmlText)); memset(&sInit, 0, sizeof(HtmlTextInit)); sInit.pText = pTree->pText; sInit.pText->pObj = Tcl_NewObj(); Tcl_IncrRefCount(sInit.pText->pObj); initHtmlText_Elem(pTree, HtmlNodeAsElement(pTree->pRoot), &sInit); Tcl_AppendToObj(sInit.pText->pObj, "\n", 1); } } void HtmlTextInvalidate(pTree) HtmlTree *pTree; { if (pTree->pText) { HtmlText *pText = pTree->pText; HtmlTextMapping *pMapping = pText->pMapping; Tcl_DecrRefCount(pTree->pText->pObj); while (pMapping) { HtmlTextMapping *pNext = pMapping->pNext; HtmlFree(pMapping); pMapping = pNext; } HtmlFree(pTree->pText); pTree->pText = 0; } } int HtmlTextTextCmd(clientData, interp, objc, objv) ClientData clientData; /* The HTML widget */ Tcl_Interp *interp; /* The interpreter */ int objc; /* Number of arguments */ Tcl_Obj *CONST objv[]; /* List of all arguments */ { HtmlTree *pTree = (HtmlTree *)clientData; if (objc != 3) { Tcl_WrongNumArgs(interp, 3, objv, ""); return TCL_ERROR; } initHtmlText(pTree); Tcl_SetObjResult(interp, pTree->pText->pObj); return TCL_OK; } /* *--------------------------------------------------------------------------- * * HtmlTextIndexCmd -- * * $html text index OFFSET ?OFFSET? ?OFFSET? * * The argument $OFFSET is an offset into the string returned * by [$html text text]. This Tcl command returns a list of two * elements - the node and node index corresponding to the * equivalent point in the document tree. * * Results: * None. * * Side effects: * None. * *--------------------------------------------------------------------------- */ int HtmlTextIndexCmd(clientData, interp, objc, objv) ClientData clientData; /* The HTML widget */ Tcl_Interp *interp; /* The interpreter */ int objc; /* Number of arguments */ Tcl_Obj *CONST objv[]; /* List of all arguments */ { HtmlTree *pTree = (HtmlTree *)clientData; int ii; Tcl_Obj *p = Tcl_NewObj(); HtmlTextMapping *pMap = 0; int iPrev = 0; if (objc < 4) { Tcl_WrongNumArgs(interp, 3, objv, "OFFSET ?OFFSET? ..."); return TCL_ERROR; } initHtmlText(pTree); for (ii = objc-1; ii >= 3; ii--) { int iIndex; if (Tcl_GetIntFromObj(interp, objv[ii], &iIndex)) { return TCL_ERROR; } if (pMap == 0 || iIndex > iPrev) { pMap = pTree->pText->pMapping; } for ( ; pMap; pMap = pMap->pNext) { assert(!pMap->pNext || pMap->iStrIndex >= pMap->pNext->iStrIndex); if (pMap->iStrIndex <= iIndex || !pMap->pNext) { int iNodeIdx = pMap->iNodeIndex; Tcl_Obj *apObj[2]; int nExtra = iIndex - pMap->iStrIndex; char *zExtra = &(pMap->pTextNode->zText[iNodeIdx]); iNodeIdx += (Tcl_UtfAtIndex(zExtra, nExtra) - zExtra); apObj[0] = HtmlNodeCommand(pTree, &pMap->pTextNode->node); apObj[1] = Tcl_NewIntObj(iNodeIdx); Tcl_ListObjReplace(0, p, 0, 0, 2, apObj); break; } } iPrev = iIndex; } Tcl_SetObjResult(interp, p); return TCL_OK; } /* *--------------------------------------------------------------------------- * * HtmlTextOffsetCmd -- * * $html text index NODE INDEX * * Given the supplied node/index pair, return the corresponding offset * in the text representation of the document. * * The INDEX parameter is in bytes. The returned value is in characters. * * Results: * None. * * Side effects: * None. * *--------------------------------------------------------------------------- */ int HtmlTextOffsetCmd(clientData, interp, objc, objv) ClientData clientData; /* The HTML widget */ Tcl_Interp *interp; /* The interpreter */ int objc; /* Number of arguments */ Tcl_Obj *CONST objv[]; /* List of all arguments */ { HtmlTree *pTree = (HtmlTree *)clientData; HtmlTextMapping *pMap; /* C interpretations of arguments passed to the Tcl command */ HtmlNode *pNode; HtmlTextNode *pTextNode; int iIndex; /* Return value for the Tcl command. Anything less than 0 results * in an empty string being returned. */ int iRet = -1; if (objc != 5) { Tcl_WrongNumArgs(interp, 3, objv, "NODE INDEX"); return TCL_ERROR; } if ( 0 == (pNode = HtmlNodeGetPointer(pTree, Tcl_GetString(objv[3]))) || TCL_OK != Tcl_GetIntFromObj(interp, objv[4], &iIndex) ) { return TCL_ERROR; } if (!(pTextNode = HtmlNodeAsText(pNode))) { const char *zNode = Tcl_GetString(objv[3]); Tcl_AppendResult(interp, zNode, " is not a text node", 0); return TCL_ERROR; } initHtmlText(pTree); for (pMap = pTree->pText->pMapping; pMap; pMap = pMap->pNext) { if (pMap->pTextNode == pTextNode && pMap->iNodeIndex <= iIndex) { char *zExtra = &pTextNode->zText[pMap->iNodeIndex]; int nExtra = iIndex - pMap->iNodeIndex; iRet = pMap->iStrIndex + Tcl_NumUtfChars(zExtra, nExtra); break; } } if (iRet >= 0) { Tcl_SetObjResult(interp, Tcl_NewIntObj(iRet)); } return TCL_OK; } /* *--------------------------------------------------------------------------- * * HtmlTextBboxCmd -- * * $html text bbox NODE1 INDEX1 NODE2 INDEX2 * * Results: * None. * * Side effects: * None. * *--------------------------------------------------------------------------- */ int HtmlTextBboxCmd(clientData, interp, objc, objv) ClientData clientData; /* The HTML widget */ Tcl_Interp *interp; /* The interpreter */ int objc; /* Number of arguments */ Tcl_Obj *CONST objv[]; /* List of all arguments */ { HtmlTree *pTree = (HtmlTree *)clientData; HtmlNode *pFrom; HtmlNode *pTo; int iFrom; int iTo; int iTop, iLeft, iBottom, iRight; if (objc != 7) { Tcl_WrongNumArgs(interp, 3, objv, "FROM-NODE FROM-INDEX TO-NODE TO-INDEX" ); return TCL_ERROR; } if ( 0 == (pFrom=HtmlNodeGetPointer(pTree, Tcl_GetString(objv[3]))) || TCL_OK != Tcl_GetIntFromObj(interp, objv[4], &iFrom) || 0 == (pTo=HtmlNodeGetPointer(pTree, Tcl_GetString(objv[5]))) || TCL_OK != Tcl_GetIntFromObj(interp, objv[6], &iTo) ) { return TCL_ERROR; } orderIndexPair(&pFrom, &iFrom, &pTo, &iTo); HtmlWidgetBboxText(pTree, pFrom, iFrom, pTo, iTo, &iTop, &iLeft, &iBottom, &iRight ); if (iTop < iBottom && iLeft < iRight) { Tcl_Obj *pRes = Tcl_NewObj(); Tcl_ListObjAppendElement(0, pRes, Tcl_NewIntObj(iLeft)); Tcl_ListObjAppendElement(0, pRes, Tcl_NewIntObj(iTop)); Tcl_ListObjAppendElement(0, pRes, Tcl_NewIntObj(iRight)); Tcl_ListObjAppendElement(0, pRes, Tcl_NewIntObj(iBottom)); Tcl_SetObjResult(interp, pRes); } return TCL_OK; } /* * NOTES ON INTERNALS OF HtmlTextNode: * * The internals of the HtmlTextNode structure should be accessed * via the following API: * * HtmlTextNew() * HtmlTextFree() * * HtmlTextIterFirst * HtmlTextIterIsValid * HtmlTextIterNext * * HtmlTextIterType * HtmlTextIterLength * HtmlTextIterData * * HtmlNodeIsWhitespace * * HtmlTextCombine() * * An HtmlTextNode object stores it's text in two parts: * * * A character string with SGML escape sequences replaced their * UTF-8 equivalents and each block of whitespace replaced by * a single space character. * * * An ordered list of tokens. Each token one of the following: * + An unwrappable block of text (i.e. a word), * + One or more newline characters, or * + One or more space characters. * * Each token is represented by an instance of struct * HtmlTextToken. It has 1 byte type and a 1 byte unsigned * length indicating the number of bytes, spaces or * newlines represented by the token. * * The following block of text: * * "abcde ><hello" * * Is represented by the data structures: * * HtmlTextNode.aToken = { * {TEXT, 5}, {SPACE, 3}, {NEWLINE, 1}, * {TEXT, 2}, {NEWLINE 2}, * {TEXT, 5}, * {END, }, * } * HtmlTextNode.zText = "abcde <> hello" * * Storing the text in this format means that we are well-placed * to rationalise a good percentage calls to Tk_DrawChars() etc. in * other parts of the widget code. * * Blocks of contiguous space or newline characters longer than 255 * characters (the maximum value of HtmlTextToken.n) are stored * as two or more contiguous SPACE tokens. i.e. 650 contiguous spaces * require the following three tokens in the aToken array: * * {SPACE, 255}, {SPACE, 255}, {SPACE, 140} * * Blocks of non-whitespace longer than 255 characters are trickier. * They always require exactly three tokens to be added to the array. * For a 650 byte block of text the following three tokens: * * {LONGTEXT, {650 >> 16} & 0xFF}, * {LONGTEXT, {650 >> 8} & 0xFF}, * {LONGTEXT, {650 >> 0} & 0xFF} * * If a node consists entirely of white-space, then the HtmlTextNode.zText * string is zero bytes in length. In this case HtmlTextNode.zText is * set to NULL, to speed up checking if the node consists entirely * of whitespace. * * Todo: It's tempting to use single byte tokens, instead of two. Three * bits for the type and five for the length. On the other hand, * premature optimization..... */ struct HtmlTextToken { unsigned char n; unsigned char eType; }; /* Return true if the argument is a unicode codpoint that should be handled * as a 'cjk' character. */ #define ISCJK(ii) ((ii)>=0x3000 && (ii)<=0x9fff) /* *--------------------------------------------------------------------------- * * utf8Read -- * * Decode a single UTF8 character from the buffer pointed to by z. * * Results: * Unicode codepoint of read character, or 0 if the end of the buffer * has been reached. * * Side effects: * None. * *--------------------------------------------------------------------------- */ static Tcl_UniChar utf8Read( const unsigned char *z, /* first byte of utf-8 character */ const unsigned char *zTerm, /* pretend this byte is 0x00 */ const unsigned char **pzNext /* write first byte past utf-8 char here */ ){ static const unsigned char UtfTrans[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x00, 0x01, 0x02, 0x03, 0x00, 0x01, 0x00, 0x00, }; unsigned int c = 0; if (zTerm>z) { c = (unsigned int)*z; if ((c&0xC0)==0xC0) { const unsigned char *zCsr = &z[1]; c = UtfTrans[c-0xC0]; while (zCsr!=zTerm && ((*zCsr)&0xC0)==0x80){ c = (c << 6) + ((*zCsr)&0x3F); zCsr++; } *pzNext = zCsr; } else { *pzNext = &z[1]; } } else { *pzNext = zTerm; } return c; } /* *--------------------------------------------------------------------------- * * tokenLength -- * * Argument zToken points at the start of a text token (a non-whitespace * character). This function returns the number of bytes in the token. * zEnd points to 1 byte passed the end of the buffer - reading *zEnd * would be a seg-fault. * * Results: * Length of token at zToken in bytes. * * Side effects: * None. * *--------------------------------------------------------------------------- */ static int tokenLength(zToken, zEnd) const unsigned char *zToken; const unsigned char *zEnd; { Tcl_UniChar iChar = 0; const unsigned char *zCsr = zToken; const unsigned char *zNext = zCsr; iChar = utf8Read(zCsr, zEnd, &zNext); while (iChar && (iChar >= 256 || !ISSPACE(iChar)) && !ISCJK(iChar)){ zCsr = zNext; iChar = utf8Read(zCsr, zEnd, &zNext); } return ((zCsr==zToken)?zNext:zCsr)-zToken; } /* *--------------------------------------------------------------------------- * * populateTextNode -- * * This function is called to tokenize a block of document text into * an HtmlTextNode structure. It is a helper function for HtmlTextNew(). * * This function is designed to be called twice for each block of text * parsed to an HtmlTextNode. The first time, it determines the space * (number of tokens and number of bytes of text) required for the * the new HtmlTextNode. The caller then allocates this space and * calls the function a second time to populate the new structure. * * Results: * None. * * Side effects: * *--------------------------------------------------------------------------- */ static void populateTextNode(n, z, pText, pnToken, pnText) int n; /* Length of input text */ char const *z; /* Input text */ HtmlTextNode *pText; /* OUT: The structure to populate (or NULL) */ int *pnToken; /* OUT: Number of tokens required (or used) */ int *pnText; /* OUT: Bytes of text required (or used) */ { char const *zCsr = z; char const *zStop = &z[n]; /* A running count of the number of tokens and bytes of text storage * required to store the parsed form of the input text. */ int nToken = 0; int nText = 0; /* This variable is used to expand tabs. */ int iCol = 0; int isPrevTokenText = 0; while (zCsr < zStop) { unsigned char c = (int)(*zCsr); char const *zStart = zCsr; if (ISSPACE(c)) { int nSpace = 0; /* Eventual token length */ int eType = HTML_TEXT_TOKEN_SPACE; /* Eventual token type */ if (ISNEWLINE(c)) { eType = HTML_TEXT_TOKEN_NEWLINE; } do { /* If a tab character, this is equivalent to adding between * one and eight spaces, depending on the current value of * variable iCol (see comments above variable declaration). */ if (ISTAB(*zCsr)) nSpace += (7 - (iCol%8)); /* The sequence CR (carraige return) followed by LF (line * feed) counts as a single newline. If either is encountered * alone, this is also a single newline. LF followed by CR * is two newlines. */ if (zCsr[0] == '\r' && &zCsr[1] < zStop && zCsr[1] == '\n') { zCsr++; } nSpace++; zCsr++; iCol += nSpace; } while ( zCsr < zStop && nSpace < (255 - 8) && ISSPACE(*zCsr) && ( (eType == HTML_TEXT_TOKEN_NEWLINE && ISNEWLINE(*zCsr)) || (eType == HTML_TEXT_TOKEN_SPACE && !ISNEWLINE(*zCsr)) ) ); if (eType == HTML_TEXT_TOKEN_NEWLINE) { iCol = 0; } assert(nSpace <= 255); if (pText) { pText->aToken[nToken].n = nSpace; pText->aToken[nToken].eType = eType; } nToken++; /* If the previous token was text, add a single space character * to the HtmlTextNode.zText buffer. Otherwise, add nothing * to the text buffer. */ if (isPrevTokenText) { if (pText) { pText->zText[nText] = ' '; } nText++; isPrevTokenText = 0; } } else { /* This block sets nThisText to the number of bytes (not * characters) in the token starting at zStart. zCsr is * left pointing to the byte immediately after the token. */ int nThisText = tokenLength( (unsigned char *)zCsr, (unsigned char *)zStop ); assert(zCsr == zStart); assert(nThisText>0); zCsr = &zCsr[nThisText]; if (nThisText > 255) { if (pText) { pText->aToken[nToken].eType = HTML_TEXT_TOKEN_LONGTEXT; pText->aToken[nToken+1].eType = HTML_TEXT_TOKEN_LONGTEXT; pText->aToken[nToken+2].eType = HTML_TEXT_TOKEN_LONGTEXT; pText->aToken[nToken].n = ((nThisText >> 16) & 0x000000FF); pText->aToken[nToken+1].n = ((nThisText >> 8) & 0x000000FF); pText->aToken[nToken+2].n = (nThisText & 0x000000FF); memcpy(&pText->zText[nText], zStart, nThisText); } nToken += 3; } else { if (pText) { pText->aToken[nToken].eType = HTML_TEXT_TOKEN_TEXT; pText->aToken[nToken].n = nThisText; memcpy(&pText->zText[nText], zStart, nThisText); } nToken++; } nText += nThisText; isPrevTokenText = 1; iCol += nThisText; } } /* Add the terminator token */ if (pText) { pText->aToken[nToken].eType = HTML_TEXT_TOKEN_END; } nToken++; if (pnToken) *pnToken = nToken; if (pnText) *pnText = nText; } void HtmlTextSet(pText, n, z, isTrimEnd, isTrimStart) HtmlTextNode *pText; int n; const char *z; int isTrimEnd; int isTrimStart; { char *z2; HtmlTextToken *pFinal; int nText = 0; int nToken = 0; int nAlloc; /* Number of bytes allocated */ if (pText->aToken) { HtmlFree(pText->aToken); } /* Make a temporary copy of the text and translate any embedded html * escape characters (i.e. " "). Todo: Avoid this copy by changing * populateTextNode() so that it deals with escapes. */ z2 = (char *)HtmlAlloc("temp", n + 1); memcpy(z2, z, n); z2[n] = '\0'; HtmlTranslateEscapes(z2); /* Figure out how much space is required for this HtmlTextNode. */ populateTextNode(strlen(z2), z2, 0, &nToken, &nText); assert(nText >= 0 && nToken > 0); /* Allocate space for HtmlTextNode.aToken and HtmlTextNode.zText */ nAlloc = nText + (nToken * sizeof(HtmlTextToken)); pText->aToken = (HtmlTextToken *)HtmlClearAlloc("TextNode.aToken", nAlloc); if (nText > 0) { pText->zText = (char *)&pText->aToken[nToken]; } else { /* If the node is all white-space, set HtmlTextNode.zText to NULL */ pText->zText = 0; } /* Populate the HtmlTextNode.aToken and zText arrays. */ populateTextNode(strlen(z2), z2, pText, 0, 0); HtmlFree(z2); assert(pText->aToken[nToken-1].eType == HTML_TEXT_TOKEN_END); pFinal = &pText->aToken[nToken-2]; if (isTrimEnd && pFinal->eType == HTML_TEXT_TOKEN_NEWLINE) { pFinal->n--; if( pFinal->n==0 ){ pFinal->eType = HTML_TEXT_TOKEN_END; nToken--; } } if (isTrimStart && pText->aToken[0].eType == HTML_TEXT_TOKEN_NEWLINE) { memmove(pText->aToken, &pText->aToken[1], sizeof(HtmlTextToken)*nToken); } #ifndef NDEBUG /* This assert() block checks the following: * * 1) If there is nothing but white-space in this node, then * HtmlTextNode.zText is set to NULL. * 2) If there are any text elements in the node HtmlTextNode.zText * is not set to NULL. * * In other words, the node is either white-space or not. This test is * included because I am paranoid the optimized HtmlNodeIsWhitespace() * test (pText->zText==0) will malfunction one day. */ if (1) { int haveText = 0; HtmlTextIter sIter; HtmlTextIterFirst(pText, &sIter); for ( ; HtmlTextIterIsValid(&sIter); HtmlTextIterNext(&sIter)) { if (HtmlTextIterType(&sIter) == HTML_TEXT_TOKEN_TEXT) { haveText = 1; } } assert( (!haveText && pText->zText == 0) || /* white-space */ (haveText && pText->zText) /* not white-space */ ); } #endif } HtmlTextNode * HtmlTextNew(n, z, isTrimEnd, isTrimStart) int n; const char *z; int isTrimEnd; int isTrimStart; { HtmlTextNode *pText; /* Allocate space for the HtmlTextNode. */ pText = HtmlNew(HtmlTextNode); HtmlTextSet(pText, n, z, isTrimEnd, isTrimStart); return pText; } /* *--------------------------------------------------------------------------- * * HtmlTextCombine -- * * Results: * * Side effects: * *--------------------------------------------------------------------------- */ #if 0 static HtmlTextNode * HtmlTextCombine(p1, p2) HtmlTextNode *p1; HtmlTextNode *p2; { /* HtmlTextNode *pNew; */ return 0; } #endif /* *--------------------------------------------------------------------------- * * HtmlTextFree -- * * Free a text-node structure allocated by HtmlTextNew(). * * Results: * None. * * Side effects: * Text-node p is deleted. * *--------------------------------------------------------------------------- */ void HtmlTextFree(p) HtmlTextNode *p; { HtmlFree(p); } void HtmlTextIterFirst(pTextNode, pTextIter) HtmlTextNode *pTextNode; HtmlTextIter *pTextIter; { pTextIter->pTextNode = pTextNode; pTextIter->iText = 0; pTextIter->iToken = 0; } int HtmlTextIterIsValid(pTextIter) HtmlTextIter *pTextIter; { HtmlTextToken *p = &pTextIter->pTextNode->aToken[pTextIter->iToken]; return (p->eType != HTML_TEXT_TOKEN_END) ? 1 : 0; } void HtmlTextIterNext(pTextIter) HtmlTextIter *pTextIter; { HtmlTextToken *p = &pTextIter->pTextNode->aToken[pTextIter->iToken]; int eType = p[0].eType; int eNext = p[1].eType; assert(eType != HTML_TEXT_TOKEN_END); if (eType == HTML_TEXT_TOKEN_TEXT) { pTextIter->iText += p->n; } else if (eType == HTML_TEXT_TOKEN_LONGTEXT) { int n = (p[0].n << 16) + (p[1].n << 8) + p[2].n; pTextIter->iText += n; pTextIter->iToken += 2; } if ((eType == HTML_TEXT_TOKEN_TEXT || eType == HTML_TEXT_TOKEN_LONGTEXT) && (eNext != HTML_TEXT_TOKEN_TEXT && eNext != HTML_TEXT_TOKEN_LONGTEXT) ) { pTextIter->iText++; } pTextIter->iToken++; } int HtmlTextIterIsLast(pTextIter) HtmlTextIter *pTextIter; { HtmlTextIter sIter; memcpy(&sIter, pTextIter, sizeof(HtmlTextIter)); HtmlTextIterNext(&sIter); return !HtmlTextIterIsValid(&sIter); } int HtmlTextIterType(pTextIter) HtmlTextIter *pTextIter; { HtmlTextToken *p = &pTextIter->pTextNode->aToken[pTextIter->iToken]; if (p->eType == HTML_TEXT_TOKEN_LONGTEXT) return HTML_TEXT_TOKEN_TEXT; return (int)(p->eType); } int HtmlTextIterLength(pTextIter) HtmlTextIter *pTextIter; { HtmlTextToken *p = &pTextIter->pTextNode->aToken[pTextIter->iToken]; if (p->eType == HTML_TEXT_TOKEN_LONGTEXT) { int n = (p[0].n << 16) + (p[1].n << 8) + p[2].n; return n; } return (int)(p->n); } const char * HtmlTextIterData(pTextIter) HtmlTextIter *pTextIter; { return (const char *)(&pTextIter->pTextNode->zText[pTextIter->iText]); } tkHTML-4ee7aaa953d6cb59/src/htmltree.c000064400000000000000000002703351151224263100167060ustar00nobodynobody/* * HtmlTree.c --- * * This file implements the tree structure that can be used to access * elements of an HTML document. * *-------------------------------------------------------------------------- * Copyright (c) 2005 Eolas Technologies Inc. * All rights reserved. * * This Open Source project was made possible through the financial support * of Eolas Technologies Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ static const char rcsid[] = "$Id: htmltree.c,v 1.161 2008/02/14 08:39:14 danielk1977 Exp $"; #include "html.h" #include "swproc.h" #include #include struct HtmlFragmentContext { HtmlNode *pRoot; HtmlElementNode *pCurrent; Tcl_Obj *pNodeList; }; /* * An HTML table is structured as follows: * *
    * * * * * Other, non-table, elements have a level of 0. * * Currently Tkhtml does not even parse and tags. When * this is fixed these two elements may need to be factored into the macro. */ #define TAG_TO_TABLELEVEL(eTag) ( \ (eTag==Html_TABLE) ? 4 : \ (eTag==Html_TBODY) ? 3 : \ (eTag==Html_THEAD) ? 3 : \ (eTag==Html_TFOOT) ? 3 : \ (eTag==Html_TR) ? 2 : \ (eTag==Html_TD) ? 1 : \ (eTag==Html_TH) ? 1 : 0 \ ) static void treeCloseFosterTree(HtmlTree *); /* *--------------------------------------------------------------------------- * * explicitCloseCount -- * * * Results: * Sets the value of *pNClose. * * Side effects: * None. * *--------------------------------------------------------------------------- */ static void explicitCloseCount(pCurrent, eTag, zTag, pNClose) HtmlNode *pCurrent; /* Node currently being constructed */ int eTag; /* Id of closing tag (i.e. "

    " -> Html_P) */ const char *zTag; /* Atom of closing tag */ int *pNClose; /* OUT: Number of elements to close */ { *pNClose = 0; if (eTag != Html_HTML && eTag != Html_BODY && eTag != Html_HEAD) { HtmlNode *p; int nLevel = 0; for (p = pCurrent; p; p = HtmlNodeParent(p)) { nLevel++; assert(zTag == p->zTag || stricmp(zTag, p->zTag)); if (zTag == p->zTag) { *pNClose = nLevel; break; } if ( TAG_TO_TABLELEVEL(p->eTag) && TAG_TO_TABLELEVEL(eTag) <= TAG_TO_TABLELEVEL(p->eTag) ) break; } } } static void implicitCloseCount(pTree, pCurrent, eTag, pNClose) HtmlTree *pTree; HtmlNode *pCurrent; int eTag; int *pNClose; { int nClose = 0; if (pCurrent) { int nLevel = 0; HtmlNode *p; int eCloseRes = TAG_PARENT; assert(HtmlNodeAsElement(pCurrent)); for (p = pCurrent; p && eCloseRes != TAG_OK; p = HtmlNodeParent(p)) { HtmlTokenMap *pMap = HtmlMarkup(HtmlNodeTagType(p)); nLevel++; if (pMap && pMap->xClose) { eCloseRes = pMap->xClose(pTree, p, eTag); assert( eCloseRes == TAG_CLOSE || eCloseRes == TAG_OK || eCloseRes == TAG_PARENT ); if (eCloseRes == TAG_CLOSE) { nClose = nLevel; } } } } *pNClose = nClose; } static void geomRequestProcCb(clientData) ClientData clientData; { HtmlNode *pNode = (HtmlNode *)clientData; HtmlTree *pTree = pNode->pNodeCmd->pTree; HtmlCallbackLayout(pTree, pNode); } static void geomRequestProc(clientData, widget) ClientData clientData; Tk_Window widget; { HtmlNode *pNode = (HtmlNode *)clientData; HtmlTree *pTree = pNode->pNodeCmd->pTree; if (!pTree->cb.inProgress) { HtmlCallbackLayout(pTree, pNode); } else { Tcl_DoWhenIdle(geomRequestProcCb, (ClientData)pNode); } } static void clearReplacement(pTree, pElem) HtmlTree *pTree; HtmlElementNode *pElem; { HtmlNodeReplacement *p = pElem->pReplacement; pElem->pReplacement = 0; if (p) { /* Cancel any idle callback scheduled by geomRequestProc() */ Tcl_CancelIdleCall(geomRequestProcCb, (ClientData)pElem); /* If there is a delete script, invoke it now. */ if (p->pDelete) { int flags = TCL_EVAL_DIRECT|TCL_EVAL_GLOBAL; Tcl_EvalObjEx(pTree->interp, p->pDelete, flags); } /* Remove any entry from the HtmlTree.pMapped list. */ if (p == pTree->pMapped) { pTree->pMapped = p->pNext; } else { HtmlNodeReplacement *pCur = pTree->pMapped; while( pCur && pCur->pNext != p ) pCur = pCur->pNext; if (pCur) { pCur->pNext = p->pNext; } } /* Cancel geometry management */ if (p->win) { if (Tk_IsMapped(p->win)) { Tk_UnmapWindow(p->win); } Tk_ManageGeometry(p->win, 0, 0); } /* Delete the Tcl_Obj's and the structure itself. */ if (p->pDelete) { Tcl_DecrRefCount(p->pDelete); } if (p->pReplace) { Tcl_DecrRefCount(p->pReplace); } if (p->pConfigureCmd) { Tcl_DecrRefCount(p->pConfigureCmd); } HtmlFree(p); } } int HtmlNodeClearStyle(pTree, pElem) HtmlTree *pTree; HtmlElementNode *pElem; { if (pElem) { HtmlNodeClearGenerated(pTree, pElem); HtmlComputedValuesRelease(pTree, pElem->pPropertyValues); HtmlComputedValuesRelease(pTree, pElem->pPreviousValues); HtmlCssInlineFree(pElem->pStyle); HtmlCssFreeDynamics(pElem); pElem->pStyle = 0; pElem->pPropertyValues = 0; pElem->pPreviousValues = 0; pElem->pDynamic = 0; HtmlDelStackingInfo(pTree, pElem); } return 0; } int HtmlNodeDeleteCommand(pTree, pNode) HtmlTree *pTree; HtmlNode *pNode; { if (pNode->pNodeCmd) { Tcl_Obj *pCommand = pNode->pNodeCmd->pCommand; Tcl_DeleteCommand(pTree->interp, Tcl_GetString(pCommand)); Tcl_DecrRefCount(pCommand); HtmlFree(pNode->pNodeCmd); pNode->pNodeCmd = 0; } return 0; } /* *--------------------------------------------------------------------------- * * freeNode -- * * Free the memory allocated for pNode and all of it's children. If the * node has attached style information, either from stylesheets or an * Html style attribute, this is deleted here too. * * Results: * None. * * Side effects: * pNode and children are made invalid. * *--------------------------------------------------------------------------- */ static void freeNode(pTree, pNode) HtmlTree *pTree; HtmlNode *pNode; { if( pNode ){ int i; /* Invalidate the cache of the parent node before deleting any * child nodes. This is because invalidating a cache may involve * deleting primitives that correspond to descendant nodes. In * general, primitives must be deleted before their owner nodes. */ HtmlLayoutInvalidateCache(pTree, pNode); if (!HtmlNodeIsText(pNode)) { /* Do HtmlElementNode specific destruction */ HtmlElementNode *pElem = (HtmlElementNode *)pNode; HtmlFree(pElem->pAttributes); /* Delete the computed values caches. */ HtmlNodeClearStyle(pTree, pElem); HtmlCssFreeDynamics(pElem); if (pElem->pOverride) { Tcl_DecrRefCount(pElem->pOverride); pElem->pOverride = 0; } /* Delete the descendant nodes. */ for(i=0; i < pElem->nChild; i++){ freeNode(pTree, pElem->apChildren[i]); } HtmlFree(pElem->apChildren); clearReplacement(pTree, pElem); HtmlDrawCanvasItemRelease(pTree, pElem->pBox); } else { HtmlTextNode *pTextNode = HtmlNodeAsText(pNode); assert(pTextNode); HtmlTagCleanupNode(pTextNode); HtmlFree(pTextNode->aToken); } /* Delete the computed values caches. */ HtmlDelScrollbars(pTree, pNode); HtmlNodeDeleteCommand(pTree, pNode); HtmlFree(pNode); } } int HtmlNodeClearGenerated(pTree, pElem) HtmlTree *pTree; HtmlElementNode *pElem; { assert(!pElem->pBefore || !HtmlNodeIsText(pElem->pBefore)); freeNode(pTree, pElem->pBefore); freeNode(pTree, pElem->pAfter); pElem->pBefore = 0; pElem->pAfter = 0; return 0; } static Tcl_Obj * nodeGetPreText(pTextNode) HtmlTextNode *pTextNode; { HtmlTextIter sIter; Tcl_Obj *pRet = Tcl_NewObj(); for ( HtmlTextIterFirst(pTextNode, &sIter); HtmlTextIterIsValid(&sIter); HtmlTextIterNext(&sIter) ) { char *zWhite = " "; int eType = HtmlTextIterType(&sIter); int nData = HtmlTextIterLength(&sIter); char const * zData = HtmlTextIterData(&sIter); switch (eType) { case HTML_TEXT_TOKEN_TEXT: Tcl_AppendToObj(pRet, zData, nData); break; case HTML_TEXT_TOKEN_NEWLINE: zWhite = "\n"; case HTML_TEXT_TOKEN_SPACE: { int ii; for (ii = 0; ii < nData; ii++) { Tcl_AppendToObj(pRet, zWhite, 1); } break; } } } return pRet; } /* *--------------------------------------------------------------------------- * * nodeRemoveChild -- * * If pChild is a child-node of pElem, then remove it from the * HtmlElementNode.apChildren[] array (so that it is no longer a * child). * * Results: * None. * * Side effects: * None. * *--------------------------------------------------------------------------- */ static int nodeRemoveChild(pElem, pChild) HtmlElementNode *pElem; HtmlNode *pChild; { int eSeen = 0; int ii; for (ii = 0; ii < pElem->nChild; ii++) { if (eSeen) { pElem->apChildren[ii - 1] = pElem->apChildren[ii]; } if (pElem->apChildren[ii] == pChild) { assert(pChild->pParent == (HtmlNode *)pElem); pChild->pParent = 0; eSeen = 1; } } if (eSeen) { pElem->nChild--; } return eSeen; } /* *--------------------------------------------------------------------------- * * HtmlElementNormalize -- * * This function normalizes the text children of element *pElem. * * Results: * None * * Side effects: * May combine two or more text-nodes into a single node. * *--------------------------------------------------------------------------- */ void HtmlElementNormalize(pElem) HtmlElementNode *pElem; { int ii; for (ii = 0; ii < (pElem->nChild - 1); ii++) { if ( HtmlNodeIsText(pElem->apChildren[ii]) && HtmlNodeIsText(pElem->apChildren[ii + 1]) ) { HtmlNode *pRemove = pElem->apChildren[ii + 1]; nodeRemoveChild(pElem, pRemove); /* TODO: Fold text from pRemove into pElem->apChildren[ii] */ HtmlTextFree(HtmlNodeAsText(pRemove)); ii--; } } } /* *--------------------------------------------------------------------------- * * nodeHandlerCallbacks -- * * This is called for every tree node by HtmlWalkTree() immediately * after the document tree is constructed. It calls the node handler * script for the node, if one exists. * * If the [$widget reset] method is called within the node-handler, * non-zero is returned. Otherwise 0. * * Results: * None. * * Side effects: * None. * *--------------------------------------------------------------------------- */ static int nodeHandlerCallbacks(pTree, pNode) HtmlTree *pTree; HtmlNode *pNode; { Tcl_HashEntry *pEntry; Tcl_Interp *interp = pTree->interp; int eTag = HtmlNodeTagType(pNode); int isFragment = (pTree->pFragment?1:0); /* If this is called as a result of a [parse] (not [fragment]) * command, this variable will be set to true if there is a node-handler * script and the script calls the [reset] method of this widget. */ assert(isFragment || pTree->eWriteState == HTML_WRITE_NONE); assert(isFragment || (eTag != Html_TD && eTag != Html_TH) || ( HtmlNodeParent(pNode) && HtmlNodeTagType(HtmlNodeParent(pNode)) == Html_TR ) ); if (!HtmlNodeIsText(pNode)) { /* HtmlElementNormalize(HtmlNodeAsElement(pNode)); */ } if (!isFragment && TAG_TO_TABLELEVEL(eTag) > 0) { treeCloseFosterTree(pTree); } /* Execute the node-handler script for node pNode, if one exists. */ pEntry = Tcl_FindHashEntry(&pTree->aNodeHandler, (char *)((size_t) eTag)); if (pEntry) { Tcl_Obj *pEval; Tcl_Obj *pScript; Tcl_Obj *pNodeCmd; int rc; pScript = (Tcl_Obj *)Tcl_GetHashValue(pEntry); pEval = Tcl_DuplicateObj(pScript); Tcl_IncrRefCount(pEval); if (!isFragment) { pTree->eWriteState = HTML_PARSE_NODEHANDLER; } pNodeCmd = HtmlNodeCommand(pTree, pNode); Tcl_ListObjAppendElement(0, pEval, pNodeCmd); rc = Tcl_EvalObjEx(interp, pEval, TCL_EVAL_DIRECT|TCL_EVAL_GLOBAL); if (rc != TCL_OK) { Tcl_BackgroundError(interp); } Tcl_DecrRefCount(pEval); assert( isFragment || pTree->eWriteState == HTML_PARSE_NODEHANDLER || pTree->eWriteState == HTML_WRITE_INHANDLERRESET ); if (!isFragment && pTree->eWriteState == HTML_PARSE_NODEHANDLER){ pTree->eWriteState = HTML_WRITE_NONE; } } return 0; } /* *--------------------------------------------------------------------------- * * HtmlFinishNodeHandlers -- * * Execute any outstanding node-handler callbacks. This is used when * the end of a document is reached - the EOF implicitly closes all * open nodes. This function executes node-handler scripts for nodes * closed in such a fashion. * * Results: * None. * * Side effects: * None. * *--------------------------------------------------------------------------- */ void HtmlFinishNodeHandlers(pTree) HtmlTree *pTree; { HtmlNode *p; for (p = pTree->state.pCurrent ; p; p = HtmlNodeParent(p)) { nodeHandlerCallbacks(pTree, p); } pTree->state.pCurrent = 0; } int HtmlNodeIsOrphan(pNode) HtmlNode *pNode; { while (pNode && pNode->iNode != HTML_NODE_ORPHAN) { pNode = HtmlNodeParent(pNode); } return (pNode ? 1 : 0); } /* *--------------------------------------------------------------------------- * * nodeOrphanize -- * nodeDeorphanize -- * * Mark a node as an orphan, or unmark it. All nodes marked as orphans * are stored in the HtmlTree.aOrphan hash table and have HtmlNode.iNode * set to HTML_NODE_ORPHAN. * * Results: * None. * * Side effects: * None. * *--------------------------------------------------------------------------- */ static void nodeOrphanize(pTree, pNode) HtmlTree *pTree; HtmlNode *pNode; { int eNew; assert( pNode->iNode != HTML_NODE_ORPHAN || pNode == pTree->pFragment->pRoot ); pNode->iNode = HTML_NODE_ORPHAN; pNode->pParent = 0; Tcl_CreateHashEntry(&pTree->aOrphan, (const char *)pNode, &eNew); assert(eNew); } static void nodeDeorphanize(pTree, pNode) HtmlTree *pTree; HtmlNode *pNode; { Tcl_HashEntry *pEntry; assert(pNode->iNode == HTML_NODE_ORPHAN); pNode->iNode = 0; pEntry = Tcl_FindHashEntry(&pTree->aOrphan, (const char *)pNode); assert(pEntry); Tcl_DeleteHashEntry(pEntry); } int HtmlNodeIndexOfChild(pParent, pChild) HtmlNode *pParent; HtmlNode *pChild; { int ii; for (ii = 0; ii < HtmlNodeNumChildren(pParent); ii++) { if (HtmlNodeChild(pParent, ii) == pChild) return ii; } return -1; } static void nodeInsertChild(pTree, pElem, pBefore, pAfter, pChild) HtmlTree *pTree; HtmlElementNode *pElem; HtmlNode *pBefore; HtmlNode *pAfter; HtmlNode *pChild; { int n; /* Number of bytes to alloc for pNode->apChildren */ int ii; int iBefore; assert(pBefore == 0 || pAfter == 0); assert(pChild); if (pChild == pBefore || pChild == pAfter) { assert(HtmlNodeParent(pChild) == (HtmlNode *)pElem); return; } /* Unlink pChild from it's parent node. */ if (HtmlNodeParent(pChild)) { HtmlNode *pParent = HtmlNodeParent(pChild); /* Before removing a child, invalidate the layout of the parent */ HtmlCallbackLayout(pTree, pChild); /* Clear all the style and layout information cached in the * sub-tree rooted at the child node. At present anything * moved to the orphan tree has all style/layout info cleared. */ HtmlNodeClearRecursive(pTree, pChild); nodeRemoveChild(HtmlNodeAsElement(pParent), pChild); } if (pBefore) { iBefore = HtmlNodeIndexOfChild((HtmlNode *)pElem, pBefore); assert(iBefore>=0); } else if (pAfter) { iBefore = HtmlNodeIndexOfChild((HtmlNode *)pElem, pAfter); assert(iBefore>=0); iBefore++; } else { iBefore = pElem->nChild; } /* Extend the size of the HtmlElementNode.apChildren[] array */ assert(pElem); pElem->nChild++; n = (pElem->nChild) * sizeof(HtmlNode*); pElem->apChildren = (HtmlNode **)HtmlRealloc( "HtmlNode.apChildren", (char *)pElem->apChildren, n ); for (ii = (pElem->nChild - 1); ii > iBefore; ii--) { pElem->apChildren[ii] = pElem->apChildren[ii - 1]; } pElem->apChildren[iBefore] = pChild; /* Link pChild into the new parent node */ pChild->pParent = (HtmlNode *)pElem; } /* *--------------------------------------------------------------------------- * * HtmlNodeAddChild -- * * Add a new child node to node pNode. pToken becomes the starting * token for the new node. The value returned is the index of the new * child. So the call: * * HtmlNodeChild(pNode, HtmlNodeAddChild(pNode, pToken)) * * returns the new child node. * * Results: * Index of the child added to pNode. * * Side effects: * None. * *--------------------------------------------------------------------------- */ int HtmlNodeAddChild(pElem, eTag, zTag, pAttributes) HtmlElementNode *pElem; int eTag; const char *zTag; /* Atom for tag name */ HtmlAttributes *pAttributes; { int n; /* Number of bytes to alloc for pNode->apChildren */ int r; /* Return value */ HtmlElementNode *pNew; /* New child node */ assert(pElem); r = pElem->nChild++; n = (r+1) * sizeof(HtmlNode*); pElem->apChildren = (HtmlNode **)HtmlRealloc( "HtmlNode.apChildren", (char *)pElem->apChildren, n ); if (!zTag) { zTag = HtmlTypeToName(0, eTag); } assert(zTag); pNew = HtmlNew(HtmlElementNode); pNew->pAttributes = pAttributes; pNew->node.pParent = (HtmlNode *)pElem; pNew->node.eTag = eTag; pNew->node.zTag = zTag; pElem->apChildren[r] = (HtmlNode *)pNew; assert(r < pElem->nChild); return r; } int HtmlNodeAddTextChild(pNode, pTextNode) HtmlNode *pNode; HtmlTextNode *pTextNode; { int n; /* Number of bytes to alloc for pNode->apChildren */ int r; /* Return value */ HtmlNode *pNew; /* New child node */ HtmlElementNode *pElem = HtmlNodeAsElement(pNode); assert(pElem); assert(pTextNode); r = pElem->nChild++; n = (r+1) * sizeof(HtmlNode*); pElem->apChildren = (HtmlNode **)HtmlRealloc( "HtmlNode.apChildren", (char *)pElem->apChildren, n ); pNew = (HtmlNode *)pTextNode; memset(pNew, 0, sizeof(HtmlNode)); pNew->pParent = pNode; pNew->eTag = Html_Text; pElem->apChildren[r] = pNew; assert(r < pElem->nChild); return r; } /* *--------------------------------------------------------------------------- * * setNodeAttribute -- * * Set the value of an attribute on a node. This function is currently * a bit inefficient, due to the way the HtmlToken structure is * allocated. * * Results: * None * * Side effects: * Modifies the HtmlToken structure associated with the specified node. * *--------------------------------------------------------------------------- */ static void setNodeAttribute(pNode, zAttrName, zAttrVal) HtmlNode *pNode; const char *zAttrName; const char *zAttrVal; { #define MAX_NUM_ATTRIBUTES 100 char const *azPtr[MAX_NUM_ATTRIBUTES * 2]; int aLen[MAX_NUM_ATTRIBUTES * 2]; int i; int isDone = 0; int nArgs; HtmlElementNode *pElem; HtmlAttributes *pAttr; pElem = HtmlNodeAsElement(pNode); if (!pElem) return; pAttr = pElem->pAttributes; for (i = 0; pAttr && i < pAttr->nAttr && i < MAX_NUM_ATTRIBUTES; i++) { azPtr[i*2] = pAttr->a[i].zName; if (0 != strcmp(pAttr->a[i].zName, zAttrName)) { azPtr[i*2+1] = pAttr->a[i].zValue; } else { azPtr[i*2+1] = zAttrVal; isDone = 1; } } if (!isDone && i < MAX_NUM_ATTRIBUTES) { azPtr[i*2] = zAttrName; azPtr[i*2+1] = zAttrVal; i++; } nArgs = i * 2; for (i = 0; i < nArgs; i++) { aLen[i] = strlen(azPtr[i]); } pElem->pAttributes = HtmlAttributesNew(nArgs, azPtr, aLen, 0); HtmlFree(pAttr); /* If this was a call to set the "style" attribute, discard the * compiled version at version HtmlElementNode.pStyle. */ if (strcmp(HTML_INLINE_STYLE_ATTR, zAttrName) == 0) { HtmlCssInlineFree(pElem->pStyle); pElem->pStyle = 0; } } static void mergeAttributes(pNode, pAttr) HtmlNode *pNode; HtmlAttributes *pAttr; { int ii; for (ii = 0; pAttr && ii < pAttr->nAttr; ii++) { setNodeAttribute(pNode, pAttr->a[ii].zName, pAttr->a[ii].zValue); } HtmlFree(pAttr); } static int doAttributeHandler(pTree, pNode, zAttr, zValue) HtmlTree *pTree; HtmlNode *pNode; const char *zAttr; const char *zValue; { int rc = TCL_OK; int eType = pNode->eTag; Tcl_HashEntry *pEntry; pEntry = Tcl_FindHashEntry(&pTree->aAttributeHandler, (char*)((size_t) eType)); if (pEntry) { Tcl_Obj *pScript; pScript = (Tcl_Obj *)Tcl_GetHashValue(pEntry); pScript = Tcl_DuplicateObj(pScript); Tcl_IncrRefCount(pScript); Tcl_ListObjAppendElement(0, pScript, HtmlNodeCommand(pTree, pNode)); Tcl_ListObjAppendElement(0, pScript, Tcl_NewStringObj(zAttr, -1)); Tcl_ListObjAppendElement(0, pScript, Tcl_NewStringObj(zValue, -1)); rc = Tcl_EvalObjEx(pTree->interp, pScript, TCL_EVAL_GLOBAL); Tcl_DecrRefCount(pScript); } return rc; } static int doParseHandler(pTree, eType, pNode, iOffset) HtmlTree *pTree; int eType; HtmlNode *pNode; int iOffset; { int rc = TCL_OK; Tcl_HashEntry *pEntry; if (iOffset < 0) return TCL_OK; if (eType == Html_Space) { eType = Html_Text; } pEntry = Tcl_FindHashEntry(&pTree->aParseHandler, (char *)((size_t) eType)); if (pEntry) { Tcl_Obj *pScript; pScript = (Tcl_Obj *)Tcl_GetHashValue(pEntry); pScript = Tcl_DuplicateObj(pScript); Tcl_IncrRefCount(pScript); if (pNode) { Tcl_ListObjAppendElement(0, pScript, HtmlNodeCommand(pTree, pNode)); } else { Tcl_ListObjAppendElement(0, pScript, Tcl_NewStringObj("", -1)); } Tcl_ListObjAppendElement( 0, pScript, Tcl_NewIntObj(iOffset + pTree->nParsed) ); rc = Tcl_EvalObjEx(pTree->interp, pScript, TCL_EVAL_GLOBAL); Tcl_DecrRefCount(pScript); } return rc; } /* *--------------------------------------------------------------------------- * * HtmlInitTree -- * * Create the parts of the tree that are always present. i.e.: * * * * * * Results: * None. * * Side effects: * May modify the tree structure at HtmlTree.pRoot and * HtmlTree.pCurrent. * *--------------------------------------------------------------------------- */ void HtmlInitTree(pTree) HtmlTree *pTree; { if (!pTree->pRoot) { /* If pTree->pRoot is NULL, then the first token of the document * has just been parsed. If the document is well-formed, it should * be an tag (Html documents may have a DOCTYPE and other such * garbage in them, but the tokenizer should ignore all that). * * But in these uncertain times you really can't trust anyone, so * Tkhtml automatically inserts the following structure at the root * of every document: * * * * * */ HtmlElementNode *pRoot; pRoot = HtmlNew(HtmlElementNode); pRoot->node.eTag = Html_HTML; pRoot->node.zTag = HtmlTypeToName(pTree, Html_HTML); pTree->pRoot = (HtmlNode *)pRoot; HtmlNodeAddChild(pRoot, Html_HEAD, HtmlTypeToName(pTree, Html_HEAD), 0); HtmlNodeAddChild(pRoot, Html_BODY, HtmlTypeToName(pTree, Html_BODY), 0); HtmlCallbackRestyle(pTree, (HtmlNode *)pRoot); } if (!pTree->state.pCurrent) { /* If there is no current node, then the node of the * document is the current node. */ pTree->state.pCurrent = HtmlNodeChild(pTree->pRoot, 1); assert(HtmlNodeTagType(pTree->state.pCurrent) == Html_BODY); } } static HtmlNode * findFosterParent(pTree, ppTable) HtmlTree *pTree; HtmlNode **ppTable; { HtmlNode *pFosterParent; HtmlNode *pTable; /* Find the parent of the
    element (the foster-parent) */ for ( pTable = pTree->state.pCurrent; HtmlNodeTagType(pTable) != Html_TABLE; pTable = HtmlNodeParent(pTable) ); pFosterParent = HtmlNodeParent(pTable); assert(pFosterParent); if (ppTable) { *ppTable = pTable; } return pFosterParent; } static void treeCloseFosterTree(pTree) HtmlTree *pTree; { if (pTree->state.pFoster) { HtmlNode *pFosterRoot = findFosterParent(pTree, 0); HtmlNode *pFoster; pFoster = pTree->state.pFoster; for ( ;pFoster != pFosterRoot; pFoster = HtmlNodeParent(pFoster)) { nodeHandlerCallbacks(pTree, pFoster); } pTree->state.pFoster = 0; } } static void treeAddFosterText(pTree, pTextNode) HtmlTree *pTree; HtmlTextNode *pTextNode; { if (pTree->state.pFoster) { HtmlNodeAddTextChild(pTree->state.pFoster, pTextNode); } else { HtmlNode *pFosterParent; HtmlNode *pBefore = 0; pFosterParent = findFosterParent(pTree, &pBefore); nodeInsertChild(pTree, (HtmlElementNode *)pFosterParent, pBefore, 0, (HtmlNode *)pTextNode ); } } HtmlNode * treeAddFosterElement(pTree, eTag, zTag, pAttr) HtmlTree *pTree; int eTag; const char *zTag; /* Atom for tag */ HtmlAttributes *pAttr; { HtmlNode *pFosterParent; HtmlNode *pNew; HtmlNode *pFoster = pTree->state.pFoster; HtmlNode *pBefore = 0; /* Find the parent of the
    element (the foster-parent) */ pFosterParent = findFosterParent(pTree, &pBefore); if (pFoster) { int nClose; int ii; implicitCloseCount(pTree, pTree->state.pFoster, eTag, &nClose); for ( ii = 0; ii < nClose && pFoster != pFosterParent; pFoster = HtmlNodeParent(pFoster) ) { nodeHandlerCallbacks(pTree, pFoster); } if (pFoster == pFosterParent) pFoster = 0; } if (pFoster) { int n = HtmlNodeAddChild((HtmlElementNode *)pFoster, eTag, zTag, pAttr); pNew = HtmlNodeChild(pFoster, n); } else { pNew = (HtmlNode *)HtmlNew(HtmlElementNode); ((HtmlElementNode *)pNew)->pAttributes = pAttr; pNew->eTag = eTag; if (!zTag) { zTag = HtmlTypeToName(0, eTag); } pNew->zTag = zTag; nodeInsertChild(pTree, (HtmlElementNode *)pFosterParent,pBefore,0,pNew); } pNew->iNode = pTree->iNextNode++; if (HtmlMarkupFlags(eTag) & HTMLTAG_EMPTY) { nodeHandlerCallbacks(pTree, pNew); pTree->state.pFoster = HtmlNodeParent(pNew); if (pTree->state.pFoster == pFosterParent) pTree->state.pFoster = 0; } else { pTree->state.pFoster = pNew; } HtmlCallbackRestyle(pTree, pNew); return pNew; } static void treeAddFosterClosingTag(pTree, eTag, zTag) HtmlTree *pTree; int eTag; const char *zTag; { HtmlNode *pFosterParent; HtmlNode *pFoster; int ii; int nClose; /* Find the parent of the
    element (the foster-parent) */ pFosterParent = findFosterParent(pTree, 0); assert(pFosterParent); explicitCloseCount(pTree->state.pFoster, eTag, zTag, &nClose); pFoster = pTree->state.pFoster; for (ii = 0; ii < nClose && pFoster != pFosterParent; ii++) { nodeHandlerCallbacks(pTree, pFoster); pFoster = HtmlNodeParent(pFoster); } if (pFoster == pFosterParent) { pFoster = 0; } pTree->state.pFoster = pFoster; } static HtmlNode * treeAddTableComponent(pTree, eTag, pAttr) HtmlTree *pTree; int eTag; HtmlAttributes *pAttr; { HtmlNode *pCurrent = pTree->state.pCurrent; HtmlNode *pParent; int eParentTag; /* The newly created document node */ HtmlNode *pNew; int n; for (pParent = pCurrent; pParent; pParent = HtmlNodeParent(pParent)) { int eCTag = HtmlNodeTagType(pParent); if ( (eCTag == Html_TABLE) || ( (eCTag==Html_TBODY || eCTag==Html_THEAD || eCTag==Html_TFOOT) && (eTag==Html_TH || eTag==Html_TD || eTag==Html_TR) ) || (eCTag == Html_TR && (eTag == Html_TD || eTag == Html_TH)) ) break; } if (!pParent) { HtmlFree(pAttr); return pParent; } eParentTag = HtmlNodeTagType(pParent); /* Invoke node-handler callbacks for implicitly closed nodes */ for ( ; pCurrent != pParent ; pCurrent = HtmlNodeParent(pCurrent)) { nodeHandlerCallbacks(pTree, pCurrent); } treeCloseFosterTree(pTree); assert( eParentTag == Html_TABLE || eParentTag == Html_TBODY || eParentTag == Html_THEAD || eParentTag == Html_TFOOT || eParentTag == Html_TR ); /* See if we need to add an implicit node */ if ( eParentTag == Html_TABLE && (eTag == Html_TR || eTag == Html_TD || eTag == Html_TH) ) { int n2 = HtmlNodeAddChild((HtmlElementNode *)pParent, Html_TBODY, 0, 0); pParent = HtmlNodeChild(pParent, n2); pParent->iNode = pTree->iNextNode++; eParentTag = Html_TBODY; } /* See if we need to add an implicit node */ if (eParentTag != Html_TR && (eTag == Html_TD || eTag == Html_TH)) { int n2 = HtmlNodeAddChild((HtmlElementNode *)pParent, Html_TR, 0, 0); pParent = HtmlNodeChild(pParent, n2); pParent->iNode = pTree->iNextNode++; eParentTag = Html_TR; } /* Add the new node to pParent */ n = HtmlNodeAddChild((HtmlElementNode *)pParent, eTag, 0, pAttr); pNew = HtmlNodeChild(pParent, n); pNew->iNode = pTree->iNextNode++; pTree->state.pCurrent = pNew; /* Return a pointer to the node just added */ return pNew; } /* *--------------------------------------------------------------------------- * * HtmlTreeAddElement -- * * Update the tree structure with an element of type eType, attributes * as specified in *pAttr. * * Results: * None. * * Side effects: * May modify the tree structure at HtmlTree.pRoot and * HtmlTree.pCurrent. * *--------------------------------------------------------------------------- */ void HtmlTreeAddElement(pTree, eType, zType, pAttr, iOffset) HtmlTree *pTree; int eType; const char *zType; HtmlAttributes *pAttr; int iOffset; { HtmlNode *pCurrent; HtmlNode *pHeadNode; HtmlNode *pBodyNode; HtmlElementNode *pHeadElem; /* If token pToken causes a node to be added to the tree, or the * attributes of an , or element to be updated, * this variable is set to point to the node. At the end of this * function, it is used as an argument to any registered * [$widget handler parse] callback script. */ HtmlNode *pParsed = 0; /* Initialise the tree and find the and elements */ HtmlInitTree(pTree); pHeadNode = HtmlNodeChild(pTree->pRoot, 0); pBodyNode = HtmlNodeChild(pTree->pRoot, 1); pHeadElem = HtmlNodeAsElement(pHeadNode); pCurrent = pTree->state.pCurrent; assert(pCurrent); assert(pHeadNode); assert(eType != Html_Text && eType != Html_Space); /* If the HtmlTreeState.isCdataInHead flag is true, then the previous * token parsed was (generally: a token that generates an * element in the <HEAD> section with #CDATA content). Close the * element before proceeding. */ if (pTree->state.isCdataInHead) { int nChild = HtmlNodeNumChildren(pHeadNode) - 1; HtmlNode *pTitle = HtmlNodeChild(pHeadNode, nChild); nodeHandlerCallbacks(pTree, pTitle); } pTree->state.isCdataInHead = 0; switch (eType) { case Html_HTML: pParsed = pTree->pRoot; mergeAttributes(pParsed, pAttr); HtmlCallbackRestyle(pTree, pParsed); break; case Html_HEAD: pParsed = pHeadNode; mergeAttributes(pParsed, pAttr); HtmlCallbackRestyle(pTree, pParsed); break; case Html_BODY: pParsed = pBodyNode; mergeAttributes(pParsed, pAttr); HtmlCallbackRestyle(pTree, pParsed); break; /* Elements with content #CDATA for the document head. * * Todo: Technically, we should be worried about <script> and * <style> elements in the document head too, but in practice it * makes little difference where these wind up. <script> is * a bit tricky as this can appear in either the <head> or <body> * section. */ case Html_TITLE: { int n = HtmlNodeAddChild(pHeadElem, eType, 0, pAttr); HtmlNode *p = HtmlNodeChild(pHeadNode, n); pTree->state.isCdataInHead = 1; p->iNode = pTree->iNextNode++; pParsed = p; HtmlCallbackRestyle(pTree, pParsed); break; } /* Self-closing elements to add to the document head */ case Html_META: case Html_LINK: case Html_BASE: { int n = HtmlNodeAddChild(pHeadElem, eType, 0, pAttr); HtmlNode *p = HtmlNodeChild(pHeadNode, n); p->iNode = pTree->iNextNode++; nodeHandlerCallbacks(pTree, p); if (pTree->eWriteState != HTML_WRITE_INHANDLERRESET) { pParsed = p; HtmlCallbackRestyle(pTree, pParsed); } break; } /* Elements that form part of <TABLE> structures. Special * rules apply to these so they are handled seperately. */ case Html_TBODY: case Html_TFOOT: case Html_THEAD: case Html_TR: case Html_TD: case Html_TH: { pParsed = treeAddTableComponent(pTree, eType, pAttr); break; } default: { int eCurrentType = HtmlNodeTagType(pCurrent); int isTableType = (( eCurrentType == Html_TABLE || eCurrentType == Html_TBODY || eCurrentType == Html_TFOOT || eCurrentType == Html_THEAD || eCurrentType == Html_TR ) ? 1 : 0); if (isTableType && eType != Html_FORM) { /* Need to add this node to the foster tree. */ pParsed = treeAddFosterElement(pTree, eType, zType, pAttr); } else { /* Add this node to pCurrent. */ int nClose = 0; int i; HtmlElementNode *pC; int N; implicitCloseCount(pTree, pCurrent, eType, &nClose); for (i = 0; i < nClose && pCurrent != pBodyNode; i++) { nodeHandlerCallbacks(pTree, pCurrent); pCurrent = HtmlNodeParent(pCurrent); } pTree->state.pCurrent = pCurrent; pC = HtmlNodeAsElement(pCurrent); assert(!HtmlNodeIsText(pTree->state.pCurrent)); N = HtmlNodeAddChild(pC, eType, zType, pAttr); pCurrent = HtmlNodeChild(pCurrent, N); pCurrent->iNode = pTree->iNextNode++; pParsed = pCurrent; assert(!isTableType || eType == Html_FORM); if ((HtmlMarkupFlags(eType) & HTMLTAG_EMPTY) || isTableType) { nodeHandlerCallbacks(pTree, pCurrent); pCurrent = HtmlNodeParent(pCurrent); } pTree->state.pCurrent = pCurrent; } } } if (pParsed) { if (HtmlNodeComputedValues(pParsed)) { HtmlCallbackRestyle(pTree, pParsed); } doParseHandler(pTree, eType, pParsed, iOffset); } } /* *--------------------------------------------------------------------------- * * HtmlTreeAddText -- * * Add the text-node pTextNode to the tree. * * Results: * None. * * Side effects: * None. * *--------------------------------------------------------------------------- */ void HtmlTreeAddText(pTree, pTextNode, iOffset) HtmlTree *pTree; HtmlTextNode *pTextNode; int iOffset; { HtmlNode *pCurrent; int eCurrentType; HtmlInitTree(pTree); pCurrent = pTree->state.pCurrent; eCurrentType = HtmlNodeTagType(pCurrent); if (pTree->state.isCdataInHead) { HtmlNode *pHeadNode = HtmlNodeChild(pTree->pRoot, 0); int nChild = HtmlNodeNumChildren(pHeadNode) - 1; HtmlNode *pTitle = HtmlNodeChild(pHeadNode, nChild); HtmlNodeAddTextChild(pTitle, pTextNode); pTextNode->node.iNode = pTree->iNextNode++; pTree->state.isCdataInHead = 0; nodeHandlerCallbacks(pTree, pTitle); } else if ( eCurrentType == Html_TABLE || eCurrentType == Html_TBODY || eCurrentType == Html_TFOOT || eCurrentType == Html_THEAD || eCurrentType == Html_TR ) { treeAddFosterText(pTree, pTextNode); pTextNode->node.iNode = pTree->iNextNode++; pTextNode->node.eTag = Html_Text; } else { HtmlNodeAddTextChild(pCurrent, pTextNode); pTextNode->node.iNode = pTree->iNextNode++; } assert(pTextNode->node.eTag == Html_Text); doParseHandler(pTree, Html_Text, (HtmlNode *)pTextNode, iOffset); } /* *--------------------------------------------------------------------------- * * HtmlTreeAddClosingTag -- * * Process the closing tag eTag. * * This method is prefixed "HtmlTreeAdd" to match HtmlTreeAddText() * and HtmlTreeAddElement(), the other two functions used by the * document parser to build the tree. * * Results: * None. * * Side effects: * None. * *--------------------------------------------------------------------------- */ void HtmlTreeAddClosingTag(pTree, eTag, zTag, iOffset) HtmlTree *pTree; int eTag; const char *zTag; int iOffset; { int nClose; int ii; HtmlInitTree(pTree); if (pTree->state.pFoster && 0 == TAG_TO_TABLELEVEL(eTag)) { assert(TAG_TO_TABLELEVEL(HtmlNodeTagType(pTree->state.pCurrent)) > 0); treeAddFosterClosingTag(pTree, eTag, zTag); } else { HtmlNode *pBody = HtmlNodeChild(pTree->pRoot, 1); explicitCloseCount(pTree->state.pCurrent, eTag, zTag, &nClose); for (ii = 0; ii < nClose && pTree->state.pCurrent != pBody; ii++) { nodeHandlerCallbacks(pTree, pTree->state.pCurrent); pTree->state.pCurrent = HtmlNodeParent(pTree->state.pCurrent); } } doParseHandler(pTree, -1 * eTag, 0, iOffset); } /* *--------------------------------------------------------------------------- * * walkTree -- * * Results: * None. * * Side effects: * None. * *--------------------------------------------------------------------------- */ static int walkTree(pTree, xCallback, pNode, clientData) HtmlTree *pTree; int (*xCallback)(HtmlTree *, HtmlNode *, ClientData clientData); HtmlNode *pNode; ClientData clientData; { int i; if( pNode ){ int rc = xCallback(pTree, pNode, clientData); switch (rc) { case HTML_WALK_ABANDON: return 1; case HTML_WALK_DESCEND: break; case HTML_WALK_DO_NOT_DESCEND: return 0; default: assert(!"Bad return value from HtmlWalkTree() callback"); } for (i = 0; i < HtmlNodeNumChildren(pNode); i++) { HtmlNode *pChild = HtmlNodeChild(pNode, i); int rc = walkTree(pTree, xCallback, pChild, clientData); assert(HtmlNodeParent(pChild) == pNode); if (rc) return rc; } } return 0; } /* *--------------------------------------------------------------------------- * * HtmlWalkTree -- * * Traverse the subset of document tree pTree rooted at pNode. If pNode is * NULL the entire tree is traversed. This function does a pre-order or * prefix traversal (each node is visited before it's children). * * When a node is visited the supplied callback function is invoked. The * callback function must return one of the following three hash * defined values: * * HTML_WALK_DESCEND * HTML_WALK_DO_NOT_DESCEND * HTML_WALK_ABANDON * * Results: * None. * * Side effects: * None. * *--------------------------------------------------------------------------- */ int HtmlWalkTree(pTree, pNode, xCallback, clientData) HtmlTree *pTree; HtmlNode *pNode; int (*xCallback)(HtmlTree *, HtmlNode *, ClientData clientData); ClientData clientData; { return walkTree(pTree, xCallback, pNode?pNode:pTree->pRoot, clientData); } /* *--------------------------------------------------------------------------- * * HtmlNodeNumChildren -- * * * Results: * None. * * Side effects: * None. * *--------------------------------------------------------------------------- */ int HtmlNodeNumChildren(pNode) HtmlNode *pNode; { if (HtmlNodeIsText(pNode)) return 0; return ((HtmlElementNode *)(pNode))->nChild; } /* *--------------------------------------------------------------------------- * * HtmlNodeChild -- * * Results: * None. * * Side effects: * None. * *--------------------------------------------------------------------------- */ #if 0 HtmlNode * HtmlNodeChild(pNode, n) HtmlNode *pNode; int n; { HtmlElementNode *pElem = (HtmlElementNode *)pNode; if (!pNode || HtmlNodeIsText(pNode) || pElem->nChild <= n) return 0; return pElem->apChildren[n]; } #endif /* *--------------------------------------------------------------------------- * * HtmlNodeBefore -- * * Results: * None. * * Side effects: * None. * *--------------------------------------------------------------------------- */ HtmlNode * HtmlNodeBefore(pNode) HtmlNode *pNode; { if (!HtmlNodeIsText(pNode)) { return ((HtmlElementNode *)pNode)->pBefore; } return 0; } #if 0 HtmlComputedValues * HtmlNodeComputedValues(pNode) HtmlNode *pNode; { if (HtmlNodeIsText(pNode)) { pNode = HtmlNodeParent(pNode); } if (pNode) { return ((HtmlElementNode *)pNode)->pPropertyValues; } return 0; } #endif /* *--------------------------------------------------------------------------- * * HtmlNodeAfter -- * * Results: * None. * * Side effects: * None. * *--------------------------------------------------------------------------- */ HtmlNode * HtmlNodeAfter(pNode) HtmlNode *pNode; { if (!HtmlNodeIsText(pNode)) { return ((HtmlElementNode *)pNode)->pAfter; } return 0; } /* *--------------------------------------------------------------------------- * * HtmlNodeTagType -- * * Return the tag-type of the node, i.e. Html_P, Html_Text or * Html_Space. * * Results: * Integer tag type. * * Side effects: * None. * *--------------------------------------------------------------------------- */ Html_u8 HtmlNodeTagType(pNode) HtmlNode *pNode; { assert(pNode); return pNode->eTag; } /* *--------------------------------------------------------------------------- * * HtmlNodeTagName -- * * Return the name of the tag-type of the node, i.e. "p", "text" or * "div". * * Results: * Boolean. * * Side effects: * None. * *--------------------------------------------------------------------------- */ CONST char * HtmlNodeTagName(pNode) HtmlNode *pNode; { assert(pNode->zTag || HtmlNodeIsText(pNode)); if (!pNode->zTag) return ""; return pNode->zTag; } /* *--------------------------------------------------------------------------- * * HtmlNodeRightSibling -- * * Get the right-hand sibling to a node, if it has one. * * Results: * None. * * Side effects: * None. * *--------------------------------------------------------------------------- */ HtmlNode *HtmlNodeRightSibling(pNode) HtmlNode *pNode; { HtmlElementNode *pParent = (HtmlElementNode *)pNode->pParent; if( pParent ){ int i; for (i=0; i < pParent->nChild - 1; i++) { if (pNode == pParent->apChildren[i]) { return pParent->apChildren[i+1]; } } assert(pNode == pParent->apChildren[pParent->nChild - 1]); } return 0; } /* *--------------------------------------------------------------------------- * * HtmlNodeLeftSibling -- * * Get the left-hand sibling to a node, if it has one. * * Results: * None. * * Side effects: * None. * *--------------------------------------------------------------------------- */ HtmlNode *HtmlNodeLeftSibling(pNode) HtmlNode *pNode; { HtmlElementNode *pParent = (HtmlElementNode *)pNode->pParent; if( pParent ){ int i; for (i = 1; i < pParent->nChild; i++) { if (pNode == pParent->apChildren[i]) { return pParent->apChildren[i-1]; } } assert(pNode == pParent->apChildren[0]); } return 0; } /* *--------------------------------------------------------------------------- * * HtmlNodeAttr -- * * Return a pointer to the value of node attribute zAttr. Attributes * are always represented as NULL-terminated strings. * * Results: * None. * * Side effects: * None. * *--------------------------------------------------------------------------- */ char CONST *HtmlNodeAttr(pNode, zAttr) HtmlNode *pNode; char CONST *zAttr; { HtmlElementNode *pElem = HtmlNodeAsElement(pNode); if (pElem) { return HtmlMarkupArg(pElem->pAttributes, zAttr, 0); } return 0; } static int markWindowAsClipped(pTree, pNode, clientData) HtmlTree *pTree; HtmlNode *pNode; ClientData clientData; { if (!HtmlNodeIsText(pNode)) { HtmlNodeReplacement *p = ((HtmlElementNode *)pNode)->pReplacement; if (p) { p->clipped = 1; } } return HTML_WALK_DESCEND; } /* *--------------------------------------------------------------------------- * * nodeViewCmd -- * * This function implements the Tcl commands: * * [nodeHandle yview] * [nodeHandle xview] * * used to scroll boxes generated by tree elements with "overflow:auto" * or "overflow:scroll". At present, the implementation of this is * not very efficient. * * Results: * None. * * Side effects: * None. * *--------------------------------------------------------------------------- */ static int nodeViewCmd(pNode, isVertical, objv, objc) HtmlNode *pNode; int isVertical; Tcl_Obj *CONST objv[]; int objc; { HtmlTree *pTree; int eType; /* One of the TK_SCROLL_ symbols */ double fraction; int count; int iNew; int iMax; int iSize; int iIncr; int x, y, w, h; HtmlElementNode *pElem = (HtmlElementNode *)pNode; if (HtmlNodeIsText(pNode) || !pElem->pScrollbar) { return TCL_ERROR; } pTree = pNode->pNodeCmd->pTree; if (isVertical) { iNew = pElem->pScrollbar->iVertical; iMax = pElem->pScrollbar->iVerticalMax; iSize = pElem->pScrollbar->iHeight; iIncr = pTree->options.yscrollincrement; } else { iNew = pElem->pScrollbar->iHorizontal; iMax = pElem->pScrollbar->iHorizontalMax; iSize = pElem->pScrollbar->iWidth; iIncr = pTree->options.xscrollincrement; } eType = Tk_GetScrollInfoObj(pTree->interp, objc, objv, &fraction, &count); switch (eType) { case TK_SCROLL_MOVETO: iNew = (int)((double)iMax * fraction); break; case TK_SCROLL_PAGES: /* TODO */ iNew += count * (0.9 * iSize); break; case TK_SCROLL_UNITS: /* TODO */ iNew += count * iIncr; break; case TK_SCROLL_ERROR: return TCL_ERROR; default: assert(!"Not possible"); } iNew = MAX(0, iNew); iNew = MIN(iNew, iMax - iSize); if (isVertical) { pElem->pScrollbar->iVertical = iNew; } else { pElem->pScrollbar->iHorizontal = iNew; } /* Invoke the scrollbar callbacks (i.e. [$scrollbar set]) to update * the scrollbar widgets with their new positions. */ HtmlNodeScrollbarDoCallback(pNode->pNodeCmd->pTree, pNode); HtmlWidgetOverflowBox(pTree, pNode, &x, &y, &w, &h); HtmlCallbackDamage(pTree, x - pTree->iScrollX, y - pTree->iScrollY, w, h); if (pTree->cb.flags) { pTree->cb.flags |= HTML_NODESCROLL; } HtmlWalkTree(pTree, pNode, markWindowAsClipped, 0); return TCL_OK; } /* *--------------------------------------------------------------------------- * * nodeRemoveCmd -- * * $node remove NODE-LIST... * * Results: * None. * * Side effects: * None. * *--------------------------------------------------------------------------- */ static int nodeRemoveCmd(pNode, objc, objv) HtmlNode *pNode; int objc; Tcl_Obj *CONST objv[]; { HtmlTree *pTree = pNode->pNodeCmd->pTree; int ii; if (objc < 3) { Tcl_WrongNumArgs(pTree->interp, 2, objv, "NODE-LIST"); return TCL_ERROR; } for (ii = 2; ii < objc; ii++) { Tcl_Obj **apNode; int nNode; int jj; int rc; rc = Tcl_ListObjGetElements(pTree->interp, objv[ii], &nNode, &apNode); if (rc != TCL_OK) { return rc; } for (jj = 0; jj < nNode; jj++) { int e; Tcl_Obj *pObj = apNode[jj]; HtmlNode *pChild = HtmlNodeGetPointer(pTree, Tcl_GetString(pObj)); e = nodeRemoveChild((HtmlElementNode *)pNode, pChild); if (e) { nodeOrphanize(pTree, pChild); HtmlNodeClearRecursive(pTree, pChild); } } } HtmlCheckRestylePoint(pTree); return TCL_OK; } /* *--------------------------------------------------------------------------- * * nodeDestroyCmd -- * * $node destroy * * Results: * None. * * Side effects: * None. * *--------------------------------------------------------------------------- */ static int nodeDestroyCmd(pNode, objc, objv) HtmlNode *pNode; int objc; Tcl_Obj *CONST objv[]; { HtmlTree *pTree = pNode->pNodeCmd->pTree; if (objc != 2) { Tcl_WrongNumArgs(pTree->interp, 2, objv, ""); return TCL_ERROR; } assert( pNode->iNode == HTML_NODE_ORPHAN || pNode == pTree->pRoot || pNode->pParent ); if (pNode->iNode == HTML_NODE_ORPHAN) { nodeDeorphanize(pTree, pNode); } else if (pNode->pParent) { HtmlCallbackRestyle(pTree, pNode->pParent); HtmlCallbackLayout(pTree, pNode->pParent); nodeRemoveChild(HtmlNodeAsElement(pNode->pParent), pNode); } else { assert(!"TODO: Delete the root node?"); } freeNode(pTree, pNode); HtmlCheckRestylePoint(pTree); return TCL_OK; } /* *--------------------------------------------------------------------------- * * nodeInsertCmd -- * * $node insert ?-before|-after NODE? NODE-LIST... * * Results: * None. * * Side effects: * None. * *--------------------------------------------------------------------------- */ static int nodeInsertCmd(pNode, objc, objv) HtmlNode *pNode; int objc; Tcl_Obj *CONST objv[]; { HtmlTree *pTree = pNode->pNodeCmd->pTree; Tcl_Interp *interp = pTree->interp; int ii; HtmlNode *pBefore = 0; HtmlNode *pAfter = 0; /* Process the "-before" or "-after" option, if one is specified. */ if (objc > 3 && ( 0 == strcmp(Tcl_GetString(objv[2]), "-before") || 0 == strcmp(Tcl_GetString(objv[2]), "-after") )) { int iBefore; pBefore = HtmlNodeGetPointer(pTree, Tcl_GetString(objv[3])); iBefore = HtmlNodeIndexOfChild(pNode, pBefore); if (iBefore < 0) { Tcl_ResetResult(pTree->interp); Tcl_AppendResult(pTree->interp, Tcl_GetString(objv[3]), " is not a child node of ", Tcl_GetString(objv[0]), 0 ); return TCL_ERROR; } if (0 == strcmp(Tcl_GetString(objv[2]), "-after")) { pAfter = pBefore; pBefore = 0; } } /* Complain if there are insufficient arguments to this command */ if (objc < 3 || (pBefore && objc < 5)) { Tcl_WrongNumArgs(interp, 2, objv, "?-before|-after NODE? NODE-LIST"); return TCL_ERROR; } for (ii = (pBefore ? 4 : 2); ii < objc; ii++) { Tcl_Obj **apNode; int nNode; int jj; int rc; rc = Tcl_ListObjGetElements(interp, objv[ii], &nNode, &apNode); if (rc != TCL_OK) { return rc; } for (jj = 0; jj < nNode; jj++) { Tcl_Obj *pObj = apNode[jj]; HtmlNode *pChild = HtmlNodeGetPointer(pTree, Tcl_GetString(pObj)); if (pChild) { HtmlElementNode *pElem = HtmlNodeAsElement(pNode); if (pChild->iNode == HTML_NODE_ORPHAN) { nodeDeorphanize(pTree, pChild); } nodeInsertChild(pTree, pElem, pBefore, pAfter, pChild); } } } pTree->isSequenceOk = 0; HtmlCheckRestylePoint(pTree); return TCL_OK; } static CssPropertySet * nodeGetStyle(pTree, p) HtmlTree *pTree; HtmlNode *p; { HtmlElementNode *pElem = HtmlNodeAsElement(p); const char *zStyle; if (!pElem->pStyle && (zStyle = HtmlNodeAttr(p, "style"))) { HtmlCssInlineParse(pTree, -1, zStyle, &pElem->pStyle); } return pElem->pStyle; } /* */ /* *--------------------------------------------------------------------------- * * nodeTextCommand -- * * $node text ?get? * $node text -tokens * $node text -pre * $node text set TEXT * * Results: * None. * * Side effects: * None. * *--------------------------------------------------------------------------- */ static int nodeTextCommand(interp, pNode, objc, objv) Tcl_Interp *interp; HtmlNode *pNode; int objc; Tcl_Obj *CONST objv[]; { HtmlTree *pTree = pNode->pNodeCmd->pTree; Tcl_Obj *pRet = 0; int nByte = 0; enum NODE_TEXT_enum { NODE_TEXT_GET, NODE_TEXT_PRE, NODE_TEXT_SET, NODE_TEXT_TOKENS }; enum NODE_TEXT_enum eChoice; static const struct NodeTextSubCommand { const char *zCommand; enum NODE_TEXT_enum eSymbol; int nArg; } aSubCommand[] = { {"get", NODE_TEXT_GET, 0}, {"-pre", NODE_TEXT_PRE, 0}, {"set", NODE_TEXT_SET, 1}, {"-tokens", NODE_TEXT_TOKENS, 0}, {0, 0, 0} }; HtmlTextNode *pTextNode = HtmlNodeAsText(pNode); /* This is a no-op for non text nodes */ if (!pTextNode) return TCL_OK; if (objc==2) { eChoice = NODE_TEXT_GET; } else { int iChoice; if (Tcl_GetIndexFromObjStruct(interp, objv[2], aSubCommand, sizeof(struct NodeTextSubCommand), "option", 0, &iChoice) ){ return TCL_ERROR; } if (objc != 3+aSubCommand[iChoice].nArg) { Tcl_WrongNumArgs(interp, 3, objv, ((objc==3)?"TEXT":"")); return TCL_ERROR; } eChoice = aSubCommand[iChoice].eSymbol; } if (eChoice == NODE_TEXT_SET) { /* Because the storage for a text nodes data is allocated as * part of the HtmlTextNode allocation, the only way to modify * the text of a node is to allocate a new HtmlTextNode * structure and then to change all the pointers that refer to * it. There are only three possibilities: * * * In the Tcl_CmdInfo struct for this node-handle, * * In the parent node, if this is not an orphan. * * In the orphan node table, if this is an orphan. */ const char *zNew; int nNew; HtmlTextNode *pOrig; pOrig = HtmlNodeAsText(pNode); assert(pOrig); /* Invalidate the layout of this node. */ HtmlCallbackLayout(pTree, pNode); /* Set the node to contain the new text */ zNew = Tcl_GetStringFromObj(objv[3], &nNew); HtmlTextSet(pOrig, nNew, zNew, 0, 0); } else if (eChoice == NODE_TEXT_PRE) { pRet = nodeGetPreText(HtmlNodeAsText(pNode)); Tcl_IncrRefCount(pRet); } else { HtmlTextIter sIter; pRet = Tcl_NewObj(); Tcl_IncrRefCount(pRet); for ( HtmlTextIterFirst((HtmlTextNode *)pNode, &sIter); HtmlTextIterIsValid(&sIter); HtmlTextIterNext(&sIter) ) { int eType = HtmlTextIterType(&sIter); int nData = HtmlTextIterLength(&sIter); char const * zData = HtmlTextIterData(&sIter); if (eChoice == NODE_TEXT_TOKENS) { char *zType = 0; Tcl_Obj *p = Tcl_NewObj(); Tcl_Obj *pObj = 0; switch (eType) { case HTML_TEXT_TOKEN_TEXT: zType = "text"; pObj = Tcl_NewStringObj(zData, nData); break; case HTML_TEXT_TOKEN_SPACE: zType = "space"; pObj = Tcl_NewIntObj(nData); break; case HTML_TEXT_TOKEN_NEWLINE: zType = "newline"; pObj = Tcl_NewIntObj(nData); break; } assert(zType); Tcl_ListObjAppendElement( 0, p, Tcl_NewStringObj(zType, -1) ); Tcl_ListObjAppendElement(0, p, pObj); Tcl_ListObjAppendElement(0, pRet, p); } else { assert(eChoice == NODE_TEXT_GET); if (eType == HTML_TEXT_TOKEN_TEXT) { nByte = (HtmlTextIterData(&sIter) - pTextNode->zText); nByte += HtmlTextIterLength(&sIter); } } } } if (eChoice == NODE_TEXT_GET) { Tcl_SetStringObj(pRet, pTextNode->zText, nByte); } if( pRet ){ Tcl_SetObjResult(interp, pRet); Tcl_DecrRefCount(pRet); } return TCL_OK; } /* *--------------------------------------------------------------------------- * * nodeCommand -- * * attr Read/write node attributes * children Return a list of the nodes child nodes * dynamic Set/clear dynamic flags (i.e. :hover) * override Read/write CSS property overrides * parent Return the parent node * prop Query CSS property values * property Query a single CSS property value * replace Set/clear the node replacement object * tag Read/write the node's tag * text Read/write the node's text content * xview Scroll a scrollable node horizontally * yview Scroll a scrollable node vertically * * This function is the implementation of the Tcl node handle command. The * clientData passed to the command is a pointer to the HtmlNode structure * for the document node. * * When this function is called, ((HtmlNode *)clientData)->pNodeCmd is * guaranteed to point to a valid HtmlNodeCmd structure. * * Results: * None. * * Side effects: * None. * *--------------------------------------------------------------------------- */ static int nodeCommand(clientData, interp, objc, objv) ClientData clientData; Tcl_Interp *interp; int objc; Tcl_Obj *CONST objv[]; { HtmlNode *pNode = (HtmlNode *)clientData; HtmlTree *pTree = pNode->pNodeCmd->pTree; int iChoice; enum NODE_enum { NODE_ATTRIBUTE, NODE_CHILDREN, NODE_DESTROY, NODE_DYNAMIC, NODE_HTML, NODE_INSERT, NODE_OVERRIDE, NODE_PARENT, NODE_PROPERTY, NODE_REMOVE, NODE_REPLACE, NODE_STACKING, NODE_TAG, NODE_TEXT, NODE_XVIEW, NODE_YVIEW }; static const struct NodeSubCommand { const char *zCommand; enum NODE_enum eSymbol; int TODO; } aSubCommand[] = { {"attribute", NODE_ATTRIBUTE, 0}, {"children", NODE_CHILDREN, 0}, {"destroy", NODE_DESTROY, 0}, {"dynamic", NODE_DYNAMIC, 0}, {"html", NODE_HTML, 0}, {"insert", NODE_INSERT, 0}, {"override", NODE_OVERRIDE, 0}, {"parent", NODE_PARENT, 0}, {"property", NODE_PROPERTY, 0}, {"remove", NODE_REMOVE, 0}, {"replace", NODE_REPLACE, 0}, {"stacking", NODE_STACKING, 0}, {"tag", NODE_TAG, 0}, {"text", NODE_TEXT, 0}, {"xview", NODE_XVIEW, 0}, {"yview", NODE_YVIEW, 0}, {0, 0, 0} }; if (objc<2) { Tcl_WrongNumArgs(interp, 1, objv, "SUBCOMMAND ..."); return TCL_ERROR; } if (Tcl_GetIndexFromObjStruct(interp, objv[1], aSubCommand, sizeof(struct NodeSubCommand), "option", 0, &iChoice) ){ return TCL_ERROR; } switch (aSubCommand[iChoice].eSymbol) { /* * nodeHandle attr ??-default DEFAULT-VALUE? ATTR-NAME? ?NEW-VALUE? */ case NODE_ATTRIBUTE: { char CONST *zAttr = 0; char *zAttrName = 0; char *zAttrVal = 0; char *zDefault = 0; switch (objc) { case 2: break; case 3: zAttrName = Tcl_GetString(objv[2]); break; case 4: zAttrName = Tcl_GetString(objv[2]); zAttrVal = Tcl_GetString(objv[3]); break; case 5: if (strcmp(Tcl_GetString(objv[2]), "-default")) { goto node_attr_usage; } zDefault = Tcl_GetString(objv[3]); zAttrName = Tcl_GetString(objv[4]); break; default: goto node_attr_usage; } /* If there are values for both zAttrName and zAttrVal, then * set the value of the attribute to the string pointed to by * zAttrVal. After doing this, run the code for an attribute * query, so that the new attribute value is returned. */ if (zAttrName && zAttrVal) { /* Check if there is an attribute-handler for this type * of node. If so, invoke the script as follows: * * eval $handler [list $attribute-name] [list $new-value] */ int rc; char *zCopy; assert(!zDefault); zCopy = HtmlAlloc("tmp", strlen(zAttrName)+1); strcpy(zCopy, zAttrName); Tcl_UtfToLower(zCopy); rc = doAttributeHandler(pTree, pNode, zCopy, zAttrVal); HtmlFree(zCopy); if (rc != TCL_OK) { return rc; } setNodeAttribute(pNode, zAttrName, zAttrVal); HtmlCallbackRestyle(pTree, pNode); } if (zAttrName) { zAttr = HtmlNodeAttr(pNode, zAttrName); zAttr = (zAttr ? zAttr : zDefault); if (zAttr==0) { Tcl_AppendResult(interp, "No such attr: ", zAttrName, 0); return TCL_ERROR; } Tcl_SetResult(interp, (char *)zAttr, TCL_VOLATILE); } else if (!HtmlNodeIsText(pNode)) { int i; HtmlAttributes *pAttr = ((HtmlElementNode *)pNode)->pAttributes; Tcl_Obj *p = Tcl_NewObj(); for (i = 0; pAttr && i < pAttr->nAttr; i++) { Tcl_Obj *pArg; pArg = Tcl_NewStringObj(pAttr->a[i].zName, -1); Tcl_ListObjAppendElement(interp, p, pArg); pArg = Tcl_NewStringObj(pAttr->a[i].zValue, -1); Tcl_ListObjAppendElement(interp, p, pArg); } Tcl_SetObjResult(interp, p); } break; node_attr_usage: Tcl_ResetResult(interp); Tcl_AppendResult(interp, "Usage: ", Tcl_GetString(objv[0]), " ", Tcl_GetString(objv[1]), " ", "? ?-default DEFAULT-VALUE? ATTR-NAME ?NEW-VAL??", 0); return TCL_ERROR; } /* * nodeHandle children * * Return a list of node handles for all children of nodeHandle. * The leftmost child node becomes element 0 of the list, the * second leftmost element 1, and so on. */ case NODE_CHILDREN: { if (objc == 2) { int i; Tcl_Obj *pRes = Tcl_NewObj(); for (i = 0; i < HtmlNodeNumChildren(pNode); i++) { HtmlNode *pChild = HtmlNodeChild(pNode, i); Tcl_Obj *pCmd = HtmlNodeCommand(pTree, pChild); Tcl_ListObjAppendElement(0, pRes, pCmd); } Tcl_SetObjResult(interp, pRes); } else { Tcl_WrongNumArgs(interp, 2, objv, ""); return TCL_ERROR; } break; } /* * nodeHandle stacking * * Return the node-handle that forms the stacking context * this node is located in. Return "" for the root-element. * * Also return "" for any element that is part of an * orphan subtree. */ case NODE_STACKING: { HtmlElementNode *pElem = HtmlNodeAsElement(pNode); if (!pElem) { pElem = HtmlNodeAsElement(HtmlNodeParent(pNode)); } assert( pNode==pTree->pRoot || pElem->pStack || HtmlNodeIsOrphan(pNode) ); if ((HtmlNode *)pElem != pTree->pRoot && pElem->pStack) { HtmlNode *p = &(pElem->pStack->pElem->node); Tcl_SetObjResult(interp, HtmlNodeCommand(pTree, p)); } break; } case NODE_TAG: { char CONST *zTag; if (objc!=2) { Tcl_WrongNumArgs(interp, 2, objv, ""); return TCL_ERROR; } zTag = HtmlNodeTagName(pNode); Tcl_SetResult(interp, (char *)zTag, TCL_VOLATILE); break; } case NODE_TEXT: { return nodeTextCommand(interp, pNode, objc, objv); } case NODE_PARENT: { HtmlNode *pParent; pParent = HtmlNodeParent(pNode); if (pParent) { Tcl_SetObjResult(interp, HtmlNodeCommand(pTree, pParent)); } break; } /* * nodeHandle property ?-before|-after|-inline? ?PROPERTY-NAME? * * Return the calculated value of a node's CSS property. If the * node is a text node, return the value of the property as * assigned to the parent node. */ case NODE_PROPERTY: { int nArg = objc - 2; Tcl_Obj * CONST *aArg = &objv[2]; HtmlComputedValues *pComputed; HtmlNode *p = pNode; /* This method is a no-op for text nodes */ if (HtmlNodeIsText(p)) break; if (nArg > 0 && 0 == strcmp(Tcl_GetString(aArg[0]), "-inline")) { CssPropertySet *pSet = nodeGetStyle(pTree, p); if (nArg == 1) return HtmlCssInlineQuery(interp, pSet, 0); if (nArg == 2) return HtmlCssInlineQuery(interp, pSet, aArg[1]); /* Otherwise, fall through for the WrongNumArgs() message */ } /* Orphan nodes may have an inline style specified (required by * DOM implementations to implement HTMLElement.style), but * they do not have a computed style, so the rest of this * function is a no-op for orphan nodes. */ if (HtmlNodeIsOrphan(p)) break; HtmlCallbackForce(pTree); if (nArg > 0) { HtmlElementNode *pElem = HtmlNodeAsElement(pNode); char *zArg0 = Tcl_GetString(aArg[0]); if (0 == strcmp(zArg0, "-before")) { p = pElem ? pElem->pBefore : 0; aArg = &aArg[1]; nArg--; } else if (0 == strcmp(zArg0, "-after")) { p = pElem ? pElem->pAfter : 0; aArg = &aArg[1]; nArg--; } } /* If the -before or -after switch was specified, and the * element doesn't have any corresponding generated content, * then p is NULL at this point. Return an empty string. */ if (!p) { return TCL_OK; } pComputed = HtmlNodeComputedValues(p); switch (nArg) { case 0: return HtmlNodeProperties(interp, pComputed); case 1: return HtmlNodeGetProperty(interp, objv[2], pComputed); default: Tcl_WrongNumArgs( interp, 2, objv,"?-before|-after|-inline? PROPERTY-NAME" ); return TCL_ERROR; } break; } /* * nodeHandle replace ?new-value? ?options? * * supported options are: * * -configurecmd <script> * -deletecmd <script> * -stylecmd <script> */ case NODE_REPLACE: { HtmlElementNode *pElem = HtmlNodeAsElement(pNode); if (!pElem) { char *zErr = "Text node does not support [replace]"; Tcl_SetResult(interp, zErr, 0); return TCL_ERROR; } if (objc > 2) { Tcl_Obj *aArgs[4]; HtmlNodeReplacement *pReplace = 0; /* New pNode->pReplacement */ Tk_Window widget; /* Replacement widget */ Tk_Window mainwin = Tk_MainWindow(pTree->interp); const char *zWin = 0; /* Replacement window name */ SwprocConf aArgConf[] = { {SWPROC_ARG, "new-value", 0, 0}, /* aArgs[0] */ {SWPROC_OPT, "configurecmd", 0, 0}, /* aArgs[1] */ {SWPROC_OPT, "deletecmd", 0, 0}, /* aArgs[2] */ {SWPROC_OPT, "stylecmd", 0, 0}, /* aArgs[3] */ {SWPROC_END, 0, 0, 0} }; if (SwprocRt(interp, objc - 2, &objv[2], aArgConf, aArgs)) { return TCL_ERROR; } zWin = Tcl_GetString(aArgs[0]); if (zWin[0]) { /* If the replacement object is a Tk window, * register Tkhtml as the geometry manager. */ widget = Tk_NameToWindow(interp, zWin, mainwin); if (widget) { static Tk_GeomMgr sManage = { "Tkhtml", geomRequestProc, 0 }; Tk_ManageGeometry(widget, &sManage, pNode); } pReplace = HtmlNew(HtmlNodeReplacement); pReplace->pReplace = aArgs[0]; pReplace->pConfigureCmd = aArgs[1]; pReplace->pDelete = aArgs[2]; pReplace->pStyleCmd = aArgs[3]; pReplace->win = widget; } /* Free any existing replacement object and set * pNode->pReplacement to point at the new structure. */ clearReplacement(pTree, pElem); pElem->pReplacement = pReplace; /* Run the layout engine. */ HtmlCallbackLayout(pTree, pNode); } /* The result of this command is the name of the current * replacement object (or an empty string). */ if (pElem->pReplacement) { assert(pElem->pReplacement->pReplace); Tcl_SetObjResult(interp, pElem->pReplacement->pReplace); } break; } /* * nodeHandle dynamic set|clear ?flag? * nodeHandle dynamic conditions * * Note that the [nodeHandle dynamic conditions] command is for * debugging only. It is not documented in the man page. */ case NODE_DYNAMIC: { struct DynamicFlag { const char *zName; Html_u8 flag; } flags[] = { {"active", HTML_DYNAMIC_ACTIVE}, {"focus", HTML_DYNAMIC_FOCUS}, {"hover", HTML_DYNAMIC_HOVER}, {"link", HTML_DYNAMIC_LINK}, {"visited", HTML_DYNAMIC_VISITED}, {0, 0} }; const char *zArg1 = (objc>2) ? Tcl_GetString(objv[2]) : 0; const char *zArg2 = (objc>3) ? Tcl_GetString(objv[3]) : 0; Tcl_Obj *pRet; int i; Html_u8 mask = 0; HtmlElementNode *pElem = (HtmlElementNode *)pNode; if (HtmlNodeIsText(pNode)) { Tcl_SetResult(interp, "Cannot call method [dynamic] on a text node", 0 ); return TCL_ERROR; } if (zArg1 && 0 == strcmp(zArg1, "conditions")) { HtmlCallbackForce(pTree); return HtmlCssTclNodeDynamics(interp, pNode); } if (zArg2) { for (i = 0; flags[i].zName; i++) { if (0 == strcmp(zArg2, flags[i].zName)) { mask = flags[i].flag; break; } } if (!mask) { Tcl_AppendResult(interp, "Unsupported dynamic CSS flag: ", zArg2, 0); return TCL_ERROR; } } if ( !zArg1 || (strcmp(zArg1, "set") && strcmp(zArg1, "clear")) || (zArg2 && !mask) ) { Tcl_WrongNumArgs(interp, 2, objv, "set|clear ?flag?"); return TCL_ERROR; } if (*zArg1 == 's') { pElem->flags |= mask; } else { pElem->flags &= ~(mask?mask:0xFF); } if (zArg2) { if ( mask == HTML_DYNAMIC_LINK || mask == HTML_DYNAMIC_VISITED ) { HtmlCallbackRestyle(pTree, pNode); } else { HtmlCallbackDynamic(pTree, pNode); } } pRet = Tcl_NewObj(); for (i = 0; flags[i].zName; i++) { if (pElem->flags & flags[i].flag) { Tcl_Obj *pNew = Tcl_NewStringObj(flags[i].zName, -1); Tcl_ListObjAppendElement(0, pRet, pNew); } } Tcl_SetObjResult(interp, pRet); break; } /* * nodeHandle override ?new-value? * * Get/set the override list. */ case NODE_OVERRIDE: { HtmlElementNode *pElem = (HtmlElementNode *)pNode; if (HtmlNodeIsText(pNode)) { Tcl_SetResult(interp, "Cannot call method [override] on a text node", 0 ); return TCL_ERROR; } if (objc != 2 && objc != 3) { Tcl_WrongNumArgs(interp, 2, objv, "?new-value?"); return TCL_ERROR; } if (objc == 3) { if (pElem->pOverride) { Tcl_DecrRefCount(pElem->pOverride); } pElem->pOverride = objv[2]; Tcl_IncrRefCount(pElem->pOverride); } Tcl_ResetResult(interp); if (pElem->pOverride) { Tcl_SetObjResult(interp, pElem->pOverride); } HtmlCallbackRestyle(pTree, pNode); return TCL_OK; } case NODE_XVIEW: { return nodeViewCmd(pNode, 0, objv, objc); } case NODE_YVIEW: { return nodeViewCmd(pNode, 1, objv, objc); } /* * nodeHandle html */ case NODE_HTML: { if (objc != 2) { Tcl_WrongNumArgs(interp, 2, objv, ""); return TCL_ERROR; } Tcl_SetResult(interp, (char *)Tcl_GetCommandName(interp, pTree->cmd), TCL_STATIC ); return TCL_OK; } /* * nodeHandle insert ?-before NODE? NODE-LIST * */ case NODE_INSERT: { HtmlCallbackRestyle(pTree, pNode); HtmlCallbackLayout(pTree, pNode); return nodeInsertCmd(pNode, objc, objv); } /* * nodeHandle remove NODE-LIST */ case NODE_REMOVE: { HtmlCallbackRestyle(pTree, pNode); HtmlCallbackLayout(pTree, pNode); return nodeRemoveCmd(pNode, objc, objv); } /* * nodeHandle destroy */ case NODE_DESTROY: { return nodeDestroyCmd(pNode, objc, objv); } default: assert(!"Impossible!"); } return TCL_OK; } /* *--------------------------------------------------------------------------- * * HtmlNodeCommand -- * * Return a Tcl object containing the name of the Tcl command used to * access pNode. If the command does not already exist it is created. * * The Tcl_Obj * returned is always a pointer to pNode->pCommand. * * Results: * None. * * Side effects: * None. * *--------------------------------------------------------------------------- */ Tcl_Obj * HtmlNodeCommand(pTree, pNode) HtmlTree *pTree; HtmlNode *pNode; { static int nodeNumber = 0; HtmlNodeCmd *pNodeCmd = pNode->pNodeCmd; if (pNode->iNode == HTML_NODE_GENERATED) { return 0; } if (!pNodeCmd) { char zBuf[100]; Tcl_Obj *pCmd; sprintf(zBuf, "::tkhtml::node%d", nodeNumber++); pCmd = Tcl_NewStringObj(zBuf, -1); Tcl_IncrRefCount(pCmd); Tcl_CreateObjCommand(pTree->interp, zBuf, nodeCommand, pNode, 0); pNodeCmd = HtmlNew(HtmlNodeCmd); pNodeCmd->pCommand = pCmd; pNodeCmd->pTree = pTree; pNode->pNodeCmd = pNodeCmd; } return pNodeCmd->pCommand; } /* *--------------------------------------------------------------------------- * * HtmlNodeScrollbarDoCallback -- * * If node pNode is scrollable, invoke the [$scrollbar set] command * for each of it's scrollbar widgets. * * Results: * None. * * Side effects: * Invokes 0-2 [$scrollbar set] scripts. * *--------------------------------------------------------------------------- */ int HtmlNodeScrollbarDoCallback(pTree, pNode) HtmlTree *pTree; HtmlNode *pNode; { HtmlElementNode *pElem = (HtmlElementNode *)pNode; if (!HtmlNodeIsText(pNode) && pElem->pScrollbar) { HtmlNodeScrollbars *p = pElem->pScrollbar; char zTmp[256]; if (p->vertical.win) { snprintf(zTmp, 255, "%s set %f %f", Tcl_GetString(p->vertical.pReplace), (double)p->iVertical / (double)p->iVerticalMax, (double)(p->iVertical + p->iHeight) / (double)p->iVerticalMax ); zTmp[255] = '\0'; Tcl_Eval(pTree->interp, zTmp); } if (p->horizontal.win) { snprintf(zTmp, 255, "%s set %f %f", Tcl_GetString(p->horizontal.pReplace), (double)p->iHorizontal / (double)p->iHorizontalMax, (double)(p->iHorizontal + p->iWidth) / (double)p->iHorizontalMax ); zTmp[255] = '\0'; Tcl_Eval(pTree->interp, zTmp); } } return TCL_OK; } /* *--------------------------------------------------------------------------- * * HtmlTreeClear -- * * Completely reset the widgets internal structures - for example when * loading a new document. * * Results: * None. * * Side effects: * Deletes internal document representation. * *--------------------------------------------------------------------------- */ int HtmlTreeClear(pTree) HtmlTree *pTree; { Tcl_HashEntry *pEntry; Tcl_HashSearch search; /* Free the canvas representation */ HtmlDrawCleanup(pTree, &pTree->canvas); memset(&pTree->canvas, 0, sizeof(HtmlCanvas)); /* Free any snapshot */ HtmlDrawSnapshotFree(pTree, pTree->cb.pSnapshot); pTree->cb.pSnapshot = 0; /* Free the contents of the search-cache */ HtmlCssSearchInvalidateCache(pTree); /* Free the tree representation - pTree->pRoot */ freeNode(pTree, pTree->pRoot); pTree->pRoot = 0; pTree->state.pCurrent = 0; pTree->state.pFoster = 0; /* Free any orphan nodes associated with this tree: */ for ( pEntry = Tcl_FirstHashEntry(&pTree->aOrphan, &search); pEntry; pEntry = Tcl_NextHashEntry(&search) ) { HtmlNode *pOrphan = (HtmlNode *)Tcl_GetHashKey(&pTree->aOrphan, pEntry); assert(pOrphan->iNode == HTML_NODE_ORPHAN); freeNode(pTree, pOrphan); } Tcl_DeleteHashTable(&pTree->aOrphan); Tcl_InitHashTable(&pTree->aOrphan, TCL_ONE_WORD_KEYS); /* Free the formatted text, if any (HtmlTree.pText) */ HtmlTextInvalidate(pTree); /* Free the plain text representation */ if (pTree->pDocument) { Tcl_DecrRefCount(pTree->pDocument); } pTree->nParsed = 0; pTree->pDocument = 0; /* Free the stylesheets */ HtmlCssStyleSheetFree(pTree->pStyle); pTree->pStyle = 0; /* Set the scroll position to top-left and clear the selection */ pTree->iScrollX = 0; pTree->iScrollY = 0; /* Deschedule any dynamic, style or layout callback. */ pTree->cb.pDynamic = 0; pTree->cb.pRestyle = 0; pTree->cb.flags &= ~(HTML_DYNAMIC|HTML_RESTYLE|HTML_LAYOUT); pTree->iNextNode = 0; return TCL_OK; } /* *--------------------------------------------------------------------------- * * HtmlNodeGetPointer -- * * String argument zCmd is the name of a node command created for * some node of tree pTree. Find the corresponding HtmlNode pointer * and return it. If zCmd is not the name of a node command, leave * an error in pTree->interp and return NULL. * * Results: * Pointer to node object associated with Tcl command zCmd, or NULL. * * Side effects: * None. * *--------------------------------------------------------------------------- */ HtmlNode * HtmlNodeGetPointer(pTree, zCmd) HtmlTree *pTree; char CONST *zCmd; { Tcl_Interp *interp = pTree->interp; Tcl_CmdInfo info; int rc; rc = Tcl_GetCommandInfo(interp, zCmd, &info); if (rc == 0 || info.objProc != nodeCommand){ Tcl_AppendResult(interp, "no such node: ", zCmd, 0); return 0; } return (HtmlNode *)info.objClientData; } /************************************************************************ * Start of [fragment] parsing code. */ static void fragmentOrphan(pTree) HtmlTree *pTree; { HtmlFragmentContext *pFragment = pTree->pFragment; HtmlNode *pOrphan = pFragment->pRoot; if (pOrphan) { Tcl_Obj *pCmd = HtmlNodeCommand(pTree, pOrphan); Tcl_ListObjAppendElement(0, pFragment->pNodeList, pCmd); nodeOrphanize(pTree, pOrphan); pFragment->pRoot = 0; pFragment->pCurrent = 0; } assert(!pFragment->pRoot && !pFragment->pCurrent); } static void fragmentAddText(pTree, pTextNode, iOffset) HtmlTree *pTree; HtmlTextNode *pTextNode; int iOffset; { HtmlFragmentContext *pFragment = pTree->pFragment; pTextNode->node.eTag = Html_Text; if (pFragment->pRoot) { /* If there is a fragment root node, add the new text node * as the right-most child of HtmlFragmentContext.pCurrent. */ nodeInsertChild(pTree, pFragment->pCurrent, 0,0, (HtmlNode *)pTextNode); } else { /* The text node becomes the a sub-tree all on it's own. */ pFragment->pRoot = (HtmlNode *)pTextNode; fragmentOrphan(pTree); } } static void fragmentAddElement(pTree, eType, zType, pAttributes, iOffset) HtmlTree *pTree; int eType; const char *zType; /* Atom */ HtmlAttributes *pAttributes; int iOffset; { HtmlElementNode *pElem; HtmlFragmentContext *pFragment = pTree->pFragment; int nClose; int ii; switch (eType) { /* Ignore <HEAD>, <BODY> and elements that occur as descendants of * <HEAD> completely. TODO: This will have to change.... */ case Html_HTML: case Html_HEAD: case Html_BODY: case Html_TITLE: case Html_META: case Html_LINK: case Html_BASE: return; } implicitCloseCount(pTree, pFragment->pCurrent, eType, &nClose); for (ii = 0; ii < nClose; ii++) { HtmlNode *pC = &pFragment->pCurrent->node; HtmlNode *pParentC = HtmlNodeParent(pC); assert(pC); nodeHandlerCallbacks(pTree, pC); pFragment->pCurrent = (HtmlElementNode *)pParentC; } if (!pFragment->pCurrent) { fragmentOrphan(pTree); } pElem = HtmlNew(HtmlElementNode); pElem->pAttributes = pAttributes; pElem->node.eTag = eType; if (!zType) { zType = HtmlTypeToName(0, eType); } pElem->node.zTag = zType; if (pFragment->pCurrent) { nodeInsertChild(pTree, pFragment->pCurrent, 0, 0, (HtmlNode *)pElem); } else { assert(!pFragment->pRoot); pFragment->pRoot = (HtmlNode *)pElem; pElem->node.iNode = HTML_NODE_ORPHAN; } pFragment->pCurrent = pElem; if (HtmlMarkup(eType)->flags & HTMLTAG_EMPTY) { nodeHandlerCallbacks(pTree, pFragment->pCurrent); pFragment->pCurrent = (HtmlElementNode *)HtmlNodeParent(pElem); } if (!pFragment->pCurrent) { fragmentOrphan(pTree); } } static void fragmentAddClosingTag(pTree, eType, zType, iOffset) HtmlTree *pTree; int eType; const char *zType; int iOffset; { int nClose; int ii; HtmlFragmentContext *p = pTree->pFragment; explicitCloseCount(p->pCurrent, eType, zType, &nClose); for (ii = 0; ii < nClose; ii++) { assert(p->pCurrent); nodeHandlerCallbacks(pTree, p->pCurrent); p->pCurrent = (HtmlElementNode *)HtmlNodeParent(p->pCurrent); } if (!p->pCurrent) { fragmentOrphan(pTree); } } void HtmlParseFragment(pTree, zHtml) HtmlTree *pTree; const char *zHtml; { HtmlFragmentContext sContext; assert(!pTree->pFragment); sContext.pRoot = 0; sContext.pCurrent = 0; sContext.pNodeList = Tcl_NewObj(); pTree->pFragment = &sContext; HtmlTokenize(pTree, zHtml, 1, fragmentAddText, fragmentAddElement, fragmentAddClosingTag ); while (sContext.pCurrent) { HtmlNode *pParent = HtmlNodeParent(sContext.pCurrent); nodeHandlerCallbacks(pTree, sContext.pCurrent); sContext.pCurrent = (HtmlElementNode *)pParent; } fragmentOrphan(pTree); pTree->pFragment = 0; Tcl_SetObjResult(pTree->interp, sContext.pNodeList); } /* *--------------------------------------------------------------------------- * * sequenceCb -- * * This is an HtmlWalkTree() callback function (the tree iteration * is started from with HtmlSequenceNodes()). * * Results: * * Side effects: * None. * *--------------------------------------------------------------------------- */ static int sequenceCb(pTree, pNode, clientData) HtmlTree *pTree; HtmlNode *pNode; ClientData clientData; { pNode->iNode = pTree->iNextNode++; return HTML_WALK_DESCEND; } /* *--------------------------------------------------------------------------- * * HtmlSequenceNodes -- * * Results: * * Side effects: * None. * *--------------------------------------------------------------------------- */ void HtmlSequenceNodes(pTree) HtmlTree *pTree; { if (!pTree->isSequenceOk) { pTree->iNextNode = 0; HtmlWalkTree(pTree, 0, sequenceCb, 0); pTree->isSequenceOk = 1; } } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������tkHTML-4ee7aaa953d6cb59/src/htmlurl.c���������������������������������������������������������������0000644�0000000�0000000�00000030317�11512242631�0016543�0����������������������������������������������������������������������������������������������������ustar�00nobody��������������������������nobody�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������static char const rcsid[] = "@(#) $Id: htmlurl.c,v 1.27 2005/03/23 01:36:54 danielk1977 Exp $"; /* ** Routines for processing URLs. ** ** This source code is released into the public domain by the author, ** D. Richard Hipp, on 2002 December 17. Instead of a license, here ** is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. */ #include <tk.h> #include <ctype.h> #include <string.h> #include <stdlib.h> #include "html.h" /* ** A parsed URI is held in an instance of the following structure. ** Each component is recorded in memory obtained from HtmlAlloc(). ** ** The examples are from the URI ** ** http://192.168.1.1:8080/cgi-bin/printenv?name=xyzzy&addr=none#frag */ struct HtmlUri { char *zScheme; /* Ex: "http" */ char *zAuthority; /* Ex: "192.168.1.1:8080" */ char *zPath; /* Ex: "cgi-bin/printenv" */ char *zQuery; /* Ex: "name=xyzzy&addr=none" */ char *zFragment; /* Ex: "frag" */ }; typedef struct HtmlUri HtmlUri; /* ** Return the length of the next component of the URL in z[] given ** that the component starts at z[0]. The initial sequence of the ** component must be zInit[]. The component is terminated by any ** character in zTerm[]. The length returned is 0 if the component ** doesn't exist. The length includes the zInit[] string, but not ** the termination character. ** ** Component zInit zTerm ** ---------- ------- ------- ** scheme "" ":/?#" ** authority "//" "/?#" ** path "/" "?#" ** query "?" "#" ** fragment "#" "" */ static int ComponentLength(z, zInit, zTerm) const char *z; const char *zInit; const char *zTerm; { int i, n; for (n = 0; zInit[n]; n++) { if (zInit[n] != z[n]) return 0; } while (z[n]) { for (i = 0; zTerm[i]; i++) { if (z[n] == zTerm[i]) return n; } n++; } return n; } /* ** Duplicate a string of length n. */ static char * StrNDup(z, n) const char *z; int n; { char *zResult; if (n <= 0) { n = strlen(z); } zResult = HtmlAlloc(n + 1); if (zResult) { memcpy(zResult, z, n); zResult[n] = 0; } return zResult; } /* ** Parse a text URI into an HtmlUri structure. */ static HtmlUri * ParseUri(zUri) const char *zUri; { HtmlUri *p; int n; p = HtmlAlloc(sizeof(*p)); if (p == 0) return 0; memset(p, 0, sizeof(*p)); if (zUri == 0 || zUri[0] == 0) return p; while (isspace(zUri[0])) { zUri++; } n = ComponentLength(zUri, "", ":/?# "); if (n > 0 && zUri[n] == ':') { p->zScheme = StrNDup(zUri, n); zUri += n + 1; } n = ComponentLength(zUri, "//", "/?# "); if (n > 0) { p->zAuthority = StrNDup(&zUri[2], n - 2); zUri += n; } n = ComponentLength(zUri, "", "?#"); if (n > 0) { p->zPath = StrNDup(zUri, n); zUri += n; } n = ComponentLength(zUri, "?", "# "); if (n > 0) { p->zQuery = StrNDup(&zUri[1], n - 1); zUri += n; } n = ComponentLength(zUri, "#", " "); if (n > 0) { p->zFragment = StrNDup(&zUri[1], n - 1); } return p; } /* ** Delete an HtmlUri structure. */ static void FreeUri(p) HtmlUri *p; { if (p == 0) return; if (p->zScheme) HtmlFree(p->zScheme); if (p->zAuthority) HtmlFree(p->zAuthority); if (p->zPath) HtmlFree(p->zPath); if (p->zQuery) HtmlFree(p->zQuery); if (p->zFragment) HtmlFree(p->zFragment); HtmlFree(p); } /* ** Create a string to hold the given URI. Memory to hold the string ** is obtained from HtmlAlloc() and must be freed by the calling ** function. */ static char * BuildUri(p) HtmlUri *p; { int n = 1; char *z; if (p->zScheme) n += strlen(p->zScheme) + 1; if (p->zAuthority) n += strlen(p->zAuthority) + 2; if (p->zPath) n += strlen(p->zPath) + 1; if (p->zQuery) n += strlen(p->zQuery) + 1; if (p->zFragment) n += strlen(p->zFragment) + 1; z = HtmlAlloc(n); if (z == 0) return 0; n = 0; if (p->zScheme) { sprintf(z, "%s:", p->zScheme); n = strlen(z); } if (p->zAuthority) { sprintf(&z[n], "//%s", p->zAuthority); n += strlen(&z[n]); } if (p->zPath) { sprintf(&z[n], "%s", p->zPath); n += strlen(&z[n]); } if (p->zQuery) { sprintf(&z[n], "?%s", p->zQuery); n += strlen(&z[n]); } if (p->zFragment) { sprintf(&z[n], "#%s", p->zFragment); } else { z[n] = 0; } return z; } /* ** Replace the string in *pzDest with the string in zSrc */ static void ReplaceStr(pzDest, zSrc) char **pzDest; const char *zSrc; { if (*pzDest != 0) HtmlFree(*pzDest); if (zSrc == 0) { *pzDest = 0; } else { *pzDest = StrNDup(zSrc, -1); } } /* ** Remove leading and trailing spaces from the given string. Return ** a new string obtained from HtmlAlloc(). */ static char * Trim(z) char *z; { int i; char *zNew; while (isspace(*z)) z++; i = strlen(z); zNew = HtmlAlloc(i + 1); if (zNew == 0) return 0; strcpy(zNew, z); if (i > 0 && isspace(zNew[i - 1])) { i--; zNew[i] = 0; } return zNew; } /* ** The input azSeries[] is a sequence of URIs. This command must ** resolve them all and put the result in the interp->result field ** of the interpreter associated with the HTML widget. Return ** TCL_OK on success and TCL_ERROR if there is a failure. ** ** This function can cause the HTML widget to be deleted or changed ** arbitrarily. */ int HtmlCallResolver(htmlPtr, azSeries) HtmlWidget *htmlPtr; /* The widget that is doing the * resolving. */ char **azSeries; /* A list of URIs. NULL terminated */ { int rc = TCL_OK; /* Return value of this function. */ char *z = 0; HtmlVerifyLock(htmlPtr); if (htmlPtr->zResolverCommand && htmlPtr->zResolverCommand[0]) { /* ** Append the current base URI then the azSeries arguments to the ** TCL command specified by the -resolvercommand optoin, then execute ** the result. ** ** The -resolvercommand could do nasty things, such as delete ** the HTML widget out from under us. Be prepared for the worst. */ Tcl_DString cmd; Tcl_DStringInit(&cmd); Tcl_DStringAppend(&cmd, htmlPtr->zResolverCommand, -1); if (htmlPtr->zBaseHref && htmlPtr->zBaseHref[0]) { z = Trim(htmlPtr->zBaseHref); } else if (htmlPtr->zBase && htmlPtr->zBase[0]) { z = Trim(htmlPtr->zBase); } if (z) { Tcl_DStringAppendElement(&cmd, z); HtmlFree(z); } while (azSeries[0]) { z = Trim(azSeries[0]); if (z) { Tcl_DStringAppendElement(&cmd, z); HtmlFree(z); } azSeries++; } HtmlLock(htmlPtr); htmlPtr->inParse++; rc = Tcl_GlobalEval(htmlPtr->interp, Tcl_DStringValue(&cmd)); htmlPtr->inParse--; Tcl_DStringFree(&cmd); if (HtmlUnlock(htmlPtr)) return TCL_ERROR; if (rc != TCL_OK) { Tcl_AddErrorInfo(htmlPtr->interp, "\n (-resolvercommand executed by HTML widget)"); Tcl_BackgroundError(htmlPtr->interp); } } else { /* ** No -resolvercommand has been specified. Do the default ** resolver algorithm specified in section 5.2 of RFC 2396. */ HtmlUri *base, *term; if (htmlPtr->zBaseHref && htmlPtr->zBaseHref[0]) { base = ParseUri(htmlPtr->zBaseHref); } else { base = ParseUri(htmlPtr->zBase); } while (azSeries[0]) { term = ParseUri(azSeries[0]); azSeries++; if (term->zScheme == 0 && term->zAuthority == 0 && term->zPath == 0 && term->zQuery == 0 && term->zFragment) { ReplaceStr(&base->zFragment, term->zFragment); } else if (term->zScheme) { HtmlUri temp; temp = *term; *term = *base; *base = temp; } else if (term->zAuthority) { ReplaceStr(&base->zAuthority, term->zAuthority); ReplaceStr(&base->zPath, term->zPath); ReplaceStr(&base->zQuery, term->zQuery); ReplaceStr(&base->zFragment, term->zFragment); } else if (term->zPath && (term->zPath[0] == '/' || base->zPath == 0)) { ReplaceStr(&base->zPath, term->zPath); ReplaceStr(&base->zQuery, term->zQuery); ReplaceStr(&base->zFragment, term->zFragment); } else if (term->zPath && base->zPath) { char *zBuf; int i, j; zBuf = HtmlAlloc(strlen(base->zPath) + strlen(term->zPath) + 2); if (zBuf) { sprintf(zBuf, "%s", base->zPath); for (i = strlen(zBuf) - 1; i >= 0 && zBuf[i] != '/'; i--) { zBuf[i] = 0; } strcat(zBuf, term->zPath); for (i = 0; zBuf[i]; i++) { if (zBuf[i] == '/' && zBuf[i + 1] == '.' && zBuf[i + 2] == '/') { strcpy(&zBuf[i + 1], &zBuf[i + 3]); i--; continue; } if (zBuf[i] == '/' && zBuf[i + 1] == '.' && zBuf[i + 2] == 0) { zBuf[i + 1] = 0; continue; } if (i > 0 && zBuf[i] == '/' && zBuf[i + 1] == '.' && zBuf[i + 2] == '.' && (zBuf[i + 3] == '/' || zBuf[i + 3] == 0)) { for (j = i - 1; j >= 0 && zBuf[j] != '/'; j--) { } if (zBuf[i + 3]) { strcpy(&zBuf[j + 1], &zBuf[i + 4]); } else { zBuf[j + 1] = 0; } i = j - 1; if (i < -1) i = -1; continue; } } HtmlFree(base->zPath); base->zPath = zBuf; } ReplaceStr(&base->zQuery, term->zQuery); ReplaceStr(&base->zFragment, term->zFragment); } else if (term->zQuery) { ReplaceStr(&base->zQuery, term->zQuery); } FreeUri(term); } Tcl_SetResult(htmlPtr->interp, BuildUri(base), TCL_DYNAMIC); FreeUri(base); } return rc; } /* ** This is a convenient wrapper routine for HtmlCallResolver. ** It makes a copy of the result into memory obtained from HtmlAlloc() ** and invokes Tcl_ResetResult(). */ char * HtmlResolveUri(htmlPtr, zUri) HtmlWidget *htmlPtr; char *zUri; { char *azSeq[2]; char *zSrc = 0; int result; if (zUri == 0 || *zUri == 0) return 0; azSeq[0] = zUri; azSeq[1] = 0; HtmlLock(htmlPtr); result = HtmlCallResolver(htmlPtr, azSeq); if (HtmlUnlock(htmlPtr)) return 0; if (result == TCL_OK) { zSrc = HtmlAlloc(strlen(htmlPtr->interp->result) + 1); if (zSrc) strcpy(zSrc, htmlPtr->interp->result); } Tcl_ResetResult(htmlPtr->interp); return zSrc; } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������tkHTML-4ee7aaa953d6cb59/src/htmlutil.c��������������������������������������������������������������0000644�0000000�0000000�00000025651�11512242631�0016723�0����������������������������������������������������������������������������������������������������ustar�00nobody��������������������������nobody����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������� #include <tcl.h> #ifdef TKHTML_ENABLE_PROFILE #include <string.h> #include <sys/time.h> #include "html.h" /* ** External interface: ** ** HtmlInstrumentInit() ** ** ::tkhtml::instrument */ typedef struct InstCommand InstCommand; typedef struct InstGlobal InstGlobal; typedef struct InstFrame InstFrame; typedef struct InstVector InstVector; typedef struct InstData InstData; struct InstCommand { Tcl_CmdInfo info; /* Original command info, before instrumentation */ int isDeleted; /* True after the Tcl command has been deleted */ Tcl_Obj *pFullName; /* The name to use for this object command */ InstGlobal *pGlobal; /* Pointer to associated "global" object */ InstCommand *pNext; /* Next in linked list starting at pGlobal */ }; struct InstVector { InstCommand *p1; InstCommand *p2; }; struct InstData { int nCall; Tcl_WideInt iClicks; }; struct InstGlobal { void (*xCall)(ClientData, int, void (*)(ClientData), ClientData); /* List of all dynamic InstCommand commands */ InstCommand *pGlobal; /* Current caller (or NULL). */ InstCommand *pCaller; Tcl_HashTable aVector; InstCommand aCommand[HTML_INSTRUMENT_NUM_SYMS]; }; #define timevalToClicks(tv) ( \ (Tcl_WideInt)tv.tv_usec + ((Tcl_WideInt)1000000 * (Tcl_WideInt)tv.tv_sec) \ ) static void updateInstData(pGlobal, p, iClicks) InstGlobal *pGlobal; InstCommand *p; int iClicks; { InstVector vector; InstData *pData; Tcl_HashEntry *pEntry; int isNew; /* Update the InstData structure associated with this call vector */ vector.p1 = pGlobal->pCaller; vector.p2 = p; pEntry = Tcl_CreateHashEntry(&pGlobal->aVector, (char *)&vector, &isNew); if (isNew) { pData = (InstData *)ckalloc(sizeof(InstData)); memset(pData, 0, sizeof(InstData)); Tcl_SetHashValue(pEntry, pData); } else { pData = Tcl_GetHashValue(pEntry); } pData->nCall++; pData->iClicks += iClicks; } void * HtmlInstrumentCall2(pClientData, iCall, xFunc, clientData) ClientData pClientData; int iCall; void *(*xFunc)(ClientData); ClientData clientData; { InstGlobal *pGlobal = (InstGlobal *)pClientData; InstCommand *p = &pGlobal->aCommand[iCall]; InstCommand *pCaller; /* Calling frame (if any) */ Tcl_WideInt iClicks; struct timeval tv = {0, 0}; void *pRet; pCaller = pGlobal->pCaller; pGlobal->pCaller = p; gettimeofday(&tv, 0); iClicks = timevalToClicks(tv); pRet = xFunc(clientData); gettimeofday(&tv, 0); iClicks = timevalToClicks(tv) - iClicks; pGlobal->pCaller = pCaller; updateInstData(pGlobal, p, (int)iClicks); return pRet; } void HtmlInstrumentCall(pClientData, iCall, xFunc, clientData) ClientData pClientData; int iCall; void (*xFunc)(ClientData); ClientData clientData; { InstGlobal *pGlobal = (InstGlobal *)pClientData; InstCommand *p = &pGlobal->aCommand[iCall]; InstCommand *pCaller; /* Calling frame (if any) */ Tcl_WideInt iClicks; struct timeval tv = {0, 0}; pCaller = pGlobal->pCaller; pGlobal->pCaller = p; gettimeofday(&tv, 0); iClicks = timevalToClicks(tv); xFunc(clientData); gettimeofday(&tv, 0); iClicks = timevalToClicks(tv) - iClicks; pGlobal->pCaller = pCaller; updateInstData(pGlobal, p, (int)iClicks); } static int execInst(clientData, interp, objc, objv) ClientData clientData; Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument strings. */ { InstCommand *p = (InstCommand *)clientData; InstGlobal *pGlobal = p->pGlobal; InstCommand *pCaller; /* Calling frame (if any) */ int rc; Tcl_WideInt iClicks; struct timeval tv = {0, 0}; pCaller = pGlobal->pCaller; pGlobal->pCaller = p; gettimeofday(&tv, 0); iClicks = timevalToClicks(tv); rc = p->info.objProc(p->info.objClientData, interp, objc, objv); gettimeofday(&tv, 0); iClicks = timevalToClicks(tv) - iClicks; pGlobal->pCaller = pCaller; updateInstData(pGlobal, p, (int)iClicks); return rc; } static void freeInstStruct(p) InstCommand *p; { Tcl_DecrRefCount(p->pFullName); ckfree((void *)p); } static void freeInstCommand(clientData) ClientData clientData; { InstCommand *p = (InstCommand *)clientData; if (p->info.deleteProc) { p->info.deleteProc(p->info.deleteData); } p->isDeleted = 1; } static int instCommand(clientData, interp, objc, objv) ClientData clientData; /* Pointer to InstGlobal structure */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument strings. */ { InstGlobal *pGlobal = (InstGlobal *)clientData; Tcl_Command token; Tcl_CmdInfo new_info; InstCommand *pInst; token = Tcl_GetCommandFromObj(interp, objv[2]); if (!token) { Tcl_AppendResult(interp, "no such command: ", Tcl_GetString(objv[2]),0); return TCL_ERROR; } pInst = (InstCommand *)ckalloc(sizeof(InstCommand)); memset(pInst, 0, sizeof(InstCommand)); Tcl_GetCommandInfoFromToken(token, &pInst->info); pInst->pFullName = Tcl_NewObj(); pInst->pGlobal = pGlobal; Tcl_IncrRefCount(pInst->pFullName); Tcl_GetCommandFullName(interp, token, pInst->pFullName); pInst->pNext = pGlobal->pGlobal; pGlobal->pGlobal = pInst; Tcl_GetCommandInfoFromToken(token, &new_info); new_info.objClientData = pInst; new_info.objProc = execInst; new_info.deleteProc = freeInstCommand; new_info.deleteData = pInst; Tcl_SetCommandInfoFromToken(token, &new_info); return TCL_OK; } static int instVectors(clientData, interp, objc, objv) ClientData clientData; /* Unused */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument strings. */ { InstGlobal *pGlobal = (InstGlobal *)clientData; Tcl_Obj *pRet; Tcl_HashSearch sSearch; Tcl_HashEntry *pEntry; pRet = Tcl_NewObj(); Tcl_IncrRefCount(pRet); for ( pEntry = Tcl_FirstHashEntry(&pGlobal->aVector, &sSearch); pEntry; pEntry = Tcl_NextHashEntry(&sSearch) ) { InstData *pData; InstVector *pVector; pData = (InstData *)Tcl_GetHashValue(pEntry); pVector = (InstVector *)Tcl_GetHashKey(&pGlobal->aVector, pEntry); if (!pVector->p1) { Tcl_Obj *pTop = Tcl_NewStringObj("<toplevel>", -1); Tcl_ListObjAppendElement(interp, pRet, pTop); } else { Tcl_ListObjAppendElement(interp, pRet, pVector->p1->pFullName); } Tcl_ListObjAppendElement(interp,pRet,pVector->p2->pFullName); Tcl_ListObjAppendElement(interp,pRet,Tcl_NewIntObj(pData->nCall)); Tcl_ListObjAppendElement(interp,pRet,Tcl_NewWideIntObj(pData->iClicks)); } Tcl_SetObjResult(interp, pRet); Tcl_DecrRefCount(pRet); return TCL_OK; } static int instZero(clientData, interp, objc, objv) ClientData clientData; /* InstGlobal structure */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument strings. */ { InstGlobal *pGlobal = (InstGlobal *)clientData; InstCommand *p; InstCommand **pp; Tcl_Obj *pRet; Tcl_HashSearch sSearch; Tcl_HashEntry *pEntry; pRet = Tcl_NewObj(); Tcl_IncrRefCount(pRet); pp = &pGlobal->pGlobal; for (p = *pp; p; p = *pp) { if (p->isDeleted) { *pp = p->pNext; freeInstStruct(p); }else{ pp = &p->pNext; } } for ( pEntry = Tcl_FirstHashEntry(&pGlobal->aVector, &sSearch); pEntry; pEntry = Tcl_NextHashEntry(&sSearch) ) { InstData *pData = Tcl_GetHashValue(pEntry); ckfree((void *)pData); } Tcl_DeleteHashTable(&pGlobal->aVector); Tcl_InitHashTable(&pGlobal->aVector, sizeof(InstVector)/sizeof(int)); Tcl_SetObjResult(interp, pRet); Tcl_DecrRefCount(pRet); return TCL_OK; } /* *--------------------------------------------------------------------------- * * instrument_objcmd -- * * Implementation of [instrument_objcmd]. Syntax is: * * instrument command COMMAND * instrument report * * Results: * TCL_OK or TCL_ERROR. * * Side effects: * See above. * *--------------------------------------------------------------------------- */ static int instrument_objcmd(clientData, interp, objc, objv) ClientData clientData; /* Unused */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument strings. */ { int iChoice; struct SubCmd { const char *zName; Tcl_ObjCmdProc *xFunc; } aSub[] = { { "command", instCommand }, { "vectors", instVectors }, { "zero", instZero }, { 0, 0 } }; if (objc < 2) { Tcl_WrongNumArgs(interp, 1, objv, "SUB-COMMAND"); return TCL_ERROR; } if (Tcl_GetIndexFromObjStruct(interp, objv[1], aSub, sizeof(aSub[0]), "sub-command", 0, &iChoice) ){ return TCL_ERROR; } return aSub[iChoice].xFunc(clientData, interp, objc, objv); } static void instDelCommand(clientData) ClientData clientData; { /* InstGlobal *p = (InstGlobal *)clientData; */ /* TODO */ } void HtmlInstrumentInit(interp) Tcl_Interp *interp; { InstGlobal *p = (InstGlobal *)ckalloc(sizeof(InstGlobal)); memset(p, 0, sizeof(InstGlobal)); p->xCall = HtmlInstrumentCall; p->aCommand[0].pFullName = Tcl_NewStringObj("C: External Script Event", -1); p->aCommand[1].pFullName = Tcl_NewStringObj("C: callbackHandler()", -1); p->aCommand[2].pFullName = Tcl_NewStringObj( "C: runDynamicStyleEngine()", -1 ); p->aCommand[3].pFullName = Tcl_NewStringObj("C: runStyleEngine()", -1); p->aCommand[4].pFullName = Tcl_NewStringObj("C: runLayoutEngine()", -1); p->aCommand[5].pFullName = Tcl_NewStringObj("C: allocateNewFont()", -1); Tcl_IncrRefCount(p->aCommand[0].pFullName); Tcl_IncrRefCount(p->aCommand[1].pFullName); Tcl_IncrRefCount(p->aCommand[2].pFullName); Tcl_IncrRefCount(p->aCommand[3].pFullName); Tcl_IncrRefCount(p->aCommand[4].pFullName); Tcl_InitHashTable(&p->aVector, sizeof(InstVector)/sizeof(int)); Tcl_CreateObjCommand(interp, "::tkhtml::instrument", instrument_objcmd, (ClientData)p, instDelCommand ); } #else /* TKHTML_ENABLE_PROFILE */ void HtmlInstrumentInit(interp) Tcl_Interp *interp; { /* No-op */ } #endif ���������������������������������������������������������������������������������������tkHTML-4ee7aaa953d6cb59/src/htmlwidget.c������������������������������������������������������������0000644�0000000�0000000�00000226525�11512242631�0017234�0����������������������������������������������������������������������������������������������������ustar�00nobody��������������������������nobody�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������static char const rcsid[] = "@(#) $Id: htmlwidget.c,v 1.59 2005/03/23 23:56:27 danielk1977 Exp $"; /* ** The main routine for the HTML widget for Tcl/Tk ** ** This source code is released into the public domain by the author, ** D. Richard Hipp, on 2002 December 17. Instead of a license, here ** is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. */ #include <tk.h> #include <ctype.h> #include <stdlib.h> #include <string.h> #include <assert.h> #include "html.h" #ifdef USE_TK_STUBS # include <tkIntXlibDecls.h> #endif #include <X11/Xatom.h> /* ** This global variable is used for tracing the operation of ** the Html formatter. */ int HtmlTraceMask = 0; #ifdef __WIN32__ # define DEF_FRAME_BG_COLOR "SystemButtonFace" # define DEF_FRAME_BG_MONO "White" # define DEF_FRAME_CURSOR "" # define DEF_BUTTON_FG "SystemButtonText" # define DEF_BUTTON_HIGHLIGHT_BG "SystemButtonFace" # define DEF_BUTTON_HIGHLIGHT "SystemWindowFrame" #else # define DEF_FRAME_BG_COLOR "#d9d9d9" # define DEF_FRAME_BG_MONO "White" # define DEF_FRAME_CURSOR "" # define DEF_BUTTON_FG "Black" # define DEF_BUTTON_HIGHLIGHT_BG "#d9d9d9" # define DEF_BUTTON_HIGHLIGHT "Black" #endif /* ** Information used for argv parsing. */ static Tk_ConfigSpec configSpecs[] = { #if !defined(_TCLHTML_) {TK_CONFIG_BORDER, "-background", "background", "Background", DEF_HTML_BG_COLOR, Tk_Offset(HtmlWidget, border), TK_CONFIG_COLOR_ONLY}, {TK_CONFIG_BORDER, "-background", "background", "Background", DEF_HTML_BG_MONO, Tk_Offset(HtmlWidget, border), TK_CONFIG_MONO_ONLY}, {TK_CONFIG_SYNONYM, "-bd", "borderWidth", (char *) NULL, (char *) NULL, 0, 0}, {TK_CONFIG_SYNONYM, "-bg", "background", (char *) NULL, (char *) NULL, 0, 0}, {TK_CONFIG_PIXELS, "-borderwidth", "borderWidth", "BorderWidth", DEF_HTML_BORDER_WIDTH, Tk_Offset(HtmlWidget, borderWidth), 0}, {TK_CONFIG_ACTIVE_CURSOR, "-cursor", "cursor", "Cursor", DEF_HTML_CURSOR, Tk_Offset(HtmlWidget, cursor), TK_CONFIG_NULL_OK}, {TK_CONFIG_BOOLEAN, "-exportselection", "exportSelection", "ExportSelection", DEF_HTML_EXPORT_SEL, Tk_Offset(HtmlWidget, exportSelection), 0}, {TK_CONFIG_SYNONYM, "-fg", "foreground", (char *) NULL, (char *) NULL, 0, 0}, {TK_CONFIG_STRING, "-fontcommand", "fontCommand", "FontCommand", DEF_HTML_CALLBACK, Tk_Offset(HtmlWidget, zFontCommand), 0}, {TK_CONFIG_STRING, "-fontfamily", "fontFamily", "FontFamily", "times", Tk_Offset(HtmlWidget, FontFamily), 0}, {TK_CONFIG_INT, "-fontadjust", "fontAdjust", "FontAdjust", "2", Tk_Offset(HtmlWidget, FontAdjust), 0}, {TK_CONFIG_INT, "-formpadding", "formPadding", "FormPadding", "4", Tk_Offset(HtmlWidget, formPadding), 0}, {TK_CONFIG_COLOR, "-foreground", "foreground", "Foreground", DEF_HTML_FG, Tk_Offset(HtmlWidget, fgColor), 0}, {TK_CONFIG_STRING, "-imgidxcommand", "imgidxCommand", "HtmlCallback", DEF_HTML_CALLBACK, Tk_Offset(HtmlWidget, zImgIdxCommand), 0}, {TK_CONFIG_PIXELS, "-height", "height", "Hidth", DEF_HTML_HEIGHT, Tk_Offset(HtmlWidget, height), 0}, {TK_CONFIG_COLOR, "-highlightbackground", "highlightBackground", "HighlightBackground", DEF_HTML_HIGHLIGHT_BG, Tk_Offset(HtmlWidget, highlightBgColorPtr), 0}, {TK_CONFIG_COLOR, "-highlightcolor", "highlightColor", "HighlightColor", DEF_HTML_HIGHLIGHT, Tk_Offset(HtmlWidget, highlightColorPtr), 0}, {TK_CONFIG_PIXELS, "-highlightthickness", "highlightThickness", "HighlightThickness", DEF_HTML_HIGHLIGHT_WIDTH, Tk_Offset(HtmlWidget, highlightWidth), 0}, {TK_CONFIG_STRING, "-hyperlinkcommand", "hyperlinkCommand", "HtmlCallback", DEF_HTML_CALLBACK, Tk_Offset(HtmlWidget, zHyperlinkCommand), 0}, {TK_CONFIG_STRING, "-imagecommand", "imageCommand", "HtmlCallback", DEF_HTML_CALLBACK, Tk_Offset(HtmlWidget, zGetImage), 0}, {TK_CONFIG_STRING, "-bgimagecommand", "BGimageCommand", "HtmlCallback", DEF_HTML_CALLBACK, Tk_Offset(HtmlWidget, zGetBGImage), 0}, {TK_CONFIG_INT, "-insertofftime", "insertOffTime", "OffTime", DEF_HTML_INSERT_OFF_TIME, Tk_Offset(HtmlWidget, insOffTime), 0}, {TK_CONFIG_INT, "-insertontime", "insertOnTime", "OnTime", DEF_HTML_INSERT_ON_TIME, Tk_Offset(HtmlWidget, insOnTime), 0}, {TK_CONFIG_STRING, "-isvisitedcommand", "isVisitedCommand", "HtmlCallback", DEF_HTML_CALLBACK, Tk_Offset(HtmlWidget, zIsVisited), 0}, {TK_CONFIG_PIXELS, "-padx", "padX", "Pad", DEF_HTML_PADX, Tk_Offset(HtmlWidget, padx), 0}, {TK_CONFIG_PIXELS, "-pady", "padY", "Pad", DEF_HTML_PADY, Tk_Offset(HtmlWidget, pady), 0}, {TK_CONFIG_PIXELS, "-leftmargin", "leftmargin", "Margin", DEF_HTML_PADY, Tk_Offset(HtmlWidget, leftmargin), 0}, {TK_CONFIG_PIXELS, "-topmargin", "topmargin", "Margin", DEF_HTML_PADY, Tk_Offset(HtmlWidget, topmargin), 0}, {TK_CONFIG_PIXELS, "-marginwidth", "marginwidth", "Margin", DEF_HTML_PADY, Tk_Offset(HtmlWidget, marginwidth), 0}, {TK_CONFIG_PIXELS, "-marginheight", "marginheight", "Margin", DEF_HTML_PADY, Tk_Offset(HtmlWidget, marginheight), 0}, {TK_CONFIG_BOOLEAN, "-overridecolors", "overrideColors", "OverrideColors", "0", Tk_Offset(HtmlWidget, overrideColors), 0}, {TK_CONFIG_BOOLEAN, "-overridefonts", "overrideFonts", "OverrideFonts", "0", Tk_Offset(HtmlWidget, overrideFonts), 0}, {TK_CONFIG_RELIEF, "-relief", "relief", "Relief", DEF_HTML_RELIEF, Tk_Offset(HtmlWidget, relief), 0}, {TK_CONFIG_RELIEF, "-rulerelief", "ruleRelief", "RuleRelief", "sunken", Tk_Offset(HtmlWidget, ruleRelief), 0}, {TK_CONFIG_COLOR, "-selectioncolor", "background", "Background", DEF_HTML_SELECTION_COLOR, Tk_Offset(HtmlWidget, selectionColor), 0}, {TK_CONFIG_RELIEF, "-tablerelief", "tableRelief", "TableRelief", "raised", Tk_Offset(HtmlWidget, tableRelief), 0}, {TK_CONFIG_STRING, "-takefocus", "takeFocus", "TakeFocus", DEF_HTML_TAKE_FOCUS, Tk_Offset(HtmlWidget, takeFocus), TK_CONFIG_NULL_OK}, {TK_CONFIG_COLOR, "-unvisitedcolor", "foreground", "Foreground", DEF_HTML_UNVISITED, Tk_Offset(HtmlWidget, newLinkColor), 0}, {TK_CONFIG_BOOLEAN, "-underlinehyperlinks", "underlineHyperlinks", "UnderlineHyperlinks", "1", Tk_Offset(HtmlWidget, underlineLinks), 0}, {TK_CONFIG_COLOR, "-visitedcolor", "foreground", "Foreground", DEF_HTML_VISITED, Tk_Offset(HtmlWidget, oldLinkColor), 0}, {TK_CONFIG_PIXELS, "-width", "width", "Width", DEF_HTML_WIDTH, Tk_Offset(HtmlWidget, width), 0}, {TK_CONFIG_STRING, "-xscrollcommand", "xScrollCommand", "ScrollCommand", DEF_HTML_SCROLL_COMMAND, Tk_Offset(HtmlWidget, xScrollCmd), TK_CONFIG_NULL_OK}, {TK_CONFIG_STRING, "-yscrollcommand", "yScrollCommand", "ScrollCommand", DEF_HTML_SCROLL_COMMAND, Tk_Offset(HtmlWidget, yScrollCmd), TK_CONFIG_NULL_OK}, #endif {TK_CONFIG_STRING, "-appletcommand", "appletCommand", "HtmlCallback", DEF_HTML_CALLBACK, Tk_Offset(HtmlWidget, zAppletCommand), 0}, {TK_CONFIG_STRING, "-base", "base", "Base", "", Tk_Offset(HtmlWidget, zBase), 0}, {TK_CONFIG_STRING, "-scriptcommand", "scriptCommand", "HtmlCallback", "", Tk_Offset(HtmlWidget, zScriptCommand), 0}, {TK_CONFIG_STRING, "-formcommand", "formCommand", "HtmlCallback", DEF_HTML_CALLBACK, Tk_Offset(HtmlWidget, zFormCommand), 0}, {TK_CONFIG_STRING, "-framecommand", "frameCommand", "HtmlCallback", DEF_HTML_CALLBACK, Tk_Offset(HtmlWidget, zFrameCommand), 0}, {TK_CONFIG_INT, "-addendtags", "addendtags", "bool", 0, Tk_Offset(HtmlWidget, AddEndTags), 0}, {TK_CONFIG_INT, "-tableborder", "tableborder", "int", 0, Tk_Offset(HtmlWidget, TableBorderMin), 0}, {TK_CONFIG_INT, "-hasscript", "hasscript", "bool", 0, Tk_Offset(HtmlWidget, HasScript), 0}, {TK_CONFIG_INT, "-hasframes", "hasframes", "bool", 0, Tk_Offset(HtmlWidget, HasFrames), 0}, {TK_CONFIG_INT, "-hastktables", "hastktables", "bool", 0, Tk_Offset(HtmlWidget, HasTktables), 0}, {TK_CONFIG_INT, "-tclhtml", "tclhtml", "bool", 0, Tk_Offset(HtmlWidget, TclHtml), 0}, {TK_CONFIG_STRING, "-resolvercommand", "resolverCommand", "HtmlCallback", DEF_HTML_CALLBACK, Tk_Offset(HtmlWidget, zResolverCommand), 0}, {TK_CONFIG_BOOLEAN, "-sentencepadding", "sentencePadding", "SentencePadding", "0", Tk_Offset(HtmlWidget, iSentencePadding), 0}, {TK_CONFIG_END, (char *) NULL, (char *) NULL, (char *) NULL, (char *) NULL, 0, 0} }; /* ** Get a copy of the config specs. */ Tk_ConfigSpec * HtmlConfigSpec() { return configSpecs; } int TclConfigureWidgetObj(interp, htmlPtr, configSpecs, objc, objv, dp, flags) Tcl_Interp *interp; HtmlWidget *htmlPtr; Tk_ConfigSpec *configSpecs; int objc; Tcl_Obj *const *objv; char *dp; int flags; { Tk_ConfigSpec *cs; int i; char *op; if (objc == 0) { cs = configSpecs; while (cs->type != TK_CONFIG_END) { switch (cs->type) { case TK_CONFIG_STRING:{ char **sp; op = dp + cs->offset; sp = (char **) op; Tcl_AppendElement(interp, cs->argvName); Tcl_AppendElement(interp, *sp); } break; case TK_CONFIG_INT:{ int *sp; char buf[50]; op = dp + cs->offset; sp = (int *) op; sprintf(buf, "%d", *sp); Tcl_AppendElement(interp, cs->argvName); Tcl_AppendElement(interp, buf); } break; default: assert(0 == "Unknown spec type"); } cs = cs + 1; } return TCL_OK; } for (i = 0; (i + 1) <= objc; i++) { char *arg = Tcl_GetString(objv[i]); cs = configSpecs; while (cs->type != TK_CONFIG_END) { if (!strcmp(arg, cs->argvName)) { switch (cs->type) { case TK_CONFIG_STRING:{ char **sp; op = dp + cs->offset; sp = (char **) op; if (++i >= objc) { Tcl_SetResult(interp, *sp, 0); return TCL_OK; } *sp = strdup(arg); goto foundopt; } break; case TK_CONFIG_INT:{ int *sp; op = dp + cs->offset; sp = (int *) op; if (++i >= objc) { char buf[50]; sprintf(buf, "%d", *sp); Tcl_SetResult(interp, buf, 0); return TCL_OK; } *sp = atoi(arg); goto foundopt; } break; default: assert(0 == "Unknown spec type"); } } cs = cs + 1; } fprintf(stderr, "Unknown option %s\n", arg); return TCL_ERROR; foundopt: continue; } return TCL_OK; } int TclConfigureWidget(interp, htmlPtr, configSpecs, argc, argv, dp, flags) Tcl_Interp *interp; HtmlWidget *htmlPtr; Tk_ConfigSpec *configSpecs; int argc; char **argv; char *dp; int flags; { Tk_ConfigSpec *cs; int i; char *op; if (argc == 0) { cs = configSpecs; while (cs->type != TK_CONFIG_END) { switch (cs->type) { case TK_CONFIG_STRING:{ char **sp; op = dp + cs->offset; sp = (char **) op; Tcl_AppendElement(interp, cs->argvName); Tcl_AppendElement(interp, *sp); } break; case TK_CONFIG_INT:{ int *sp; char buf[50]; op = dp + cs->offset; sp = (int *) op; sprintf(buf, "%d", *sp); Tcl_AppendElement(interp, cs->argvName); Tcl_AppendElement(interp, buf); } break; default: assert(0 == "Unknown spec type"); } cs = cs + 1; } return TCL_OK; } for (i = 0; (i + 1) <= argc && argv[i]; i++) { cs = configSpecs; while (cs->type != TK_CONFIG_END) { if (!strcmp(argv[i], cs->argvName)) { switch (cs->type) { case TK_CONFIG_STRING:{ char **sp; op = dp + cs->offset; sp = (char **) op; if (++i >= argc) { Tcl_SetResult(interp, *sp, 0); return TCL_OK; } *sp = strdup(argv[i]); goto foundopt; } break; case TK_CONFIG_INT:{ int *sp; op = dp + cs->offset; sp = (int *) op; if (++i >= argc) { char buf[50]; sprintf(buf, "%d", *sp); Tcl_SetResult(interp, buf, 0); return TCL_OK; } *sp = atoi(argv[i]); goto foundopt; } break; default: assert(0 == "Unknown spec type"); } } cs = cs + 1; } fprintf(stderr, "Unknown option %s\n", argv[i]); return TCL_ERROR; foundopt: continue; } return TCL_OK; } #ifdef _TCLHTML_ static void HtmlCmdDeletedProc(ClientData clientData) { } static void HtmlEventProc(ClientData clientData, XEvent * eventPtr) { } void HtmlRedrawText(HtmlWidget * htmlPtr, int y) { } void HtmlRedrawBlock(HtmlWidget * htmlPtr, HtmlBlock * p) { } int HtmlGetColorByName(HtmlWidget * htmlPtr, char *zColor, int def) { return 0; } void HtmlScheduleRedraw(HtmlWidget * htmlPtr) { } #else /* ** Find the width of the usable drawing area in pixels. If the window isn't ** mapped, use the size requested by the user. ** ** The usable drawing area is the area available for displaying rendered ** HTML. The usable drawing area does not include the 3D border or the ** padx and pady boundry within the 3D border. The usable drawing area ** is the size of the clipping window. */ int HtmlUsableWidth(htmlPtr) HtmlWidget *htmlPtr; { int w; Tk_Window tkwin = htmlPtr->tkwin; if (tkwin && Tk_IsMapped(tkwin)) { w = Tk_Width(tkwin) - 2 * (htmlPtr->padx + htmlPtr->inset); } else { w = htmlPtr->width; } return w; } /* ** Find the height of the usable drawing area in pixels. If the window isn't ** mapped, use the size requested by the user. ** ** The usable drawing area is the area available for displaying rendered ** HTML. The usable drawing area does not include the 3D border or the ** padx and pady boundry within the 3D border. The usable drawing area ** is the size of the clipping window. */ int HtmlUsableHeight(htmlPtr) HtmlWidget *htmlPtr; { int h; Tk_Window tkwin = htmlPtr->tkwin; if (tkwin && Tk_IsMapped(tkwin)) { h = Tk_Height(tkwin) - 2 * (htmlPtr->pady + htmlPtr->inset); } else { h = htmlPtr->height; } return h; } /* ** Compute a pair of floating point numbers that describe the current ** vertical scroll position. The first number is the fraction of ** the document that is off the top of the visible region and the second ** number is the fraction that is beyond the end of the visible region. */ void HtmlComputeVerticalPosition(htmlPtr, buf) HtmlWidget *htmlPtr; char *buf; /* Write the two floating point values * here */ { int actual; /* Size of the viewing area */ double frac1, frac2; actual = HtmlUsableHeight(htmlPtr); if (htmlPtr->maxY <= 0) { frac1 = 0.0; frac2 = 1.0; } else { frac1 = (double) htmlPtr->yOffset / (double) htmlPtr->maxY; if (frac1 > 1.0) { frac1 = 1.0; } else if (frac1 < 0.0) { frac1 = 0.0; } frac2 = (double) (htmlPtr->yOffset + actual) / (double) htmlPtr->maxY; if (frac2 > 1.0) { frac2 = 1.0; } else if (frac2 < 0.0) { frac2 = 0.0; } } sprintf(buf, "%g %g", frac1, frac2); } /* ** Do the same thing for the horizontal direction */ void HtmlComputeHorizontalPosition(htmlPtr, buf) HtmlWidget *htmlPtr; char *buf; /* Write the two floating point values * here */ { int actual; /* Size of the viewing area */ double frac1, frac2; actual = HtmlUsableWidth(htmlPtr); if (htmlPtr->maxX <= 0) { frac1 = 0.0; frac2 = 1.0; } else { frac1 = (double) htmlPtr->xOffset / (double) htmlPtr->maxX; if (frac1 > 1.0) { frac1 = 1.0; } else if (frac1 < 0.0) { frac1 = 0.0; } frac2 = (double) (htmlPtr->xOffset + actual) / (double) htmlPtr->maxX; if (frac2 > 1.0) { frac2 = 1.0; } else if (frac2 < 0.0) { frac2 = 0.0; } } sprintf(buf, "%g %g", frac1, frac2); } static int GcNextToFree = 0; /* ** Clear the cache of GCs */ void ClearGcCache(htmlPtr) HtmlWidget *htmlPtr; { int i; for (i = 0; i < N_CACHE_GC; i++) { if (htmlPtr->aGcCache[i].index) { Tk_FreeGC(htmlPtr->display, htmlPtr->aGcCache[i].gc); htmlPtr->aGcCache[i].index = 0; } else { } } GcNextToFree = 0; } /* ** This routine is called when the widget command is deleted. If the ** widget isn't already in the process of being destroyed, this command ** starts that process rolling. ** ** This routine can be called in two ways. ** ** (1) The window is destroyed, which causes the command to be deleted. ** In this case, we don't have to do anything. ** ** (2) The command only is deleted (ex: "rename .html {}"). In that ** case we need to destroy the window. */ static void HtmlCmdDeletedProc(clientData) ClientData clientData; { HtmlWidget *htmlPtr = (HtmlWidget *) clientData; if (htmlPtr != NULL && htmlPtr->tkwin != NULL) { Tk_Window tkwin = htmlPtr->tkwin; htmlPtr->tkwin = NULL; Tk_DestroyWindow(tkwin); } } /* ** Reset the main layout context in the main widget. This happens ** before we redo the layout, or just before deleting the widget. */ static void ResetLayoutContext(htmlPtr) HtmlWidget *htmlPtr; { htmlPtr->layoutContext.headRoom = 0; htmlPtr->layoutContext.top = 0; htmlPtr->layoutContext.bottom = 0; HtmlClearMarginStack(&htmlPtr->layoutContext.leftMargin); HtmlClearMarginStack(&htmlPtr->layoutContext.rightMargin); } /* *--------------------------------------------------------------------------- * * HtmlRedrawCallback -- * * This routine is invoked in order to redraw all or part of the HTML * widget. This might happen because the display has changed, or in * response to an expose event. In all cases, though, this routine is * called by an idle callback. * * Results: * None. * * Side effects: * Layout engine might be run. The window contents might be modified. * *--------------------------------------------------------------------------- */ void HtmlRedrawCallback(clientData) ClientData clientData; /* The Html widget */ { HtmlWidget *htmlPtr = (HtmlWidget *) clientData; Tk_Window tkwin = htmlPtr->tkwin; Tk_Window clipwin = htmlPtr->clipwin; Pixmap pixmap; /* The buffer on which to render HTML */ int x, y, w, h; /* Virtual canvas coordinates of area * to draw */ int hw; /* highlight thickness */ int insetX, insetY; /* Total highlight thickness, border * width and ** padx/y */ int clipwinH, clipwinW; /* Width and height of the clipping * window */ HtmlBlock *pBlock; /* For looping over blocks to be drawn */ int redoSelection = 0; /* True to recompute the selection */ int top, bottom, left, right; /* Coordinates of the clipping window */ int imageTop; /* Top edge of image */ HtmlElement *pElem; /* * Don't bother doing anything if the widget is in the process of * being destroyed, or we are in the middle of a parse. */ if (tkwin == 0) { goto redrawExit; } if (htmlPtr->inParse) { htmlPtr->flags &= ~REDRAW_PENDING; goto redrawExit; } if ((htmlPtr->flags & RESIZE_ELEMENTS) != 0 && (htmlPtr->flags & STYLER_RUNNING) == 0) { HtmlImage *pImage; for (pImage = htmlPtr->imageList; pImage; pImage = pImage->pNext) { pImage->pList = 0; } htmlPtr->lastSized = 0; htmlPtr->flags &= ~RESIZE_ELEMENTS; htmlPtr->flags |= RELAYOUT; } /* * Recompute the layout, if necessary or requested. * * We used to make a distinction between RELAYOUT and EXTEND_LAYOUT. ** * RELAYOUT would be used when the widget was resized, but the ** less * compute-intensive EXTEND_LAYOUT would be used when new ** text was * appended. ** ** Unfortunately, EXTEND_LAYOUT has some problem that * arise when ** tables are used. The quick fix is to make an * EXTEND_LAYOUT do ** a complete RELAYOUT. Someday, we need to fix * EXTEND_LAYOUT so ** that it works right... * * Calling HtmlLayout() is tricky because HtmlLayout() may invoke one * or more callbacks (thru the "-imagecommand" callback, for instance) * and these callbacks could, in theory, do nasty things like delete * or unmap this widget. So we have to take precautions: * * * Don't remove the REDRAW_PENDING flag until after HtmlLayout() * has been called, to prevent a recursive call to * HtmlRedrawCallback(). * * * Call HtmlLock() on the htmlPtr structure to prevent it from * being deleted out from under us. */ if ((htmlPtr->flags & (RELAYOUT | EXTEND_LAYOUT)) != 0 && (htmlPtr->flags & STYLER_RUNNING) == 0) { htmlPtr->nextPlaced = 0; /* * htmlPtr->nInput = 0; */ htmlPtr->varId = 0; htmlPtr->maxX = 0; htmlPtr->maxY = 0; ResetLayoutContext(htmlPtr); htmlPtr->firstBlock = 0; htmlPtr->lastBlock = 0; redoSelection = 1; htmlPtr->flags &= ~RELAYOUT; htmlPtr->flags |= HSCROLL | VSCROLL | REDRAW_TEXT | EXTEND_LAYOUT; } if ((htmlPtr->flags & EXTEND_LAYOUT) && htmlPtr->pFirst != 0) { HtmlLock(htmlPtr); HtmlLayout(htmlPtr); if (HtmlUnlock(htmlPtr)) goto redrawExit; tkwin = htmlPtr->tkwin; htmlPtr->flags &= ~EXTEND_LAYOUT; HtmlFormBlocks(htmlPtr); HtmlMapControls(htmlPtr); if (redoSelection && htmlPtr->selBegin.p && htmlPtr->selEnd.p) { HtmlUpdateSelection(htmlPtr, 1); HtmlUpdateInsert(htmlPtr); } } htmlPtr->flags &= ~REDRAW_PENDING; /* * No need to do any actual drawing if we aren't mapped */ if (!Tk_IsMapped(tkwin)) { goto redrawExit; } /* * Redraw the scrollbars. Take care here, since the scrollbar ** update * command could (in theory) delete the html widget, or ** even the whole * interpreter. Preserve critical data structures, ** and check to see * if we are still alive before continuing. */ if ((htmlPtr->flags & (HSCROLL | VSCROLL)) != 0) { Tcl_Interp *interp = htmlPtr->interp; int result; char buf[200]; if ((htmlPtr->flags & HSCROLL) != 0) { if (htmlPtr->xScrollCmd && htmlPtr->xScrollCmd[0]) { HtmlComputeHorizontalPosition(htmlPtr, buf); HtmlLock(htmlPtr); result = Tcl_VarEval(interp, htmlPtr->xScrollCmd, " ", buf, 0); if (HtmlUnlock(htmlPtr)) goto redrawExit; if (result != TCL_OK) { Tcl_AddErrorInfo(interp, "\n (horizontal scrolling command executed by html widget)"); Tcl_BackgroundError(interp); } } htmlPtr->flags &= ~HSCROLL; } if ((htmlPtr->flags & VSCROLL) != 0 && tkwin && Tk_IsMapped(tkwin)) { if (htmlPtr->yScrollCmd && htmlPtr->yScrollCmd[0]) { Tcl_Interp *interp = htmlPtr->interp; int result; char buf[200]; HtmlComputeVerticalPosition(htmlPtr, buf); HtmlLock(htmlPtr); result = Tcl_VarEval(interp, htmlPtr->yScrollCmd, " ", buf, 0); if (HtmlUnlock(htmlPtr)) goto redrawExit; if (result != TCL_OK) { Tcl_AddErrorInfo(interp, "\n (horizontal scrolling command executed by html widget)"); Tcl_BackgroundError(interp); } } htmlPtr->flags &= ~VSCROLL; } tkwin = htmlPtr->tkwin; if (tkwin == 0 || !Tk_IsMapped(tkwin)) { goto redrawExit; } if (htmlPtr->flags & REDRAW_PENDING) { return; } clipwin = htmlPtr->clipwin; if (clipwin == 0) { goto redrawExit; } } /* * Redraw the focus highlight, if requested */ hw = htmlPtr->highlightWidth; if (htmlPtr->flags & REDRAW_FOCUS) { if (hw > 0) { GC gc; Tk_Window tkwin = htmlPtr->tkwin; if (htmlPtr->flags & GOT_FOCUS) { gc = Tk_GCForColor(htmlPtr->highlightColorPtr, Tk_WindowId(tkwin)); } else { gc = Tk_GCForColor(htmlPtr->highlightBgColorPtr, Tk_WindowId(tkwin)); } Tk_DrawFocusHighlight(tkwin, gc, hw, Tk_WindowId(tkwin)); } htmlPtr->flags &= ~REDRAW_FOCUS; } /* * Draw the borders around the parameter of the window. This is ** drawn * directly -- it is not double buffered. */ if (htmlPtr->flags & REDRAW_BORDER) { htmlPtr->flags &= ~REDRAW_BORDER; Tk_Fill3DRectangle(tkwin, Tk_WindowId(tkwin), htmlPtr->border, hw, /* x */ hw, /* y */ Tk_Width(tkwin) - 2 * hw, /* width */ Tk_Height(tkwin) - 2 * hw, /* height */ htmlPtr->borderWidth, htmlPtr->relief); } /* ** If the styler is in a callback, unmap the clipping window and ** abort further processing. */ if (htmlPtr->flags & STYLER_RUNNING) { if (Tk_IsMapped(clipwin)) { Tk_UnmapWindow(clipwin); } goto earlyOut; } /* ** If we don't have a clipping window, then something is seriously ** wrong. We might as well give up. */ if (clipwin == NULL) { goto earlyOut; } /* * Resize, reposition and map the clipping window, if necessary */ insetX = htmlPtr->padx + htmlPtr->inset; insetY = htmlPtr->pady + htmlPtr->inset; if (htmlPtr->flags & RESIZE_CLIPWIN) { int h, w; Tk_MoveResizeWindow(clipwin, insetX, insetY, htmlPtr->realWidth - 2 * insetX, htmlPtr->realHeight - 2 * insetY); if (!Tk_IsMapped(clipwin)) { Tk_MapWindow(clipwin); } h = htmlPtr->realHeight - 2 * insetY; if (htmlPtr->yOffset + h > htmlPtr->maxY) { htmlPtr->yOffset = htmlPtr->maxY - h; } if (htmlPtr->yOffset < 0) { htmlPtr->yOffset = 0; } w = htmlPtr->realWidth - 2 * insetX; if (htmlPtr->xOffset + w > htmlPtr->maxX) { htmlPtr->xOffset = htmlPtr->maxX - w; } if (htmlPtr->xOffset < 0) { htmlPtr->xOffset = 0; } htmlPtr->flags &= ~RESIZE_CLIPWIN; } HtmlMapControls(htmlPtr); /* ** Compute the virtual canvas coordinates corresponding to the ** dirty region of the clipping window. */ clipwinW = Tk_Width(clipwin); clipwinH = Tk_Height(clipwin); if (htmlPtr->flags & REDRAW_TEXT) { w = clipwinW; h = clipwinH; x = htmlPtr->xOffset; y = htmlPtr->yOffset; htmlPtr->dirtyLeft = 0; htmlPtr->dirtyTop = 0; htmlPtr->flags &= ~REDRAW_TEXT; } else { if (htmlPtr->dirtyLeft < 0) { htmlPtr->dirtyLeft = 0; } if (htmlPtr->dirtyRight > clipwinW) { htmlPtr->dirtyRight = clipwinW; } if (htmlPtr->dirtyTop < 0) { htmlPtr->dirtyTop = 0; } if (htmlPtr->dirtyBottom > clipwinH) { htmlPtr->dirtyBottom = clipwinH; } w = htmlPtr->dirtyRight - htmlPtr->dirtyLeft; h = htmlPtr->dirtyBottom - htmlPtr->dirtyTop; x = htmlPtr->xOffset + htmlPtr->dirtyLeft; y = htmlPtr->yOffset + htmlPtr->dirtyTop; } top = htmlPtr->yOffset; bottom = top + HtmlUsableHeight(htmlPtr); left = htmlPtr->xOffset; right = left + HtmlUsableWidth(htmlPtr); /* * Skip the rest of the drawing process if the area to be refreshed is ** * less than zero */ if (w > 0 && h > 0) { Display *display = htmlPtr->display; int dead; GC gcBg; XRectangle xrec; /* * fprintf(stderr,"Redraw %dx%d at %d,%d: %d,%d: %d,%d\n", w, h, x, * y, left, top, htmlPtr->dirtyLeft, htmlPtr->dirtyTop); */ /* * Allocate and clear a pixmap upon which to draw */ gcBg = HtmlGetGC(htmlPtr, COLOR_Background, FONT_Any); pixmap = Tk_GetPixmap(display, Tk_WindowId(clipwin), w, h, Tk_Depth(clipwin)); xrec.x = 0; xrec.y = 0; xrec.width = w; xrec.height = h; XFillRectangles(display, pixmap, gcBg, &xrec, 1); if (htmlPtr->bgimage) HtmlBGDraw(htmlPtr, left, top, w, h, pixmap, htmlPtr->bgimage); /* * Render all visible HTML onto the pixmap */ HtmlLock(htmlPtr); for (pBlock = htmlPtr->firstBlock; pBlock; pBlock = pBlock->pNext) { if (pBlock->top <= y + h && pBlock->bottom >= y && pBlock->left <= x + w && pBlock->right >= x) { HtmlBlockDraw(htmlPtr, pBlock, pixmap, x, y, w, h, pixmap); if (htmlPtr->tkwin == 0) break; } } dead = HtmlUnlock(htmlPtr); /* * Finally, copy the pixmap onto the window and delete the pixmap */ if (!dead) { XCopyArea(display, pixmap, Tk_WindowId(clipwin), gcBg, 0, 0, w, h, htmlPtr->dirtyLeft, htmlPtr->dirtyTop); } Tk_FreePixmap(display, pixmap); if (dead) goto redrawExit; /* * XFlush(display); */ } /* * Redraw images, if requested */ if (htmlPtr->flags & REDRAW_IMAGES) { HtmlImage *pImage; for (pImage = htmlPtr->imageList; pImage; pImage = pImage->pNext) { for (pElem = pImage->pList; pElem; pElem = pElem->image.pNext) { if (pElem->image.redrawNeeded == 0) continue; imageTop = pElem->image.y - pElem->image.ascent; if (imageTop > bottom || imageTop + pElem->image.h < top || pElem->image.x > right || pElem->image.x + pElem->image.w < left) { continue; } HtmlDrawImage(htmlPtr, pElem, Tk_WindowId(htmlPtr->clipwin), left, top, right, bottom); } } htmlPtr->flags &= ~(REDRAW_IMAGES | ANIMATE_IMAGES); } /* * Set the dirty region to the empty set. */ earlyOut: htmlPtr->dirtyTop = LARGE_NUMBER; htmlPtr->dirtyLeft = LARGE_NUMBER; htmlPtr->dirtyBottom = 0; htmlPtr->dirtyRight = 0; redrawExit: return; } /* ** If any part of the screen needs to be redrawn, Then call this routine ** with the values of a box (in window coordinates) that needs to be ** redrawn. This routine will make sure an idle callback is scheduled ** to do the redraw. ** ** The box coordinates are relative to the clipping window (clipwin), ** not the main window (tkwin). */ void HtmlRedrawArea(htmlPtr, left, top, right, bottom) HtmlWidget *htmlPtr; /* The widget to be redrawn */ int left; /* Top left corner of area to redraw */ int top; int right; /* bottom right corner of area to * redraw */ int bottom; { if (bottom < 0) { return; } if (top > htmlPtr->realHeight) { return; } if (right < 0) { return; } if (left > htmlPtr->realWidth) { return; } if (htmlPtr->dirtyTop > top) { htmlPtr->dirtyTop = top; } if (htmlPtr->dirtyLeft > left) { htmlPtr->dirtyLeft = left; } if (htmlPtr->dirtyBottom < bottom) { htmlPtr->dirtyBottom = bottom; } if (htmlPtr->dirtyRight < right) { htmlPtr->dirtyRight = right; } HtmlScheduleRedraw(htmlPtr); } /* Redraw the HtmlBlock given. */ void HtmlRedrawBlock(htmlPtr, p) HtmlWidget *htmlPtr; HtmlBlock *p; { if (p) { HtmlRedrawArea(htmlPtr, p->left - htmlPtr->xOffset, p->top - htmlPtr->yOffset, p->right - htmlPtr->xOffset + 1, p->bottom - htmlPtr->yOffset); } else { } } /* ** Call this routine to force the entire widget to be redrawn. */ void HtmlRedrawEverything(htmlPtr) HtmlWidget *htmlPtr; { htmlPtr->flags |= REDRAW_FOCUS | REDRAW_TEXT | REDRAW_BORDER; HtmlScheduleRedraw(htmlPtr); } /* ** Do the redrawing right now. Don't wait. */ #if 0 /* NOT_USED */ static void HtmlRedrawPush(HtmlWidget * htmlPtr) { if (htmlPtr->flags & REDRAW_PENDING) { Tcl_CancelIdleCall(HtmlRedrawCallback, (ClientData) htmlPtr); } else { } HtmlRedrawCallback((ClientData) htmlPtr); } #endif /* ** Call this routine to cause all of the rendered HTML at the ** virtual canvas coordinate of Y and beyond to be redrawn. */ void HtmlRedrawText(htmlPtr, y) HtmlWidget *htmlPtr; int y; { int yOffset; /* Top-most visible canvas coordinate */ int clipHeight; /* Height of the clipping window */ yOffset = htmlPtr->yOffset; clipHeight = HtmlUsableHeight(htmlPtr); y -= yOffset; if (y < clipHeight) { HtmlRedrawArea(htmlPtr, 0, y, LARGE_NUMBER, clipHeight); } else { } } /* ** Recalculate the preferred size of the html widget and pass this ** along to the geometry manager. */ static void HtmlRecomputeGeometry(htmlPtr) HtmlWidget *htmlPtr; { int w, h; /* Total width and height of the * widget */ htmlPtr->inset = htmlPtr->highlightWidth + htmlPtr->borderWidth; w = htmlPtr->width + 2 * (htmlPtr->padx + htmlPtr->inset); h = htmlPtr->height + 2 * (htmlPtr->pady + htmlPtr->inset); Tk_GeometryRequest(htmlPtr->tkwin, w, h); Tk_SetInternalBorder(htmlPtr->tkwin, htmlPtr->inset); } void HtmlClearTk(htmlPtr) HtmlWidget *htmlPtr; { int i; HtmlElement *p, *pNext; HtmlImage *Ip; htmlPtr->topmargin = htmlPtr->leftmargin = HTML_INDENT / 4; htmlPtr->marginwidth = htmlPtr->marginheight = HTML_INDENT / 4; for (i = N_PREDEFINED_COLOR; i < N_COLOR; i++) { if (htmlPtr->apColor[i] != 0) { Tk_FreeColor(htmlPtr->apColor[i]); htmlPtr->apColor[i] = 0; } } for (i = 0; i < N_COLOR; i++) { htmlPtr->iDark[i] = 0; htmlPtr->iLight[i] = 0; } htmlPtr->colorUsed = 0; while ((Ip = htmlPtr->imageList)) { htmlPtr->imageList = Ip->pNext; Tk_FreeImage(Ip->image); while (Ip->anims) { HtmlImageAnim *a = Ip->anims; Ip->anims = a->next; Tk_FreeImage(a->image); HtmlFree((char *) a); } HtmlFree(Ip); } if (htmlPtr->bgimage) { Tk_FreeImage(htmlPtr->bgimage); htmlPtr->bgimage = 0; } ClearGcCache(htmlPtr); ResetLayoutContext(htmlPtr); } void DestroyHtmlWidgetTk(htmlPtr) HtmlWidget *htmlPtr; { int i; Tk_FreeOptions(configSpecs, (char *) htmlPtr, htmlPtr->display, 0); for (i = 0; i < N_FONT; i++) { if (htmlPtr->aFont[i] != 0) { Tk_FreeFont(htmlPtr->aFont[i]); htmlPtr->aFont[i] = 0; } } HtmlFree(htmlPtr->zClipwin); } /* ** Flash the insertion cursor. */ void HtmlFlashCursor(clientData) ClientData clientData; { HtmlWidget *htmlPtr = (HtmlWidget *) clientData; if (htmlPtr->pInsBlock == 0 || htmlPtr->insOnTime <= 0 || htmlPtr->insOffTime <= 0) { htmlPtr->insTimer = 0; return; } HtmlRedrawBlock(htmlPtr, htmlPtr->pInsBlock); if ((htmlPtr->flags & GOT_FOCUS) == 0) { htmlPtr->insStatus = 0; htmlPtr->insTimer = 0; } else if (htmlPtr->insStatus) { htmlPtr->insTimer = Tcl_CreateTimerHandler(htmlPtr->insOffTime, HtmlFlashCursor, clientData); htmlPtr->insStatus = 0; } else { htmlPtr->insTimer = Tcl_CreateTimerHandler(htmlPtr->insOnTime, HtmlFlashCursor, clientData); htmlPtr->insStatus = 1; } } /* ** Return a GC from the cache. As many as N_CACHE_GCs are kept valid ** at any one time. They are replaced using an LRU algorithm. ** ** A value of FONT_Any (-1) for the font means "don't care". */ GC HtmlGetGC(htmlPtr, color, font) HtmlWidget *htmlPtr; int color; int font; { int i, j; GcCache *p = htmlPtr->aGcCache; XGCValues gcValues; int mask; Tk_Font tkfont; /* ** Check for an existing GC. */ if (color < 0 || color >= N_COLOR) { color = 0; } if (font < FONT_Any || font >= N_FONT) { font = FONT_Default; } for (i = 0; i < N_CACHE_GC; i++, p++) { if (p->index == 0) { continue; } if ((font < 0 || p->font == font) && p->color == color) { if (p->index > 1) { for (j = 0; j < N_CACHE_GC; j++) { if (htmlPtr->aGcCache[j].index && htmlPtr->aGcCache[j].index < p->index) { htmlPtr->aGcCache[j].index++; } } p->index = 1; } return htmlPtr->aGcCache[i].gc; } } /* ** No GC matches. Find a place to allocate a new GC. */ p = htmlPtr->aGcCache; for (i = 0; i < N_CACHE_GC; i++, p++) { if (p->index == 0 || p->index == N_CACHE_GC) { break; } } if (i >= N_CACHE_GC) { /* No slot, so free one: round-robin */ p = htmlPtr->aGcCache; for (i = 0; i < N_CACHE_GC && i < GcNextToFree; i++, p++); GcNextToFree = (GcNextToFree + 1) % N_CACHE_GC; Tk_FreeGC(htmlPtr->display, p->gc); /* * fprintf(stderr,"Tk_FreeGC: %d)\n", p->gc); */ } gcValues.foreground = htmlPtr->apColor[color]->pixel; gcValues.graphics_exposures = True; mask = GCForeground | GCGraphicsExposures; if (font < 0) { font = FONT_Default; } tkfont = HtmlGetFont(htmlPtr, font); if (tkfont) { gcValues.font = Tk_FontId(tkfont); mask |= GCFont; } p->gc = Tk_GetGC(htmlPtr->tkwin, mask, &gcValues); /* * fprintf(stderr,"Tk_GetGC: %d\n", p->gc); */ if (p->index == 0) { p->index = N_CACHE_GC + 1; } for (j = 0; j < N_CACHE_GC; j++) { if (htmlPtr->aGcCache[j].index && htmlPtr->aGcCache[j].index < p->index) { htmlPtr->aGcCache[j].index++; } } p->index = 1; p->font = font; p->color = color; return p->gc; } /* ** Retrieve any valid GC. The font and color don't matter since the ** GC will only be used for copying. */ GC HtmlGetAnyGC(htmlPtr) HtmlWidget *htmlPtr; { int i; GcCache *p = htmlPtr->aGcCache; for (i = 0; i < N_CACHE_GC; i++, p++) { if (p->index) { return p->gc; } } return HtmlGetGC(htmlPtr, COLOR_Normal, FONT_Default); } /* ** All window events (for both tkwin and clipwin) are ** sent to this routine. */ static void HtmlEventProc(clientData, eventPtr) ClientData clientData; XEvent *eventPtr; { HtmlWidget *htmlPtr = (HtmlWidget *) clientData; int redraw_needed = 0; XConfigureRequestEvent *p; switch (eventPtr->type) { case GraphicsExpose: case Expose: if (htmlPtr->tkwin == 0) { /* * The widget is being deleted. Do nothing */ } else if (eventPtr->xexpose.window != Tk_WindowId(htmlPtr->tkwin)) { /* * Exposure in the clipping window */ htmlPtr->flags |= ANIMATE_IMAGES; HtmlRedrawArea(htmlPtr, eventPtr->xexpose.x - 1, eventPtr->xexpose.y - 1, eventPtr->xexpose.x + eventPtr->xexpose.width + 1, eventPtr->xexpose.y + eventPtr->xexpose.height + 1); } else { /* * Exposure in the main window */ htmlPtr->flags |= (REDRAW_BORDER | ANIMATE_IMAGES); HtmlScheduleRedraw(htmlPtr); } break; case DestroyNotify: if ((htmlPtr->flags & REDRAW_PENDING)) { Tcl_CancelIdleCall(HtmlRedrawCallback, (ClientData) htmlPtr); htmlPtr->flags &= ~REDRAW_PENDING; } if (htmlPtr->tkwin != 0) { if (eventPtr->xany.window != Tk_WindowId(htmlPtr->tkwin)) { Tk_DestroyWindow(htmlPtr->tkwin); htmlPtr->clipwin = 0; break; } htmlPtr->tkwin = 0; Tcl_DeleteCommand(htmlPtr->interp, htmlPtr->zCmdName); Tcl_DeleteCommand(htmlPtr->interp, htmlPtr->zClipwin); } HtmlUnlock(htmlPtr); break; case ConfigureNotify: if (htmlPtr->tkwin != 0 && eventPtr->xconfigure.window == Tk_WindowId(htmlPtr->tkwin) ) { p = (XConfigureRequestEvent *) eventPtr; if (p->width != htmlPtr->realWidth) { redraw_needed = 1; htmlPtr->realWidth = p->width; } if (p->height != htmlPtr->realHeight) { redraw_needed = 1; htmlPtr->realHeight = p->height; } else { } if (redraw_needed) { htmlPtr->flags |= RELAYOUT | VSCROLL | HSCROLL | RESIZE_CLIPWIN; htmlPtr->flags |= ANIMATE_IMAGES; HtmlRedrawEverything(htmlPtr); } } break; case FocusIn: if (htmlPtr->tkwin != 0 && eventPtr->xfocus.window == Tk_WindowId(htmlPtr->tkwin) && eventPtr->xfocus.detail != NotifyInferior) { htmlPtr->flags |= GOT_FOCUS | REDRAW_FOCUS | ANIMATE_IMAGES; HtmlScheduleRedraw(htmlPtr); HtmlUpdateInsert(htmlPtr); } break; case FocusOut: if (htmlPtr->tkwin != 0 && eventPtr->xfocus.window == Tk_WindowId(htmlPtr->tkwin) && eventPtr->xfocus.detail != NotifyInferior) { htmlPtr->flags &= ~GOT_FOCUS; htmlPtr->flags |= REDRAW_FOCUS; HtmlScheduleRedraw(htmlPtr); } break; } } /* ** The rendering and layout routines should call this routine in order to get ** a font structure. The iFont parameter specifies which of the N_FONT ** fonts should be obtained. The font is allocated if necessary. ** ** Because the -fontcommand callback can be invoked, this function can ** (in theory) cause the HTML widget to be changed arbitrarily or even ** deleted. Callers of this function much be prepared to be called ** recursively and/or to have the HTML widget deleted out from under ** them. This routine will return NULL if the HTML widget is deleted. */ Tk_Font HtmlGetFont(htmlPtr, iFont) HtmlWidget *htmlPtr; /* The HTML widget to which the font * applies */ int iFont; /* Which font to obtain */ { Tk_Font toFree = 0; if (iFont < 0) { iFont = 0; } if (iFont >= N_FONT) { iFont = N_FONT - 1; CANT_HAPPEN; } /* ** If the font has previously been allocated, but the "fontValid" bitmap ** shows it is no longer valid, then mark it for freeing later. We use ** a policy of allocate-before-free because Tk's font cache operates ** much more efficiently that way. */ if (!FontIsValid(htmlPtr, iFont) && htmlPtr->aFont[iFont] != 0) { toFree = htmlPtr->aFont[iFont]; htmlPtr->aFont[iFont] = 0; } /* ** If we need to allocate a font, first construct the font name then ** allocate it. */ if (htmlPtr->aFont[iFont] == 0) { char name[200]; /* Name of the font */ name[0] = 0; /* * Run the -fontcommand if it is specified */ if (htmlPtr->zFontCommand && htmlPtr->zFontCommand[0]) { int iFam; /* The font family index. Value * between 0 and 7 */ Tcl_DString str; /* The command we'll execute to get * the font name */ char *zSep = ""; /* Separator between font attributes */ int rc; /* Return code from the font command */ char zBuf[100]; /* Temporary buffer */ Tcl_DStringInit(&str); Tcl_DStringAppend(&str, htmlPtr->zFontCommand, -1); sprintf(zBuf, " %d {", FontSize(iFont) + 1); Tcl_DStringAppend(&str, zBuf, -1); iFam = iFont / N_FONT_SIZE; if (iFam & 1) { Tcl_DStringAppend(&str, "bold", -1); zSep = " "; } if (iFam & 2) { Tcl_DStringAppend(&str, zSep, -1); Tcl_DStringAppend(&str, "italic", -1); zSep = " "; } if (iFam & 4) { Tcl_DStringAppend(&str, zSep, -1); Tcl_DStringAppend(&str, "fixed", -1); } Tcl_DStringAppend(&str, "}", -1); HtmlLock(htmlPtr); rc = Tcl_GlobalEval(htmlPtr->interp, Tcl_DStringValue(&str)); Tcl_DStringFree(&str); if (HtmlUnlock(htmlPtr)) { return NULL; } if (rc != TCL_OK) { Tcl_AddErrorInfo(htmlPtr->interp, "\n (-fontcommand callback of HTML widget)"); Tcl_BackgroundError(htmlPtr->interp); } else { sprintf(name, "%.100s", htmlPtr->interp->result); } Tcl_ResetResult(htmlPtr->interp); } /* ** If the -fontcommand failed or returned an empty string, or if ** there is no -fontcommand, then get the default font name. */ if (name[0] == 0) { char *familyStr = ""; int iFamily; int iSize; int size, finc = htmlPtr->FontAdjust; iFamily = iFont / N_FONT_SIZE; iSize = iFont % N_FONT_SIZE + 1; switch (iFamily) { case 0: familyStr = "%s -%d"; break; case 1: familyStr = "%s -%d bold"; break; case 2: familyStr = "%s -%d italic"; break; case 3: familyStr = "%s -%d bold italic"; break; case 4: familyStr = "%s -%d"; break; case 5: familyStr = "%s -%d bold"; break; case 6: familyStr = "%s -%d italic"; break; case 7: familyStr = "%s -%d bold italic"; break; default: familyStr = "%s -14"; CANT_HAPPEN; } switch (iSize) { case 1: size = 6 + finc; break; case 2: size = 10 + finc; break; case 3: size = 12 + finc; break; case 4: size = 14 + finc; break; case 5: size = 20 + finc; break; case 6: size = 24 + finc; break; case 7: size = 30 + finc; break; default: size = 14 + finc; CANT_HAPPEN; } sprintf(name, familyStr, htmlPtr->FontFamily, size); } /* * Get the named font */ htmlPtr->aFont[iFont] = Tk_GetFont(htmlPtr->interp, htmlPtr->tkwin, name); if (htmlPtr->aFont[iFont] == 0) { Tcl_AddErrorInfo(htmlPtr->interp, "\n (trying to create a font named \""); Tcl_AddErrorInfo(htmlPtr->interp, name); Tcl_AddErrorInfo(htmlPtr->interp, "\" in the HTML widget)"); Tcl_BackgroundError(htmlPtr->interp); htmlPtr->aFont[iFont] = Tk_GetFont(htmlPtr->interp, htmlPtr->tkwin, "fixed"); } if (htmlPtr->aFont[iFont] == 0) { Tcl_AddErrorInfo(htmlPtr->interp, "\n (trying to create font \"fixed\" in the HTML widget)"); Tcl_BackgroundError(htmlPtr->interp); htmlPtr->aFont[iFont] = Tk_GetFont(htmlPtr->interp, htmlPtr->tkwin, "helvetica -12"); } FontSetValid(htmlPtr, iFont); } /* ** Free the expired font, if any. */ if (toFree != 0) { Tk_FreeFont(toFree); } return htmlPtr->aFont[iFont]; } /* ** Compute the squared distance between two colors */ static float colorDistance(pA, pB) XColor *pA; XColor *pB; { float x, y, z; x = 0.30 * (pA->red - pB->red); y = 0.61 * (pA->green - pB->green); z = 0.11 * (pA->blue - pB->blue); return x * x + y * y + z * z; } /* ** This routine returns an index between 0 and N_COLOR-1 which indicates ** which XColor structure in the apColor[] array of htmlPtr should be ** used to describe the color specified by the given name. */ int HtmlGetColorByName(htmlPtr, zColor, def) HtmlWidget *htmlPtr; char *zColor; int def; { XColor *pNew; int iColor; Tk_Uid name; int i, n; char zAltColor[16]; /* * Netscape accepts color names that are just HEX values, without ** the * # up front. This isn't valid HTML, but we support it for ** * compatibility. */ n = strlen(zColor); if (n == 6 || n == 3 || n == 9 || n == 12) { for (i = 0; i < n; i++) { if (!isxdigit(zColor[i])) break; } if (i == n) { sprintf(zAltColor, "#%s", zColor); } else { strcpy(zAltColor, zColor); } name = Tk_GetUid(zAltColor); } else { name = Tk_GetUid(zColor); } pNew = Tk_GetColor(htmlPtr->interp, htmlPtr->clipwin, name); if (pNew == 0) { return def; } iColor = GetColorByValue(htmlPtr, pNew); Tk_FreeColor(pNew); if (iColor < N_COLOR) return iColor; return def; } /* ** Macros used in the computation of appropriate shadow colors. */ #define MAX_COLOR 65535 #define MAX(A,B) ((A)<(B)?(B):(A)) #define MIN(A,B) ((A)<(B)?(A):(B)) /* ** Check to see if the given color is too dark to be easily distinguished ** from black. */ static int isDarkColor(p) XColor *p; { float x, y, z; x = 0.50 * p->red; y = 1.00 * p->green; z = 0.28 * p->blue; return (x * x + y * y + z * z) < 0.05 * MAX_COLOR * MAX_COLOR; } /* ** Given that the background color is iBgColor, figure out an ** appropriate color for the dark part of a 3D shadow. */ int HtmlGetDarkShadowColor(htmlPtr, iBgColor) HtmlWidget *htmlPtr; int iBgColor; { if (htmlPtr->iDark[iBgColor] == 0) { XColor *pRef, val; pRef = htmlPtr->apColor[iBgColor]; if (isDarkColor(pRef)) { int t1, t2; t1 = MIN(MAX_COLOR, pRef->red * 1.2); t2 = (pRef->red * 3 + MAX_COLOR) / 4; val.red = MAX(t1, t2); t1 = MIN(MAX_COLOR, pRef->green * 1.2); t2 = (pRef->green * 3 + MAX_COLOR) / 4; val.green = MAX(t1, t2); t1 = MIN(MAX_COLOR, pRef->blue * 1.2); t2 = (pRef->blue * 3 + MAX_COLOR) / 4; val.blue = MAX(t1, t2); } else { val.red = pRef->red * 0.6; val.green = pRef->green * 0.6; val.blue = pRef->blue * 0.6; } htmlPtr->iDark[iBgColor] = GetColorByValue(htmlPtr, &val) + 1; } return htmlPtr->iDark[iBgColor] - 1; } /* ** Check to see if the given color is too light to be easily distinguished ** from white. */ static int isLightColor(p) XColor *p; { return p->green >= 0.85 * MAX_COLOR; } /* ** Given that the background color is iBgColor, figure out an ** appropriate color for the bright part of the 3D shadow. */ int HtmlGetLightShadowColor(htmlPtr, iBgColor) HtmlWidget *htmlPtr; int iBgColor; { if (htmlPtr->iLight[iBgColor] == 0) { XColor *pRef, val; pRef = htmlPtr->apColor[iBgColor]; if (isLightColor(pRef)) { val.red = pRef->red * 0.9; val.green = pRef->green * 0.9; val.blue = pRef->blue * 0.9; } else { int t1, t2; t1 = MIN(MAX_COLOR, pRef->green * 1.4); t2 = (pRef->green + MAX_COLOR) / 2; val.green = MAX(t1, t2); t1 = MIN(MAX_COLOR, pRef->red * 1.4); t2 = (pRef->red + MAX_COLOR) / 2; val.red = MAX(t1, t2); t1 = MIN(MAX_COLOR, pRef->blue * 1.4); t2 = (pRef->blue + MAX_COLOR) / 2; val.blue = MAX(t1, t2); } htmlPtr->iLight[iBgColor] = GetColorByValue(htmlPtr, &val) + 1; } return htmlPtr->iLight[iBgColor] - 1; } # define COLOR_MASK 0xf800 /* Eliminate remapped duplicate colors. */ int CheckDupColor(htmlPtr, slot) HtmlWidget *htmlPtr; int slot; { int i; int r, g, b; XColor *pRef = htmlPtr->apColor[slot]; r = pRef->red &= COLOR_MASK; g = pRef->green &= COLOR_MASK; b = pRef->blue &= COLOR_MASK; for (i = 0; i < N_COLOR; i++) { XColor *p = htmlPtr->apColor[i]; if (i == slot) continue; if (p && (p->red & COLOR_MASK) == r && (p->green & COLOR_MASK) == g && (p->blue & COLOR_MASK) == b) { htmlPtr->colorUsed &= ~(1LL << slot); htmlPtr->apColor[slot] = 0; return i; } } return slot; } /* ** Find a color integer for the color whose color components ** are given by pRef. */ int GetColorByValue(htmlPtr, pRef) HtmlWidget *htmlPtr; XColor *pRef; { int i; float dist; float closestDist; int closest; int r, g, b; /* * Search for an exact match */ r = pRef->red &= COLOR_MASK; g = pRef->green &= COLOR_MASK; b = pRef->blue &= COLOR_MASK; for (i = 0; i < N_COLOR; i++) { XColor *p = htmlPtr->apColor[i]; if (p && (p->red & COLOR_MASK) == r && (p->green & COLOR_MASK) == g && (p->blue & COLOR_MASK) == b) { htmlPtr->colorUsed |= (1LL << i); return i; } } /* * No exact matches. Look for a completely unused slot */ for (i = N_PREDEFINED_COLOR; i < N_COLOR; i++) { if (htmlPtr->apColor[i] == 0) { htmlPtr->apColor[i] = Tk_GetColorByValue(htmlPtr->clipwin, pRef); /* * Check if colow was remapped to an existing slot */ htmlPtr->colorUsed |= (1LL << i); return CheckDupColor(htmlPtr, i); } } /* * No empty slots. Look for a slot that contains a color that ** isn't * currently in use. */ for (i = N_PREDEFINED_COLOR; i < N_COLOR; i++) { if (((htmlPtr->colorUsed >> i) & 1LL) == 0) { Tk_FreeColor(htmlPtr->apColor[i]); htmlPtr->apColor[i] = Tk_GetColorByValue(htmlPtr->clipwin, pRef); htmlPtr->colorUsed |= (1LL << i); return CheckDupColor(htmlPtr, i); } } /* * Ok, find the existing color that is closest to the color requested ** * and use it. */ closest = 0; closestDist = colorDistance(pRef, htmlPtr->apColor[0]); for (i = 1; i < N_COLOR; i++) { dist = colorDistance(pRef, htmlPtr->apColor[i]); if (dist < closestDist) { closestDist = dist; closest = i; } } return i; } /* Only support rect for now */ int HtmlInArea(p, left, top, x, y) HtmlElement *p; int left; int top; int x; int y; { int *ip = p->area.coords; return (ip && (left + ip[0]) <= x && (top + ip[1]) <= y && (left + ip[2]) >= x && (top + ip[3]) >= y); } /* ** This routine searchs for a hyperlink beneath the coordinates x,y ** and returns a pointer to the HREF for that hyperlink. The text ** is held one of the markup.argv[] fields of the <a> markup. */ char * HtmlGetHref(htmlPtr, x, y, target) HtmlWidget *htmlPtr; int x; int y; char **target; { HtmlBlock *pBlock; HtmlElement *pElem; char *z; for (pBlock = htmlPtr->firstBlock; pBlock; pBlock = pBlock->pNext) { if (pBlock->top > y || pBlock->bottom < y || pBlock->left > x || pBlock->right < x) { continue; } pElem = pBlock->base.pNext; if (pElem->base.type == Html_IMG && pElem->image.pMap) { pElem = pElem->image.pMap->pNext; while (pElem && pElem->base.type != Html_EndMAP) { if (pElem->base.type == Html_AREA) if (HtmlInArea(pElem, pBlock->left, pBlock->top, x, y)) { *target = HtmlMarkupArg(pElem, "target", 0); return HtmlMarkupArg(pElem, "href", 0); } pElem = pElem->pNext; } continue; } if ((pElem->base.style.flags & STY_Anchor) == 0) { continue; } switch (pElem->base.type) { case Html_Text: case Html_Space: case Html_IMG: while (pElem && pElem->base.type != Html_A) { pElem = pElem->base.pPrev; } if (pElem == 0 || pElem->base.type != Html_A) { break; } *target = HtmlMarkupArg(pElem, "target", 0); return HtmlMarkupArg(pElem, "href", 0); default: break; } } return 0; } /* Return coordinates of item. */ int HtmlElementCoords(interp, htmlPtr, p, i, pct, coords) Tcl_Interp *interp; HtmlWidget *htmlPtr; HtmlElement *p; int i; int pct; int *coords; { HtmlBlock *pBlock; while (p && p->base.type != Html_Block) { p = p->base.pPrev; } if (!p) return 1; pBlock = &p->block; if (pct) { HtmlElement *pEnd = htmlPtr->pLast; HtmlBlock *pb2; while (pEnd && pEnd->base.type != Html_Block) { pEnd = pEnd->base.pPrev; } pb2 = &pEnd->block; #define HGCo(dir) pb2->dir?pBlock->dir*100/pb2->dir:0 coords[0] = HGCo(left); coords[1] = HGCo(top); coords[2] = HGCo(right); coords[3] = HGCo(bottom); } else { coords[0] = pBlock->left; coords[1] = pBlock->top; coords[2] = pBlock->right; coords[3] = pBlock->bottom; } return 0; } /* Return coordinates of item. */ void HtmlGetCoords(interp, htmlPtr, p, i, pct) Tcl_Interp *interp; HtmlWidget *htmlPtr; HtmlElement *p; int i; int pct; { Tcl_DString str; char *z, zLine[100]; int coords[4]; if (HtmlElementCoords(interp, htmlPtr, p, i, pct, coords)) return; Tcl_DStringInit(&str); sprintf(zLine, "%d %d %d %d", coords[0], coords[1], coords[2], coords[3]); Tcl_DStringAppend(&str, zLine, -1); Tcl_DStringResult(interp, &str); } /* ** Change the "yOffset" field from its current value to the value given. ** This has the effect of scrolling the widget vertically. */ void HtmlVerticalScroll(htmlPtr, yOffset) HtmlWidget *htmlPtr; int yOffset; { int inset; /* The 3D border plus the pady */ int h; /* Height of the clipping window */ int diff; /* Difference between old and new * offset */ GC gc; /* Graphics context used for copying */ int w; /* Width of text area */ if (yOffset == htmlPtr->yOffset) { return; } inset = htmlPtr->pady + htmlPtr->inset; h = htmlPtr->realHeight - 2 * inset; if ((htmlPtr->flags & REDRAW_TEXT) != 0 || (htmlPtr->dirtyTop < h && htmlPtr->dirtyBottom > 0) || htmlPtr->yOffset > yOffset + (h - 30) || htmlPtr->yOffset < yOffset - (h - 30) ) { htmlPtr->yOffset = yOffset; htmlPtr->flags |= VSCROLL | REDRAW_TEXT; HtmlScheduleRedraw(htmlPtr); return; } diff = htmlPtr->yOffset - yOffset; gc = HtmlGetAnyGC(htmlPtr); w = htmlPtr->realWidth - 2 * (htmlPtr->inset + htmlPtr->padx); htmlPtr->flags |= VSCROLL; htmlPtr->yOffset = yOffset; if (diff < 0) { XCopyArea(htmlPtr->display, Tk_WindowId(htmlPtr->clipwin), /* source */ Tk_WindowId(htmlPtr->clipwin), /* destination */ gc, 0, -diff, /* source X, Y */ w, h + diff, /* Width and height */ 0, 0); /* Destination X, Y */ HtmlRedrawArea(htmlPtr, 0, h + diff, w, h); } else { XCopyArea(htmlPtr->display, Tk_WindowId(htmlPtr->clipwin), /* source */ Tk_WindowId(htmlPtr->clipwin), /* destination */ gc, 0, 0, /* source X, Y */ w, h - diff, /* Width and height */ 0, diff); /* Destination X, Y */ HtmlRedrawArea(htmlPtr, 0, 0, w, diff); } /* * HtmlMapControls(htmlPtr); */ } /* ** Change the "xOffset" field from its current value to the value given. ** This has the effect of scrolling the widget horizontally. */ void HtmlHorizontalScroll(htmlPtr, xOffset) HtmlWidget *htmlPtr; int xOffset; { if (xOffset == htmlPtr->xOffset) { return; } htmlPtr->xOffset = xOffset; HtmlMapControls(htmlPtr); htmlPtr->flags |= HSCROLL | REDRAW_TEXT; HtmlScheduleRedraw(htmlPtr); } /* ** Make sure that a call to the HtmlRedrawCallback() routine has been ** queued. */ void HtmlScheduleRedraw(htmlPtr) HtmlWidget *htmlPtr; { if ((htmlPtr->flags & REDRAW_PENDING) == 0 && htmlPtr->tkwin != 0 && Tk_IsMapped(htmlPtr->tkwin) ) { Tcl_DoWhenIdle(HtmlRedrawCallback, (ClientData) htmlPtr); htmlPtr->flags |= REDRAW_PENDING; } } #endif /* _TCLHTML_ */ /* ** This routine is called in order to process a "configure" subcommand ** on the given html widget. */ int ConfigureHtmlWidgetObj(interp, htmlPtr, objc, objv, flags, realign) Tcl_Interp *interp; /* Write error message to this * interpreter */ HtmlWidget *htmlPtr; /* The Html widget to be configured */ int objc; /* Number of configuration arguments */ Tcl_Obj *CONST objv[]; /* Text of configuration arguments */ int flags; /* Configuration flags */ int realign; /* Always do a redraw if set */ { int rc; int i; int redraw = realign; /* True if a redraw is required. */ char *arg; /* * Scan thru the configuration options to see if we need to redraw ** the * widget. */ for (i = 0; redraw == 0 && i < objc; i += 2) { int c; int n; arg = Tcl_GetStringFromObj(objv[i], &n); if (arg[0] != '-') { redraw = 1; break; } c = arg[1]; if (c == 'c' && n > 4 && strncmp(arg, "-cursor", n) == 0) { /* * do nothing */ } else /* * The default case */ { redraw = 1; } } #ifdef _TCLHTML_ rc = TclConfigureWidgetObj(interp, htmlPtr, configSpecs, objc, objv, (char *) htmlPtr, flags); if (rc != TCL_OK || redraw == 0) { return rc; } #else { CONST char *sargv[20]; CONST char **argv; if (objc >= 19) { argv = calloc(sizeof(char *), objc + 1); for (i = 0; i < objc; i++) argv[i] = Tcl_GetString(objv[i]); argv[i] = 0; rc = Tk_ConfigureWidget(interp, htmlPtr->tkwin, configSpecs, objc, argv, (char *) htmlPtr, flags); HtmlFree(argv); } else { for (i = 0; i < objc; i++) sargv[i] = Tcl_GetString(objv[i]); sargv[i] = 0; rc = Tk_ConfigureWidget(interp, htmlPtr->tkwin, configSpecs, objc, sargv, (char *) htmlPtr, flags); } } if (rc != TCL_OK || redraw == 0) { return rc; } memset(htmlPtr->fontValid, 0, sizeof(htmlPtr->fontValid)); htmlPtr->apColor[COLOR_Normal] = htmlPtr->fgColor; htmlPtr->apColor[COLOR_Visited] = htmlPtr->oldLinkColor; htmlPtr->apColor[COLOR_Unvisited] = htmlPtr->newLinkColor; htmlPtr->apColor[COLOR_Selection] = htmlPtr->selectionColor; htmlPtr->apColor[COLOR_Background] = Tk_3DBorderColor(htmlPtr->border); Tk_SetBackgroundFromBorder(htmlPtr->tkwin, htmlPtr->border); if (htmlPtr->highlightWidth < 0) { htmlPtr->highlightWidth = 0; } if (htmlPtr->padx < 0) { htmlPtr->padx = 0; } if (htmlPtr->pady < 0) { htmlPtr->pady = 0; } if (htmlPtr->width < 100) { htmlPtr->width = 100; } if (htmlPtr->height < 100) { htmlPtr->height = 100; } if (htmlPtr->borderWidth < 0) { htmlPtr->borderWidth = 0; } htmlPtr->flags |= RESIZE_ELEMENTS | RELAYOUT | REDRAW_BORDER | RESIZE_CLIPWIN; HtmlRecomputeGeometry(htmlPtr); HtmlRedrawEverything(htmlPtr); ClearGcCache(htmlPtr); #endif return rc; } int HtmlNewWidget(clientData, interp, objc, objv) ClientData clientData; /* Main window */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument strings. */ { HtmlWidget *htmlPtr; Tk_Window new; Tk_Window clipwin; char *zClipwin; Tk_Window tkwin = (Tk_Window) clientData; static int varId = 1; /* Used to construct unique names */ int n; char *arg1 = Tcl_GetStringFromObj(objv[1], &n); #ifndef _TCLHTML_ new = Tk_CreateWindowFromPath(interp, tkwin, arg1, (char *) NULL); if (new == NULL) { return TCL_ERROR; } zClipwin = HtmlAlloc(n + 3); if (zClipwin == 0) { Tk_DestroyWindow(new); return TCL_ERROR; } sprintf(zClipwin, "%s.x", arg1); clipwin = Tk_CreateWindowFromPath(interp, new, zClipwin, 0); if (clipwin == 0) { Tk_DestroyWindow(new); HtmlFree(zClipwin); return TCL_ERROR; } #endif dbghtmlPtr = htmlPtr = HtmlAlloc(sizeof(HtmlWidget) + n + 1); memset(htmlPtr, 0, sizeof(HtmlWidget)); #ifdef _TCLHTML_ htmlPtr->tkwin = 1; #else htmlPtr->tkwin = new; htmlPtr->clipwin = clipwin; htmlPtr->zClipwin = zClipwin; htmlPtr->display = Tk_Display(new); #endif htmlPtr->interp = interp; htmlPtr->zCmdName = (char *) &htmlPtr[1]; strcpy(htmlPtr->zCmdName, arg1); htmlPtr->relief = TK_RELIEF_FLAT; htmlPtr->dirtyLeft = LARGE_NUMBER; htmlPtr->dirtyTop = LARGE_NUMBER; htmlPtr->flags = RESIZE_CLIPWIN; htmlPtr->varId = varId++; Tcl_CreateObjCommand(interp, htmlPtr->zCmdName, HtmlWidgetObjCommand, (ClientData) htmlPtr, HtmlCmdDeletedProc); #ifndef _TCLHTML_ Tcl_CreateObjCommand(interp, htmlPtr->zClipwin, HtmlWidgetObjCommand, (ClientData) htmlPtr, HtmlCmdDeletedProc); Tk_SetClass(new, "Html"); Tk_SetClass(clipwin, "HtmlClip"); Tk_CreateEventHandler(htmlPtr->tkwin, ExposureMask | StructureNotifyMask | FocusChangeMask, HtmlEventProc, (ClientData) htmlPtr); Tk_CreateEventHandler(htmlPtr->clipwin, ExposureMask | StructureNotifyMask, HtmlEventProc, (ClientData) htmlPtr); if (HtmlFetchSelectionPtr) { Tk_CreateSelHandler(htmlPtr->tkwin, XA_PRIMARY, XA_STRING, HtmlFetchSelectionPtr, (ClientData) htmlPtr, XA_STRING); Tk_CreateSelHandler(htmlPtr->clipwin, XA_PRIMARY, XA_STRING, HtmlFetchSelectionPtr, (ClientData) htmlPtr, XA_STRING); } #endif /* _TCLHTML_ */ if (ConfigureHtmlWidgetObj(interp, htmlPtr, objc - 2, objv + 2, 0, 1) != TCL_OK) { goto error; } Tcl_InitHashTable(&htmlPtr->tokenHash, TCL_STRING_KEYS); htmlPtr->tokenCnt = Html_TypeCount; #ifdef _TCLHTML_ interp->result = arg1; #else interp->result = Tk_PathName(htmlPtr->tkwin); #endif return TCL_OK; error: #ifndef _TCLHTML_ Tk_DestroyWindow(htmlPtr->tkwin); #endif return TCL_ERROR; } /* ** The following routine implements the Tcl "html" command. This command ** is used to create new HTML widgets only. After the widget has been ** created, it is manipulated using the widget command defined above. */ int HtmlObjCommand(clientData, interp, objc, objv) ClientData clientData; /* Main window */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument strings. */ { int n; char *arg1, *zn, zs, *cmd; cmd = Tcl_GetString(objv[0]); if (objc < 2) { Tcl_AppendResult(interp, "wrong # args: should be \"", cmd, " pathName ?options?\"", (char *) NULL); return TCL_ERROR; } arg1 = Tcl_GetStringFromObj(objv[1], &n); /* * If the first argument begins with ".", then it must be the ** name of * a new window the user wants to create. */ if (*arg1 == '.') return HtmlNewWidget(clientData, interp, objc, objv); return HtmlCommandObj(clientData, interp, objc, objv); } /* ** The following mess is used to define DLL_EXPORT. DLL_EXPORT is ** blank except when we are building a Windows95/NT DLL from this ** library. Some special trickery is necessary to make this wall ** work together with makeheaders. */ #if INTERFACE #define DLL_EXPORT #endif #if defined(USE_TCL_STUBS) && defined(__WIN32__) # undef DLL_EXPORT # define DLL_EXPORT __declspec(dllexport) #endif #ifndef DLL_EXPORT #define DLL_EXPORT #endif /* ** This routine is used to register the "html" command with the ** Tcl interpreter. This is the only routine in this file with ** external linkage. */ extern Tcl_Command htmlcmdhandle; #ifndef _TCLHTML_ int HtmlXErrorHandler(dsp, ev) Display *dsp; XErrorEvent *ev; { char buf[300]; /* #if ! defined(__WIN32__) */ #if 0 XGetErrorText(dsp, ev->error_code, buf, 300); fprintf(stderr, "X-Error: %s\n", buf); #endif /* if (dsp) abort(); if (ev) abort(); abort(); */ } DLL_EXPORT int Tkhtml_SafeInit(interp) Tcl_Interp *interp; { return Tkhtml_Init(interp); } DLL_EXPORT int Tkhtml_Init(interp) Tcl_Interp *interp; { #ifdef USE_TCL_STUBS if (Tcl_InitStubs(interp, "8.3", 0) == 0) { return TCL_ERROR; } if (Tk_InitStubs(interp, "8.3", 0) == 0) { return TCL_ERROR; } #endif htmlcmdhandle = Tcl_CreateObjCommand(interp, "html", HtmlObjCommand, Tk_MainWindow(interp), 0); /* * Tcl_GlobalEval(interp,HtmlLib); */ #ifdef DEBUG Tcl_LinkVar(interp, "HtmlTraceMask", (char *) &HtmlTraceMask, TCL_LINK_INT); #endif Tcl_StaticPackage(interp, "Tkhtml", Tkhtml_Init, Tkhtml_SafeInit); Tcl_PkgProvide(interp, HTML_PKGNAME, HTML_PKGVERSION); XSetErrorHandler(HtmlXErrorHandler); return Htmlexts_Init(interp); return TCL_OK; } #endif ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������tkHTML-4ee7aaa953d6cb59/src/htmlwish.c��������������������������������������������������������������0000644�0000000�0000000�00000001234�11512242631�0016707�0����������������������������������������������������������������������������������������������������ustar�00nobody��������������������������nobody�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������static char const rcsid[] = "@(#) $Id: htmlwish.c,v 1.10 2005/03/23 23:56:27 danielk1977 Exp $"; /* ** Make a "wish" that includes the html widget. ** ** This source code is released into the public domain by the author, ** D. Richard Hipp, on 2002 December 17. Instead of a license, here ** is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. */ #include "appinit.h" #ifndef _TCLHTML_ int Et_AppInit(interp) Tcl_Interp *interp; { extern int Tkhtml_Init(Tcl_Interp *); Tkhtml_Init(interp); return TCL_OK; } #endif ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������tkHTML-4ee7aaa953d6cb59/src/main.c������������������������������������������������������������������0000644�0000000�0000000�00000012516�11512242631�0016001�0����������������������������������������������������������������������������������������������������ustar�00nobody��������������������������nobody�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * tkAppInit.c -- * * Provides a default version of the Tcl_AppInit procedure for * use in wish and similar Tk-based applications. * *-------------------------------------------------------------------------- * Copyright (c) 1993 The Regents of the University of California. * Copyright (c) 1994-1997 Sun Microsystems, Inc. * Copyright (c) 2005 Eolas Technologies Inc. * All rights reserved. * * This Open Source project was made possible through the financial support * of Eolas Technologies Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the <ORGANIZATION> nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ static const char rcsid[] = "$Id: main.c,v 1.9 2007/09/28 14:14:56 danielk1977 Exp $"; #undef USE_TCL_STUBS #undef USE_TK_STUBS #include "tk.h" #include "locale.h" #ifdef TK_TEST extern int Tktest_Init _ANSI_ARGS_((Tcl_Interp *interp)); #endif /* TK_TEST */ /* *---------------------------------------------------------------------- * * main -- * * This is the main program for the application. * * Results: * None: Tk_Main never returns here, so this procedure never * returns either. * * Side effects: * Whatever the application does. * *---------------------------------------------------------------------- */ int main(argc, argv) int argc; /* Number of command-line arguments. */ char **argv; /* Values of command-line arguments. */ { /* * The following #if block allows you to change the AppInit * function by using a #define of TCL_LOCAL_APPINIT instead * of rewriting this entire file. The #if checks for that * #define and uses Tcl_AppInit if it doesn't exist. */ #ifndef TK_LOCAL_APPINIT #define TK_LOCAL_APPINIT Tcl_AppInit #endif extern int TK_LOCAL_APPINIT _ANSI_ARGS_((Tcl_Interp *interp)); /* * The following #if block allows you to change how Tcl finds the startup * script, prime the library or encoding paths, fiddle with the argv, * etc., without needing to rewrite Tk_Main() */ #ifdef TK_LOCAL_MAIN_HOOK extern int TK_LOCAL_MAIN_HOOK _ANSI_ARGS_((int *argc, char ***argv)); TK_LOCAL_MAIN_HOOK(&argc, &argv); #endif /* Tcl_InitStubs(0, "8.4", 0); */ /* Tk_InitStubs(0, "8.4", 0); */ Tk_Main(argc, argv, TK_LOCAL_APPINIT); return 0; /* Needed only to prevent compiler warning. */ } /* *---------------------------------------------------------------------- * * Tcl_AppInit -- * * This procedure performs application-specific initialization. * Most applications, especially those that incorporate additional * packages, will have their own version of this procedure. * * Results: * Returns a standard Tcl completion code, and leaves an error * message in the interp's result if an error occurs. * * Side effects: * Depends on the startup script. * *---------------------------------------------------------------------- */ int Tcl_AppInit(interp) Tcl_Interp *interp; /* Interpreter for application. */ { int Tkhtml_Init(Tcl_Interp *); int Tkhtml_SafeInit(Tcl_Interp *); if (Tcl_Init(interp) == TCL_ERROR) { return TCL_ERROR; } if (Tk_Init(interp) == TCL_ERROR) { return TCL_ERROR; } Tcl_StaticPackage(interp, "Tk", Tk_Init, Tk_SafeInit); #ifdef TK_TEST if (Tktest_Init(interp) == TCL_ERROR) { return TCL_ERROR; } Tcl_StaticPackage(interp, "Tktest", Tktest_Init, (Tcl_PackageInitProc *) NULL); #endif /* TK_TEST */ if (Tkhtml_Init(interp) == TCL_ERROR) { return TCL_ERROR; } Tcl_StaticPackage(interp, "Tkhtml", Tkhtml_Init, Tkhtml_SafeInit); /* * Specify a user-specific startup file to invoke if the application * is run interactively. Typically the startup file is "~/.apprc" * where "app" is the name of the application. If this line is deleted * then no user-specific startup file will be run under any conditions. */ Tcl_SetVar(interp, "tcl_rcFileName", "~/.wishrc", TCL_GLOBAL_ONLY); return TCL_OK; } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������tkHTML-4ee7aaa953d6cb59/src/mkdefaultstyle.tcl������������������������������������������������������0000644�0000000�0000000�00000002175�11512242631�0020452�0����������������������������������������������������������������������������������������������������ustar�00nobody��������������������������nobody����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������� proc FileToDefine {file define} { set fd [open $file] append ret "#define $define \\" while {![eof $fd]} { set line [string map [list \" \\\" \\ \\\\] [gets $fd]] append ret "\n \"$line\\n\" \\" } append ret "\n\n\n" return $ret } proc VersionsToDefine {glob define} { set ret "#define $define \\\n" foreach file [glob $glob] { set fd [open $file] set contents [read $fd] close $fd set DOLLAR $ set expression \\${DOLLAR}Id:(\[^${DOLLAR}\]*)\\${DOLLAR} if {[regexp $expression $contents dummy match]} { append ret " \"[string trim $match]\\n\" \\\n" } } return $ret } set css_file [file join [file dirname [info script]] .. src html.css] set tcl_file [file join [file dirname [info script]] .. src tkhtml.tcl] set quirks_file [file join [file dirname [info script]] quirks.css] set src_files [file join [file dirname [info script]] {*.c}] puts "" puts [FileToDefine $tcl_file HTML_DEFAULT_TCL] puts [FileToDefine $css_file HTML_DEFAULT_CSS] puts [FileToDefine $quirks_file HTML_DEFAULT_QUIRKS] puts [VersionsToDefine $src_files HTML_SOURCE_FILES] ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������tkHTML-4ee7aaa953d6cb59/src/quirks.css��������������������������������������������������������������0000644�0000000�0000000�00000001345�11512242631�0016737�0����������������������������������������������������������������������������������������������������ustar�00nobody��������������������������nobody����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������� /*------------------------------*/ /* QUIRKS MODE RULES */ /*------------------------------*/ /* Tables are historically special. All font attributes except font-family, * text-align, white-space and line-height) take their initial values. */ TABLE { white-space: normal; line-height: normal; font-size: medium; font-weight: normal; font-style: normal; font-variant: normal; text-align: left; } TABLE[align] { text-align: left; } /* Vertical margins of <p> elements do not collapse against the top or * bottom of containing table cells. */ TH > P:first-child, TD > P:first-child { margin-top: 0px; } TH > P:last-child, TD > P:last-child { margin-bottom: 0px; } FORM { margin-bottom: 1em; } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������tkHTML-4ee7aaa953d6cb59/src/restrack.c��������������������������������������������������������������0000644�0000000�0000000�00000045140�11512242631�0016672�0����������������������������������������������������������������������������������������������������ustar�00nobody��������������������������nobody�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * restrack.c -- * * This file contains wrappers for functions that dynamically allocate * and deallocate resources (for example ckalloc() and ckfree()). The * purpose of this is to provide a built-in system for debugging * problems with dynamic resource allocation and buffer-overruns. * * Currently, only heap memory is managed, but others (colors, fonts, * pixmaps, Tcl_Obj, etc.) are to be added later. * * Heap memory alloc/free wrappers: * Rt_Alloc() * Rt_Realloc() * Rt_Free() * * Other externally available functions: * Rt_AllocCommand() * This implements the [::tkhtml::htmlalloc] command. See * below for details. * * HtmlHeapDebug() * This implements the [::tkhtml::heapdebug] command. See * below for details. * * No tkhtml code outside of this file should call ckalloc() and * friends directly. * * This code is not thread safe. It's only for debugging. * *------------------------------------------------------------------------- * * Copyright (c) 2005 Dan Kennedy. * All rights reserved. * * This Open Source project was made possible through the financial support * of Eolas Technologies Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of Eolas Technologies Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * */ static const char rcsid[] = "$Id: restrack.c,v 1.13 2007/12/12 04:50:29 danielk1977 Exp $"; #ifdef HTML_RES_DEBUG #define RES_DEBUG #endif #include "tcl.h" #include "tk.h" #include <stdio.h> #ifdef RES_DEBUG #include <execinfo.h> #endif #include <string.h> #include <assert.h> #ifndef NDEBUG #define MAX(x,y) ((x)>(y)?(x):(y)) #define MIN(x,y) ((x)<(y)?(x):(y)) #define RES_ALLOC 0 #define RES_OBJREF 1 #define RES_GC 2 #define RES_PIXMAP 3 #define RES_XCOLOR 4 static const char *aResNames[] = { "memory allocation", /* RES_ALLOC */ "tcl object reference", /* RES_OBJREF */ "GC", /* RES_GC */ "pixmap", /* RES_PIXMAP */ "xcolor", /* RES_XCOLOR */ 0 }; static int aResCounts[] = {0, 0, 0, 0, 0}; /* * If RES_DEBUG is defined and glibc is in use, then a little extra * accounting is enabled. * * The interface to the accounting system is: * * ResAlloc() - Note the allocation of a resource. * ResFree() - Note the deallocation of a resource. * ResDump() - Print a catalogue of all currently allocated * resources to stdout. * * Each resource is identified by two ClientData variables, one to identify * the type of resource and another to identify the unique resource * instance. Collectively, the two ClientData values make up a * "resource-id". The global hash table, aOutstanding, contains a mapping * between resource-id and a ResRecord structure instance for every * currently allocated resource: * * (<res-type> <res-ptr>) -> ResRecord * * There can be more than one reference to a single resource, so reference * counted resources (Tcl_Obj* for example) can be used with this system. */ /* * Each ResRecord structure stores info for a currently allocated resource. * The information stored is the number of references to the resource, and * the backtraces of each of the call-chains that reserved a reference. * A "backtrace" is obtained from the non-standard backtrace() function * implemented in glibc. * * There may be more backtraces than outstanding references. This is * because when a reference is returned via ResFree(), it is not possible * to tell which of the backtraces to remove. For example, if the sequence * of calls is: * * Rt_IncrRefCount(); * Rt_IncrRefCount(); * Rt_DecrRefCount(); * * the ResRecord structure has nRef==1, nStack==2 and aStack pointing to an * array of size 2. */ typedef struct ResRecord ResRecord; struct ResRecord { int nRef; /* Current number of outstanding references */ int nStack; /* Number of stored stack-dumps */ int **aStack; /* Array of stored stack-dumps */ }; /* * Global hash table of currently outstanding resource references. */ #if defined(RES_DEBUG) && defined(__GLIBC__) static Tcl_HashTable aOutstanding; #endif /* *--------------------------------------------------------------------------- * * ResAlloc -- * * Add an entry to aOutstanding for the resource identified by (v1, v2). * Or, if the resource already exists, increment it's ref-count and * add a new stack-trace. * * Results: * None. * * Side effects: * See above. * *--------------------------------------------------------------------------- */ static void ResAlloc(v1, v2) ClientData v1; ClientData v2; { #if defined(RES_DEBUG) && defined(__GLIBC__) int key[2]; int newentry; Tcl_HashEntry *pEntry; int *aFrame; ResRecord *pRec; static int init = 0; if (!init) { Tcl_InitHashTable(&aOutstanding, 2); init = 1; } key[0] = (int)v1; key[1] = (int)v2; pEntry = Tcl_CreateHashEntry(&aOutstanding, (const char *)key, &newentry); if (newentry) { pRec = (ResRecord *)ckalloc(sizeof(ResRecord)); memset(pRec, 0, sizeof(ResRecord)); Tcl_SetHashValue(pEntry, pRec); } else { pRec = Tcl_GetHashValue(pEntry); } aFrame = (int *)ckalloc(sizeof(int) * 30); backtrace((void *)aFrame, 29); aFrame[29] = 0; pRec->nRef++; pRec->nStack++; pRec->aStack = (int **)ckrealloc( (char *)pRec->aStack, sizeof(int *) * pRec->nStack ); pRec->aStack[pRec->nStack - 1] = aFrame; #endif aResCounts[(int)((size_t) v1)]++; } /* *--------------------------------------------------------------------------- * * ResFree -- * * Decrement the reference count of the resource identified by (v1, v2). * If the ref-count reaches 0, remove the entry from the aOutstanding * hash table. * * Results: * None. * * Side effects: * See above. * *--------------------------------------------------------------------------- */ static void ResFree(v1, v2) ClientData v1; ClientData v2; { #if defined(RES_DEBUG) && defined(__GLIBC__) int key[2]; Tcl_HashEntry *pEntry; ResRecord *pRec; key[0] = (int)v1; key[1] = (int)v2; pEntry = Tcl_FindHashEntry(&aOutstanding, (const char *)key); assert(pEntry); pRec = (ResRecord *)Tcl_GetHashValue(pEntry); pRec->nRef--; if (pRec->nRef == 0) { int i; ResRecord *pRec = (ResRecord *)Tcl_GetHashValue(pEntry); for (i = 0; i < pRec->nStack; i++) { ckfree((char *)pRec->aStack[i]); } ckfree((char *)pRec->aStack); ckfree((char *)pRec); Tcl_DeleteHashEntry(pEntry); } #endif aResCounts[(int)((size_t) v1)]--; } /* *--------------------------------------------------------------------------- * * ResDump -- * * Print the current contents of the global hash table aOutstanding to * stdout. * * Results: * None. * * Side effects: * None. * *--------------------------------------------------------------------------- */ static void ResDump() { #if defined(RES_DEBUG) && defined(__GLIBC__) Tcl_HashEntry *pEntry; Tcl_HashSearch search; for ( pEntry = Tcl_FirstHashEntry(&aOutstanding, &search); pEntry; pEntry = Tcl_NextHashEntry(&search) ) { int *aKey = (int *)Tcl_GetHashKey(&aOutstanding, pEntry); ResRecord *pRec = (ResRecord *)Tcl_GetHashValue(pEntry); int i; printf("RESOURCE %x %x ", aKey[0], aKey[1]); for (i = 0; i < pRec->nStack; i++) { int j; printf("{"); for (j = 0; pRec->aStack[i][j]; j++) { printf("%x%s", pRec->aStack[i][j], pRec->aStack[i][j+1]?" ":""); } printf("} "); } printf("\n"); } #endif } /* *--------------------------------------------------------------------------- * End of ResTrack code. *--------------------------------------------------------------------------- */ /* * Two hash tables to maintain a summary of the currently outstanding * calls to HtmlAlloc() (used to measure approximate heap usage). They * are manipulated exclusively by the following functions: * * * initMallocHash() * * insertMallocHash() * * freeMallocHash() * * Each call to Rt_Alloc() or Rt_Realloc() is passed a "topic" argument * (a string). Usually, the topic is the name of the structure being * allocated (i.e. "HtmlComputedValues"), but can be anything. * * The aMalloc table is a mapping from topic name to the total number * of bytes currently allocated specifying that topic. i.e: * * "HtmlComputedValues" -> 4068 * "HtmlNode" -> 13456 * ... * * The aAllocationType is a mapping from each pointer returned by * Rt_Alloc() or Rt_Realloc() to a pointer to the hash entry corresponding * to that topic in the aMalloc table. */ static Tcl_HashTable aMalloc; static Tcl_HashTable aAllocationType; /* *--------------------------------------------------------------------------- * * initMallocHash -- * * Initialise the global aMalloc and aAllocationType hash tables. * This function is a no-op if they have already been initialised. * * Results: * None. * * Side effects: * May initialise aMalloc and aAllocationType. * *--------------------------------------------------------------------------- */ static void initMallocHash() { static int init = 0; if (!init) { Tcl_InitHashTable(&aMalloc, TCL_STRING_KEYS); Tcl_InitHashTable(&aAllocationType, TCL_ONE_WORD_KEYS); init = 1; } } /* *--------------------------------------------------------------------------- * * insertMallocHash -- * * Insert an entry into the aMalloc/aAllocationType database. * * Results: * None. * * Side effects: * May initialise aMalloc and aAllocationType. May insert an entry into * aMalloc. Always inserts an entry into aAllocationType. * *--------------------------------------------------------------------------- */ static void insertMallocHash(zTopic, p, nBytes) const char *zTopic; /* Topic for allocation */ char *p; /* Pointer just allocated by Rt_Alloc()/Realloc() */ int nBytes; /* Number of bytes allocated at p */ { int *aData; int isNewEntry; Tcl_HashEntry *pEntry; Tcl_HashEntry *pEntry2; initMallocHash(); pEntry = Tcl_CreateHashEntry(&aMalloc, zTopic, &isNewEntry); if (isNewEntry) { aData = (int *)ckalloc(sizeof(int) * 2); aData[0] = 1; aData[1] = nBytes; Tcl_SetHashValue(pEntry, aData); } else { aData = Tcl_GetHashValue(pEntry); aData[0] += 1; aData[1] += nBytes; } pEntry2 = Tcl_CreateHashEntry(&aAllocationType, p, &isNewEntry); Tcl_SetHashValue(pEntry2, pEntry); } /* *--------------------------------------------------------------------------- * * freeMallocHash -- * * Remove an entry from the aMalloc/aAllocationType database. If * the supplied pointer is not in the database, an assert() will * fail. * * Results: * None. * * Side effects: * Removes an entry from aAllocationType hash table. * *--------------------------------------------------------------------------- */ static void freeMallocHash(p, nBytes) char *p; /* Pointer to remove from db */ int nBytes; /* Number of bytes (previously) allocated at p */ { int *aData; Tcl_HashEntry *pEntryAllocationType; Tcl_HashEntry *pEntryMalloc; initMallocHash(); pEntryAllocationType = Tcl_FindHashEntry(&aAllocationType, p); assert(pEntryAllocationType); pEntryMalloc = (Tcl_HashEntry *)Tcl_GetHashValue(pEntryAllocationType); assert(pEntryMalloc); aData = Tcl_GetHashValue(pEntryMalloc); aData[0] -= 1; aData[1] -= nBytes; assert((aData[0] == 0 && aData[1] == 0) || (aData[0] > 0 && aData[1] >= 0)); if (aData[0] == 0) { Tcl_DeleteHashEntry(pEntryMalloc); ckfree((char *)aData); } Tcl_DeleteHashEntry(pEntryAllocationType); } /* *--------------------------------------------------------------------------- * * HtmlHeapDebug -- * * ::tkhtml::heapdebug * * This Tcl command reports on the currently outstanding heap memory * allocations made by the Html widget code. A Tcl list is returned * containing a single entry for each allocation "topic" used by * the html widget (see above). Each list entry is itself a list * of length three, as follows: * * [list TOPIC N-ALLOCATIONS N-BYTES] * * i.e.: * * [list HtmlComputedValues 4 544] * * indicates that 4 HtmlComputedValues structures are allocated for * a total of 544 bytes. * * Results: * Always TCL_OK. * * Side effects: * Populates the tcl interpreter with a result. * *--------------------------------------------------------------------------- */ int HtmlHeapDebug(clientData, interp, objc, objv) ClientData clientData; Tcl_Interp *interp; int objc; Tcl_Obj * const objv[]; { Tcl_Obj *pRet = Tcl_NewObj(); Tcl_HashEntry *pEntry; Tcl_HashSearch search; for ( pEntry = Tcl_FirstHashEntry(&aMalloc, &search); pEntry; pEntry = Tcl_NextHashEntry(&search) ) { const char *zTopic = (const char *)Tcl_GetHashKey(&aMalloc, pEntry); int *aData = (int *)Tcl_GetHashValue(pEntry); Tcl_Obj *pObj = Tcl_NewObj(); Tcl_ListObjAppendElement(interp, pObj, Tcl_NewStringObj(zTopic, -1)); Tcl_ListObjAppendElement(interp, pObj, Tcl_NewIntObj(aData[0])); Tcl_ListObjAppendElement(interp, pObj, Tcl_NewIntObj(aData[1])); Tcl_ListObjAppendElement(interp, pRet, pObj); } Tcl_SetObjResult(interp, pRet); return TCL_OK; } /* *--------------------------------------------------------------------------- * * Rt_AllocCommand -- * * ::tkhtml::htmlalloc * * This Tcl command is only available if NDEBUG is not defined. It * returns a Tcl key-value list (suitable for passing to [array set]) * containing the names of the managed resource types and the number * of outstanding allocations. i.e: * * [list "memory allocation" 345 "tcl object reference" 0 ....] * * Note: At this stage all except "memory allocation" will be 0. * * This function also invokes ResDump(). So if RES_DEBUG is defined at * compile time and glibc is in use some data may be dumped to stdout. * * Results: * Always TCL_OK. * * Side effects: * Populates the tcl interpreter with a result. Invokes ResDump(). * *--------------------------------------------------------------------------- */ int Rt_AllocCommand(clientData, interp, objc, objv) ClientData clientData; Tcl_Interp *interp; int objc; Tcl_Obj * const objv[]; { int i; Tcl_Obj *pRet; pRet = Tcl_NewObj(); for (i = 0; aResNames[i]; i++) { Tcl_Obj *pName = Tcl_NewStringObj(aResNames[i],-1); Tcl_ListObjAppendElement(interp, pRet, pName); Tcl_ListObjAppendElement(interp, pRet, Tcl_NewIntObj(aResCounts[i])); } Tcl_SetObjResult(interp, pRet); ResDump(); return TCL_OK; } /* *--------------------------------------------------------------------------- * * Rt_Alloc -- * * A wrapper around ckalloc() for use by code outside of this file. * * Results: * None. * * Side effects: * None. * *--------------------------------------------------------------------------- */ char * Rt_Alloc(zTopic, n) const char *zTopic; int n; { int nAlloc = n + 4 * sizeof(int); int *z = (int *)ckalloc(nAlloc); char *zRet = (char *)&z[2]; z[0] = 0xFED00FED; z[1] = n; z[3 + n / sizeof(int)] = 0xBAD00BAD; ResAlloc(RES_ALLOC, z); insertMallocHash(zTopic ? zTopic : "UNSPECIFIED", zRet, n); memset(zRet, 0x55, n); return zRet; } /* *--------------------------------------------------------------------------- * * Rt_Free -- * * A wrapper around ckfree() for use by code outside of this file. * * Results: * None. * * Side effects: * None. * *--------------------------------------------------------------------------- */ void Rt_Free(p) char *p; { if (p) { int *z = (int *)p; int n = z[-1]; assert(z[-2] == 0xFED00FED); assert(z[1 + n / sizeof(int)] == 0xBAD00BAD); memset(z, 0x55, n); ckfree((char *)&z[-2]); ResFree(RES_ALLOC, &z[-2]); freeMallocHash((char *) z, n); } } /* *--------------------------------------------------------------------------- * * Rt_Realloc -- * * A wrapper around ckrealloc() for use by code outside of this file. * * Results: * None. * * Side effects: * None. * *--------------------------------------------------------------------------- */ char * Rt_Realloc(zTopic, p, n) const char *zTopic; char *p; int n; { char *pRet = Rt_Alloc(zTopic, n); if (p) { int current_sz = ((int *)p)[-1]; memcpy(pRet, p, MIN(current_sz, n)); Rt_Free((char *)p); } return pRet; } #endif ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������tkHTML-4ee7aaa953d6cb59/src/restrack.h��������������������������������������������������������������0000644�0000000�0000000�00000000523�11512242631�0016673�0����������������������������������������������������������������������������������������������������ustar�00nobody��������������������������nobody����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������� #ifndef __RESTRACK_H__ #define __RESTRACK_H__ #include <tcl.h> char * Rt_Alloc(const char * ,int); char * Rt_Realloc(const char *, char *, int); void Rt_Free(char *); int HtmlHeapDebug(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj * const objv[]); Tcl_ObjCmdProc Rt_AllocCommand; Tcl_ObjCmdProc HtmlHeapDebug; #endif �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������tkHTML-4ee7aaa953d6cb59/src/swproc.c����������������������������������������������������������������0000644�0000000�0000000�00000025117�11512242631�0016373�0����������������������������������������������������������������������������������������������������ustar�00nobody��������������������������nobody����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������� #include <tcl.h> #include <assert.h> #include <string.h> #include "swproc.h" static const char rcsid[] = "$Id: swproc.c,v 1.6 2006/06/10 12:38:38 danielk1977 Exp $"; /* *--------------------------------------------------------------------------- * * SwprocRt -- * * This function is used to interpret the arguments passed to a Tcl * command. The assumption is that Tcl commands take three types of * arguments: * * * Regular arguments, the type interpeted automatically by * [proc]. When using this function, regular arguments may not * have default values. * * * Switches that take arguments. * * * Switches that do not require an argument (called "options"). * * Results: * None. * * Side effects: * None. * *--------------------------------------------------------------------------- */ int SwprocRt(interp, objc, objv, aConf, apObj) Tcl_Interp *interp; /* Tcl interpreter */ int objc; Tcl_Obj *CONST objv[]; SwprocConf *aConf; Tcl_Obj **apObj; { SwprocConf *pConf; int ii; int jj; int argsatend = 0; int argcnt = 0; /* Number of compulsory arguments */ int firstarg; /* Index of first compulsory arg in aConf */ int lastswitch; /* Index of element after last switch or option */ char const *zSwitch; /* Set all the entries in apObj[] to 0. This makes cleaning up in the * case of an error easier. Also, check whether the compulsory * arguments (if any) are at the start or end of the array. Set argcnt * to the number of compulsory args. */ argsatend = (aConf[0].eType == SWPROC_ARG) ? 0 : 1; for (jj = 0; aConf[jj].eType != SWPROC_END; jj++) { apObj[jj] = 0; if (aConf[jj].eType == SWPROC_ARG) { argcnt++; } } /* Set values of compulsory arguments. Also set all switches and * options to their default values. */ firstarg = argsatend ? (objc - argcnt) : 0; ii = firstarg; for (jj = 0; aConf[jj].eType != SWPROC_END; jj++) { pConf = &aConf[jj]; if (pConf->eType == SWPROC_ARG) { if (ii < objc && ii >= 0) { apObj[jj] = objv[ii]; Tcl_IncrRefCount(apObj[jj]); ii++; } else { goto error_insufficient_args; } } else if (pConf->zDefault) { apObj[jj] = Tcl_NewStringObj(pConf->zDefault, -1); Tcl_IncrRefCount(apObj[jj]); } } /* Now set values for any options or switches passed */ lastswitch = (argsatend ? firstarg : objc); for (ii = (argsatend ? 0 : argcnt); ii < lastswitch ;ii++) { zSwitch = Tcl_GetString(objv[ii]); if (zSwitch[0] != '-') { goto error_no_such_option; } for (jj = 0; aConf[jj].eType != SWPROC_END; jj++) { pConf = &aConf[jj]; if (pConf->eType == SWPROC_OPT || pConf->eType == SWPROC_SWITCH) { if (0 == strcmp(pConf->zSwitch, &zSwitch[1])) { if (apObj[jj]) { Tcl_DecrRefCount(apObj[jj]); apObj[jj] = 0; } if (pConf->eType == SWPROC_SWITCH) { apObj[jj] = Tcl_NewStringObj(pConf->zTrue, -1); Tcl_IncrRefCount(apObj[jj]); } else if (ii+1 < lastswitch) { ii++; apObj[jj] = objv[ii]; Tcl_IncrRefCount(apObj[jj]); } else { goto error_option_requires_arg; } break; } } } if (aConf[jj].eType == SWPROC_END) { goto error_no_such_option; } } return TCL_OK; error_insufficient_args: Tcl_AppendResult(interp, "Insufficient args", 0); goto error_out; error_no_such_option: Tcl_AppendResult(interp, "No such option: ", zSwitch, 0); goto error_out; error_option_requires_arg: Tcl_AppendResult(interp, "Option \"", zSwitch, "\"requires an argument", 0); goto error_out; error_out: /* Any error condition eventually jumps here. Discard any accumulated * object references and return TCL_ERROR. */ for (jj = 0; aConf[jj].eType != SWPROC_END; jj++) { if (apObj[jj]) { Tcl_DecrRefCount(apObj[jj]); apObj[jj] = 0; } } return TCL_ERROR; } /* *--------------------------------------------------------------------------- * * SwprocCleanup -- * * Results: * None. * * Side effects: * None. * *--------------------------------------------------------------------------- */ void SwprocCleanup(apObj, nObj) Tcl_Obj **apObj; int nObj; { int ii; for (ii = 0; ii < nObj; ii++) { if (apObj[ii]) { Tcl_DecrRefCount(apObj[ii]); } } } /* *--------------------------------------------------------------------------- * * swproc_rtCmd -- * * Results: * None. * * Side effects: * None. * *--------------------------------------------------------------------------- */ static int swproc_rtCmd(clientData, interp, objc, objv) ClientData clientData; /* The HTML widget data structure */ Tcl_Interp *interp; /* Current interpreter. */ int objc; /* Number of arguments. */ Tcl_Obj *CONST objv[]; /* Argument strings. */ { SwprocConf aConf[2 + 1] = { {SWPROC_ARG, "conf", 0, 0}, /* CONFIGURATION */ {SWPROC_ARG, "args", 0, 0}, /* ARGUMENTS */ {SWPROC_END, 0, 0, 0} }; Tcl_Obj *apObj[2]; int rc; int ii; assert(sizeof(apObj)/sizeof(apObj[0])+1 == sizeof(aConf)/sizeof(aConf[0])); rc = SwprocRt(interp, objc - 1, &objv[1], aConf, apObj); if (rc == TCL_OK) { Tcl_Obj **apConf; int nConf; rc = Tcl_ListObjGetElements(interp, apObj[0], &nConf, &apConf); if (rc == TCL_OK) { SwprocConf *aScriptConf; Tcl_Obj **apVars; aScriptConf = (SwprocConf *)ckalloc( nConf * sizeof(Tcl_Obj*) + (nConf + 1) * sizeof(SwprocConf) ); apVars = (Tcl_Obj **)&aScriptConf[nConf + 1]; for (ii = 0; ii < nConf && rc == TCL_OK; ii++) { SwprocConf *pConf = &aScriptConf[ii]; Tcl_Obj **apParams; int nP; rc = Tcl_ListObjGetElements(interp, apConf[ii], &nP, &apParams); if (rc == TCL_OK) { switch (nP) { case 3: pConf->eType = SWPROC_SWITCH; pConf->zSwitch=Tcl_GetString(apParams[0]); pConf->zDefault=Tcl_GetString(apParams[1]); pConf->zTrue = Tcl_GetString(apParams[2]); break; case 2: pConf->eType = SWPROC_OPT; pConf->zSwitch=Tcl_GetString(apParams[0]); pConf->zDefault=Tcl_GetString(apParams[1]); break; case 1: pConf->eType = SWPROC_ARG; pConf->zSwitch=Tcl_GetString(apParams[0]); break; default: rc = TCL_ERROR; break; } } } aScriptConf[nConf].eType = SWPROC_END; if (rc == TCL_OK) { Tcl_Obj **apArgs; int nArgs; rc = Tcl_ListObjGetElements(interp, apObj[1], &nArgs, &apArgs); if (rc == TCL_OK) { rc = SwprocRt(interp, nArgs, apArgs, aScriptConf, apVars); if (rc == TCL_OK) { for (ii = 0; ii < nConf; ii++) { const char *zVar = aScriptConf[ii].zSwitch; const char *zVal = Tcl_GetString(apVars[ii]); Tcl_SetVar(interp, zVar, zVal, 0); Tcl_DecrRefCount(apVars[ii]); } } } } ckfree((char *)aScriptConf); } for (ii = 0; ii < sizeof(apObj)/sizeof(apObj[0]); ii++) { assert(apObj[ii]); Tcl_DecrRefCount(apObj[ii]); } } return rc; } /* *--------------------------------------------------------------------------- * * SwprocInit -- * * Add the swproc command to the specified interpreter: * * swproc NAME ARGS BODY * * [swproc] is very similar to the proc command, except any procedure * arguments with default values must be specified with switches * instead of on the command line. For example, the following are * equivalent: * * proc abc {a {b hello} {c goodbye}} {...} * abc one two * * swproc swabc {a {b hello} {c goodbye}} {...} * swabc one -b two * * This means, in the above example, that it is possible to call * [swabc] and supply a value for parameter "c" but not "b". This is * not possible with commands created by regular Tcl [proc]. * * Commands created with [swproc] may also accept switches that do not * take arguments. These should be specified as a list of three * elements. The first is the name of the switch (and variable). The * second is the default value of the variable (if the switch is not * present), and the third is the value if the switch is present. For * example, the following two blocks are equivalent: * * proc abc {a} {...} * abc b * abc c * * swproc abc {{a b c}} {...} * abc * abc -a * * * Results: * None. * * Side effects: * None. * *--------------------------------------------------------------------------- */ int SwprocInit(interp) Tcl_Interp *interp; { Tcl_CreateObjCommand(interp, "::tkhtml::swproc_rt", swproc_rtCmd, 0, 0); Tcl_Eval(interp, "proc swproc {procname arguments script} {\n" " uplevel [subst {\n" " proc $procname {args} {\n" " ::tkhtml::swproc_rt [list $arguments] \\$args\n" " $script\n" " }\n" " }]\n" "}\n" ); return TCL_OK; } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������tkHTML-4ee7aaa953d6cb59/src/swproc.h����������������������������������������������������������������0000644�0000000�0000000�00000000671�11512242631�0016376�0����������������������������������������������������������������������������������������������������ustar�00nobody��������������������������nobody����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������� #ifndef __SWPROC_H__ #define __SWPROC_H__ #define SWPROC_END 0 #define SWPROC_ARG 1 #define SWPROC_OPT 2 #define SWPROC_SWITCH 3 struct SwprocConf { int eType; const char *zSwitch; const char *zDefault; const char *zTrue; }; typedef struct SwprocConf SwprocConf; int SwprocRt(Tcl_Interp *, int, Tcl_Obj *CONST[], SwprocConf *, Tcl_Obj **); void SwprocCleanup(Tcl_Obj **, int); int SwprocInit(Tcl_Interp *); #endif �����������������������������������������������������������������������tkHTML-4ee7aaa953d6cb59/src/tkhtml.tcl��������������������������������������������������������������0000644�0000000�0000000�00000012757�11512242631�0016727�0����������������������������������������������������������������������������������������������������ustar�00nobody��������������������������nobody�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������# # tkhtml.tcl -- # # This file contains: # # - The default bindings for the Html widget, and # - Some Tcl functions used by the stylesheet html.css. # # ------------------------------------------------------------------------ # # Copyright (c) 2005 Eolas Technologies Inc. # All rights reserved. # # This Open Source project was made possible through the financial support # of Eolas Technologies Inc. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are met: # # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # * Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # * Neither the name of the <ORGANIZATION> nor the names of its # contributors may be used to endorse or promote products derived from # this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. # switch -- $::tcl_platform(platform) { windows { bind Html <MouseWheel> { %W yview scroll [expr %D/-30] units } } macintosh { bind Html <MouseWheel> { %W yview scroll [expr %D*-4] units } } default { # Assume X windows by default. bind Html <ButtonPress-4> { %W yview scroll -4 units } bind Html <ButtonPress-5> { %W yview scroll 4 units } } } # Some Tcl procs used by html.css # namespace eval tkhtml { # This is called for <input type=text> tags that have a size # attribute. The size attribute in this case is supposed to be # the width in characters. proc inputsize_to_css {} { upvar N node set size [$node attr size] catch { if {$size < 0} {error "Bad value for size attribute"} } # Figure out if we are talking characters or pixels: switch -- [string tolower [$node attr -default text type]] { text { incr size [expr {int(($size/10)+1)}] set units ex } password { incr size [expr {int(($size/10)+1)}] set units ex } file { incr size 10 set units ex } default { set units px } } return "${size}${units}" } proc if_disabled {if else} { upvar N node set disabled [$node attr -default 0 disabled] if {$disabled} {return $if} return $else } # The following two procs are used to determine the width and height of # <textarea> markups. Technically speaking, the "cols" and "rows" # attributes are compulsory for <textarea> elements. proc textarea_width {} { upvar N node set cols [$node attr -default "" cols] if {[regexp {[[:digit:]]+}] $cols} { return "${cols}ex" } return $cols } proc textarea_height {} { upvar N node set rows [$node attr -default "" rows] if {[regexp {[[:digit:]]+} $rows]} { return "[expr ${rows} * 1.2]em" } return $rows } proc size_to_fontsize {} { upvar N node set size [$node attr size] if {![regexp {([+-]?)([0123456789]+)} $size dummy sign quantity]} { error "not an integer" } if {$sign eq ""} { switch -- $quantity { 1 {return xx-small} 2 {return small} 3 {return medium} 4 {return large} 5 {return x-large} 6 {return xx-large} default { error "out of range: $size" } } } if {$sign eq "-"} { if {$quantity eq "1"} {return smaller} return "[expr 100 * pow(0.85, $quantity)]%" } if {$sign eq "+"} { if {$quantity eq "1"} {return larger} return "[expr 100 * pow(1.176, $quantity)]%" } error "logic error" } proc vscrollbar {base node} { set sb [scrollbar ${base}.vsb_[string map {: _} $node]] $sb configure -borderwidth 1 -highlightthickness 0 -command "$node yview" return $sb } proc hscrollbar {base node} { set sb [scrollbar ${base}.hsb_[string map {: _} $node] -orient horiz] $sb configure -borderwidth 1 -highlightthickness 0 -command "$node xview" return $sb } proc ol_liststyletype {} { switch -exact -- [uplevel {$N attr type}] { i {return lower-roman} I {return upper-roman} a {return lower-alpha} A {return upper-alpha} 1 {return decimal} } error "Unrecognized type attribute on OL element" } } �����������������tkHTML-4ee7aaa953d6cb59/src/tokenlist.txt�����������������������������������������������������������0000644�0000000�0000000�00000024170�11512242631�0017465�0����������������������������������������������������������������������������������������������������ustar�00nobody��������������������������nobody�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������# # $Revision: 1.45 $ # # tokenlist.tcl -- # # This file contains raw data used to build a database of tag # information used by tkhtml at runtime. Most of the information in # this file comes from the SGML specification of the various versions # of the HTML language. Also, some html tags require a special C # structure to be allocated for some specific use. This file identifies # these tags. # # In an HTML document, some elements have implicit close tags (some # also have optional open tags, but this is handled entirely in # htmltree.c). To build the correct document tree from an HTML file # tkhtml needs to know about this. So this file contains enough # information to allow implicit close tags to be determined. # # The rules for implicit closes in HTML are summarised in the # following table: # # Tag | Allowed content # ------------------------------- # <p> | %inline only. # <colgroup> | <col> only. # <dd> | %flow # <dt> | %inline only. # <li> | %flow # <option> | #PCDATA only. # <td> | %flow # <tfoot> | <tr> only. # <th> | %flow # <thead> | <tr> only # <tr> | <TH> or <TD> only. # #---------------------------------------------------------------------------- # Copyright (c) 2005 Eolas Technologies Inc. # All rights reserved. # # This Open Source project was made possible through the financial support # of Eolas Technologies Inc. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are met: # # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # * Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # * Neither the name of the <ORGANIZATION> nor the names of its # contributors may be used to endorse or promote products derived from # this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. # ########################################################################### proc TAG {args} { lappend ::tagscript [concat _TAG $args] } # # File Format: # # This file is sourced by a Tcl interpreter. The global 'TAG' # command is used to add a new tag to the internal database. The # Tcl script outputs C-code which is used to build a runtime # version of the same database. # # TAG tag-name # ?-content (content function)? # ?-flow (inline|block)? # # ?-head? # ?-body? # ?-frameset? # # ?-pcdata? # TAG a -flow inline -content HtmlAnchorContent # TAG abbr # TAG acronym TAG address TAG applet -flow inline TAG area -content HtmlEmptyContent TAG base -content HtmlEmptyContent TAG basefont TAG b -flow inline # TAG bdo TAG big -flow inline TAG blockquote -flow block TAG body TAG br -content HtmlEmptyContent -flow inline TAG button TAG caption TAG center -flow block TAG cite -flow inline TAG code -flow inline # TAG col # TAG colgroup -content HtmlColgroupContent TAG dd -content HtmlLiContent # TAG del TAG dfn -flow inline TAG dir -flow block -content HtmlUlContent TAG div -flow block TAG dl -flow block -content HtmlDlContent TAG dt -content HtmlLiContent TAG em -flow inline TAG fieldset -flow inline TAG font -flow inline TAG form -flow block -content HtmlFormContent TAG frame -content HtmlEmptyContent TAG frameset TAG h1 -flow block TAG h2 -flow block TAG h3 -flow block TAG h4 -flow block TAG h5 -flow block TAG h6 -flow block TAG head -content HtmlHeadContent TAG hr -content HtmlEmptyContent -flow block TAG html TAG i -flow inline TAG iframe ;# -content HtmlEmptyContent TAG img -content HtmlEmptyContent -flow inline TAG input -content HtmlEmptyContent -flow inline TAG isindex -flow block -content HtmlEmptyContent TAG kbd -flow inline TAG label -flow inline TAG legend -flow inline TAG li -content HtmlLiContent TAG link -content HtmlEmptyContent TAG map -flow inline TAG menu -flow block -content HtmlUlContent TAG meta -content HtmlEmptyContent TAG noframes TAG noscript TAG object TAG ol -flow block -content HtmlUlContent # TAG optgroup TAG option -content HtmlPcdataContent -flow inline TAG p -flow block -content HtmlInlineContent TAG param -content HtmlEmptyContent TAG pre -flow block # TAG q TAG s -flow inline TAG samp -flow inline TAG script -content HtmlEmptyContent -flow inline TAG select -flow inline TAG small -flow inline TAG span -flow inline TAG strike -flow inline TAG strong -flow inline TAG style -content HtmlEmptyContent TAG sub -flow inline TAG sup -flow inline # Note: In "quirks mode", according to both Opera and Gecko, you can nest a # <table> tag inside of a <p>. The results pages from google look a bit # better if this is the case too. For now though, operate in strict mode only. # # TODO: Check the IE behaviour. TAG table -flow block -content HtmlTableContent # TAG table -content HtmlTableContent TAG tbody TAG td -content HtmlTableCellContent TAG textarea -flow inline -pcdata TAG tfoot TAG th -content HtmlTableCellContent TAG thead TAG title TAG tr -content HtmlTableRowContent TAG tt -flow inline TAG u -flow inline TAG ul -flow block -content HtmlUlContent TAG var -flow inline # The tags listed above are the complete set of HTML 4.01 tags. Some # are commented out because we don't support them in any way. # # Tkhtml also supports the tags below. They are no longer inluded # in the standard as of HTML 4.01. Supporting these tags is a low # priority. # TAG comment TAG embed -content HtmlEmptyContent TAG listing TAG marquee TAG nextid -content HtmlEmptyContent TAG nobr -flow inline TAG noembed TAG plaintext -content HtmlInlineContent TAG wbr -content HtmlEmptyContent -flow inline TAG xmp TAG bgsound -content HtmlEmptyContent ########################################################################### # Below this line is the engine for processing the database declared # above. We produce a header file (htmltokens.h) and an implementation # file (htmltokens.c). # #------------------------------------------------------------------------- # shift -- # # shift LISTVAR # # This is a helper proc for [_TAG]. The argument is the name of a # list variable in the callers context. This proc returns and removes # the first element of that list. i.e: # # $ set abc {a b c} # {a b c} # $ shift abc # a # $ set abc # {b c} # proc shift {list} { upvar $list l set ret [lindex $l 0] set l [lrange $l 1 end] return $ret } set ::nextfreeconst 0 proc _TAG {args} { set tag [lindex $args 0] # Parse the arguments. Default values are all zero. set flow 0 set pcdata 0 set empty 0 set xClose 0 while {[llength $args]} { switch -exact -- [shift args] { -flow { set flow HTMLTAG_[string toupper [shift args]] } -content { set xClose [shift args] } -pcdata { set pcdata 1 } } } # Insert the two constants for the tag into the header file. set header_format {#define % -20s %s} set opensym "Html_[string toupper $tag]" puts $::h_file [format $header_format $opensym $::nextfreeconst] incr ::nextfreeconst # set closesym "Html_End[string toupper $tag]" # puts $::h_file [format $header_format $closesym $::nextfreeconst] # incr ::nextfreeconst # Insert the HtmlTokenMap record into the constant array. set fmt { {% -15s % -18s %s %s %s},} set flags 0 if {$flow!=0} { set flags $flow } if {$xClose == "HtmlEmptyContent"} { append flags |HTMLTAG_EMPTY set xClose 0 } if {$pcdata} { append flags |HTMLTAG_PCDATA } puts $::c_file [format $fmt "\"$tag\"," $opensym, $flags, $xClose, 0] # set flags HTMLTAG_END # if {$flow!=0} { append flags |$flow } # puts $::c_file [format $fmt "\"/$tag\"," $closesym, $flags, 0, 0] } # Open the files htmltokens.c and htmltokens.h for writing. Write a # warning to the top of each that they are generated files. # set c_file [open htmltokens.c w] set h_file [open htmltokens.h w] set warning { /* * DO NOT EDIT! * * The code in this file was automatically generated. See the files * src/tokenlist.txt and tools/maketokens.tcl from the tkhtml source * distribution. */ } puts $c_file $warning puts $h_file $warning puts -nonewline $h_file { #define Html_Text 1 #define Html_Space 2 #define Html_Unknown 3 #define Html_Block 4 #define HtmlIsMarkup(X) ((X)->base.type>Html_Block) } set ::nextfreeconst 5 # puts $c_file {#include "html.h"} puts $c_file "HtmlTokenMap HtmlMarkupMap\[] = {" # Evaluate the calls to TAG from the database specified above. foreach l $::tagscript {eval $l} set c $::nextfreeconst puts $h_file "#define Html_TypeCount $c" puts $h_file "#define HTML_MARKUP_HASH_SIZE [expr $c+11]" puts $h_file "#define HTML_MARKUP_COUNT [expr $c-5]" puts $c_file "};" # Close the two generated files. close $c_file close $h_file ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������tkHTML-4ee7aaa953d6cb59/tclconfig�������������������������������������������������������������������0000755�0000000�0000000�00000000000�11512242631�0016006�5����������������������������������������������������������������������������������������������������ustar�00nobody��������������������������nobody�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������tkHTML-4ee7aaa953d6cb59/tclconfig/ChangeLog���������������������������������������������������������0000644�0000000�0000000�00000053171�11512242631�0017646�0����������������������������������������������������������������������������������������������������ustar�00nobody��������������������������nobody�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������2006-01-25 Jeff Hobbs <jeffh@ActiveState.com> *** Bump to TEA version 3.5 *** * tcl.m4: keep LD_SEARCH_FLAGS and CC_SEARCH_FLAGS synchronous with core tcl.m4 meaning. 2006-01-24 Daniel Steffen <das@users.sourceforge.net> * tcl.m4 (Darwin): use makefile variable LDFLAGS_DEFAULT instead of LDFLAGS in SHLIB_LD, to ensure linker flags in sampleextension Makefile are picked up. [Bug 1403343] 2006-01-23 Jeff Hobbs <jeffh@ActiveState.com> * tcl.m4: add C:/Tcl/lib and C:/Progra~1/Tcl/lib dirs to check for *Config.sh on Windows. [Bug 1407544] 2006-01-23 Daniel Steffen <das@users.sourceforge.net> * tcl.m4 (Darwin): for Tk extensions, remove -arch ppc64 from CFLAGS like in the Tk configure, as neither TkAqua nor TkX11 can be built for 64bit at present (no 64bit GUI libraries). 2006-01-22 Jeff Hobbs <jeffh@ActiveState.com> * tcl.m4: restore system=windows on Windows. Remove error if 'ar' isn't found (it may not be on Windows). Do not add -lxnet or define _XOPEN_SOURCE on HP-UX by default. Ensure the C|LDFLAGS_DEFAULT gets the fully sub'd value at configure time. 2006-01-10 Daniel Steffen <das@users.sourceforge.net> * tcl.m4: add caching, use AC_CACHE_CHECK instead of AC_CACHE_VAL where possible, consistent message quoting, sync relevant tcl/unix/tcl.m4 HEAD changes and gratuitous formatting differences (notably sunc removal of support for for ancient BSD's, IRIX 4, RISCos and Ultrix by kennykb), Darwin improvements to TEA_LOAD_*CONFIG to make linking work against Tcl/Tk frameworks installed in arbitrary location, change TEA_PROG_* search order (look in *_BIN_DIR parents before *_PREFIX). 2006-01-05 Jeff Hobbs <jeffh@ActiveState.com> * tcl.m4: add dkf's system config refactor 2006-01-04 Jeff Hobbs <jeffh@ActiveState.com> * tcl.m4: remove extraneous ' that causes bash 3.1 to choke 2005-12-19 Joe English <jenglish@users.sourceforge.net> * tcl.m4 (TEA_PATH_TCLCONFIG &c): Look for tclConfig.sh &c in ${libdir}, where they are installed by default [Patch #1377407]. 2005-12-05 Don Porter <dgp@users.sf.net> * tcl.m4 (TEA_PUBLIC_*_HEADERS): Better support for finding header files for uninstalled Tcl and Tk. 2005-12-02 Jeff Hobbs <jeffh@ActiveState.com> * tcl.m4: correctly bump TEA_VERSION var to 3.4 2005-12-01 Daniel Steffen <das@users.sourceforge.net> * unix/tcl.m4 (Darwin): fixed error when MACOSX_DEPLOYMENT_TARGET unset 2005-11-29 Jeff Hobbs <jeffh@ActiveState.com> * tcl.m4: *** Bump to TEA version 3.4 *** Add Windows x64 build support. Remove TEA_PATH_NOSPACE and handle the problem with ""s where necessary - the macro relied on TCLSH_PROG which didn't work for cross-compiles. 2005-11-27 Daniel Steffen <das@users.sourceforge.net> * tcl.m4 (Darwin): add 64bit support, add CFLAGS to SHLIB_LD to support passing -isysroot in env(CFLAGS) to configure (flag can't be present twice, so can't be in both CFLAGS and LDFLAGS during configure), don't use -prebind when deploying on 10.4. (TEA_ENABLE_LANGINFO, TEA_TIME_HANDLER): add/fix caching. 2005-10-30 Daniel Steffen <das@users.sourceforge.net> * tcl.m4: fixed two tests for TEA_WINDOWINGSYSTEM = "aqua" that should have been for `uname -s` = "Darwin" instead; added some missing quoting. (TEA_PROG_TCLSH, TEA_PROG_WISH): fix incorrect assumption that install location of tclConfig.sh/tkConfig.sh allows to determine the tclsh/wish install dir via ../bin. Indeed tcl/tk can be configured with arbitrary --libdir and --bindir (independent of prefix) and such a configuration is in fact standard with Darwin framework builds. At least now also check ${TCL_PREFIX}/bin resp. ${TK_PREFIX}/bin for presence of tclsh resp. wish (if tcl/tk have been configured with arbitrary --bindir, this will still not find them, for a general solution *Config.sh would need to contain the values of bindir/libdir/includedir passed to configure). 2005-10-07 Jeff Hobbs <jeffh@ActiveState.com> * tcl.m4: Fix Solaris 5.10 check and Solaris AMD64 64-bit builds. 2005-10-04 Jeff Hobbs <jeffh@ActiveState.com> * tcl.m4 (TEA_PRIVATE_TCL_HEADERS): add / to finish sed macro (TEA_ENABLE_THREADS): don't check for pthread_attr_setstacksize func 2005-09-13 Jeff Hobbs <jeffh@ActiveState.com> * tcl.m4: *** Update to TEA version 3.3 *** define TEA_WINDOWINGSYSTEM in TEA_LOAD_TKCONFIG. Make --enable-threads the default (users can --disable-threads). Improve AIX ${CC}_r fix to better check existing ${CC} value. Do the appropriate evals to not require the *TOP_DIR_NATIVE vars be set for extensions that use private headers. Make aqua check for Xlib compat headers the same as win32. 2005-07-26 Mo DeJong <mdejong@users.sourceforge.net> * tcl.m4 (TEA_PROG_TCLSH, TEA_BUILD_TCLSH, TEA_PROG_WISH, TEA_BUILD_WISH): Remove TEA_BUILD_TCLSH and TEA_BUILD_WISH because of complaints that it broke the build when only an installed version of Tcl was available at extension build time. The TEA_PROG_TCLSH and TEA_PROG_WISH macros will no longer search the path at all. The build tclsh or installed tclsh shell will now be found by TEA_PROG_TCLSH. 2005-07-24 Mo DeJong <mdejong@users.sourceforge.net> * tcl.m4 (TEA_PROG_TCLSH, TEA_BUILD_TCLSH, TEA_PROG_WISH, TEA_BUILD_WISH): Split confused search for tclsh on PATH and build and install locations into two macros. TEA_PROG_TCLSH and TEA_PROG_WISH search the system PATH for an installed tclsh or wish. The TEA_BUILD_TCLSH and TEA_BUILD_WISH macros determine the name of tclsh or wish in the Tcl or Tk build directory even if tclsh or wish has not yet been built. [Tcl bug 1160114] [Tcl patch 1244153] 2005-06-23 Daniel Steffen <das@users.sourceforge.net> * tcl.m4 (TEA_PRIVATE_TK_HEADERS): add ${TK_SRC_DIR}/macosx to TK_INCLUDES when building against TkAqua. * tcl.m4 (TEA_PATH_X): fixed missing comma in AC_DEFINE * tcl.m4: changes to better support framework builds of Tcl and Tk out of the box: search framework install locations for *Config.sh, and if in presence of a framework build, use the framework's Headers and PrivateHeaders directories for public and private includes. [FR 947735] 2005-06-18 Daniel Steffen <das@users.sourceforge.net> * tcl.m4 (Darwin): add -headerpad_max_install_names to LDFLAGS to ensure we can always relocate binaries with install_name_tool. 2005-06-04 Daniel Steffen <das@users.sourceforge.net> * tcl.m4 (TEA_PATH_X): for TEA_WINDOWINGSYSTEM == aqua, check if xlib compat headers are available in tkheaders location, otherwise add xlib sourcedir to TK_XINCLUDES. 2005-04-25 Daniel Steffen <das@users.sourceforge.net> * tcl.m4: added AC_DEFINE* descriptions (from core tcl.m4) to allow use with autoheader. (Darwin): added configure checks for recently added linker flags -single_module and -search_paths_first to allow building with older tools (and on Mac OS X 10.1), use -single_module in SHLIB_LD. (TEA_MISSING_POSIX_HEADERS): added caching of dirent.h check. (TEA_BUGGY_STRTOD): added caching (sync with core tcl.m4). 2005-03-24 Jeff Hobbs <jeffh@ActiveState.com> * tcl.m4 (TEA_TCL_64BIT_FLAGS): use Tcl header defaults for wide int type only on Windows when __int64 is detected as valid. 2005-03-24 Don Porter <dgp@users.sf.net> * README.txt: Update reference to "SC_* macros" to "TEA_* macros". * tcl.m4: Incorporated recent improvements in SC_PATH_TCLCONFIG and SC_PATH_TKCONFIG into TEA_PATH_TCLCONFIG and TEA_PATH_TKCONFIG. Corrected search path in TEA_PATH_CONFIG and added AC_SUBST($1_BIN_DIR) to TEA_LOAD_CONFIG so that packages that load the configuration of another package can know where they loaded it from. 2005-03-18 Jeff Hobbs <jeffh@ActiveState.com> * tcl.m4 (TEA_CONFIG_CFLAGS): correct 2005-03-17 change to have variant LD_SEARCH_FLAGS for gcc and cc builds. * tcl.m4 (TEA_PROG_TCLSH, TEA_PROG_WISH): correct x-compile check. 2005-03-17 Jeff Hobbs <jeffh@ActiveState.com> * tcl.m4: Correct gcc build and HP-UX-11. 2005-02-08 Jeff Hobbs <jeffh@ActiveState.com> * tcl.m4 (TEA_ADD_LIBS): don't touch lib args starting with -. (TEA_CONFIG_CFLAGS): only define _DLL for CE in shared build. (TEA_MAKE_LIB): set RANLIB* to : on Windows (it's not needed). 2005-02-01 Jeff Hobbs <jeffh@ActiveState.com> * tcl.m4: redo of 2005-01-27 changes to correctly handle paths with spaces. Win/CE and Win/64 builds now require a prebuilt tclsh to handle conversion to short pathnames. This is done in the new TEA_PATH_NOSPACE macro. For Win/CE|64, make CC just the compiler and move the necessary includes to CFLAGS. (TEA_CONFIG_CFLAGS): Add Solaris 64-bit gcc build support. (TEA_PROG_TCLSH, TEA_PROG_WISH): Allow TCLSH_PROG and WISH_PROG to be set in the env and prevent resetting. (TEA_ADD_LIBS): On Windows using GCC (mingw), convert foo.lib args to -lfoo, for use with mingw. *** POTENTIAL INCOMPATABILITY *** (TEA_CONFIG_CFLAGS): Fix AIX gcc builds to work out-of-box. Bumped TEA to 3.2. 2005-01-27 Jeff Hobbs <jeffh@ActiveState.com> * tcl.m4: remove cygpath calls to support msys. Update base CE build assumption to "420,ARMV4,ARM,Pocket PC 2003". Make STLIB_LD use $LINKBIN -lib. 2005-01-25 Daniel Steffen <das@users.sourceforge.net> * tcl.m4 (Darwin): fixed bug with static build linking to dynamic library in /usr/lib etc instead of linking to static library earlier in search path. [Tcl Bug 956908] Removed obsolete references to Rhapsody. 2004-12-29 Jeff Hobbs <jeffh@ActiveState.com> * tcl.m4: Updates for VC7 compatibility, fixing CFLAGS and LDFLAGS options, using better default -O levels. [Bug 1092952, 1091967] 2004-12-29 Joe English <jenglish@users.sourceforge.net> * tcl.m4: Do not use ${DBGX} suffix when building shared libraries [patch #1081595, TIP #34] 2004-09-07 Jeff Hobbs <jeffh@ActiveState.com> * tcl.m4 (TEA_CONFIG_CFLAGS): support eVC4 Win/CE builds 2004-08-10 Jeff Hobbs <jeffh@ActiveState.com> * tcl.m4 (TEA_INIT, TEA_PREFIX): update handling of exec_prefix to work around subdir configures since autoconf only propagates the prefix (not exec_prefix). 2004-07-23 Daniel Steffen <das@users.sourceforge.net> * tcl.m4 (TEA_CONFIG_CFLAGS): Darwin section: brought inline with Tcl 8.5 HEAD config, removed core specific & obsolete settings. 2004-07-22 Jeff Hobbs <jeffh@ActiveState.com> * tcl.m4 (TEA_PATH_X): check in TK_DEFS for MAC_OSX_TK to see if we are compiling on Aqua. Add TEA_WINDOWINGSYSTEM var that reflects 'tk windowingsystem' value. 2004-07-16 Jeff Hobbs <jeffh@ActiveState.com> * tcl.m4 (TEA_ENABLE_THREADS): force a threaded build when building against a threaded core. (CFLAGS_WARNING): Remove -Wconversion for gcc builds (TEA_CONFIG_CFLAGS): Reorder configure.in for better 64-bit build configuration, replacing EXTRA_CFLAGS with CFLAGS. [Bug #874058] Update to latest Tcl 8.5 head config settings. Call this TEA version 3.1. 2004-04-29 Jeff Hobbs <jeffh@ActiveState.com> * tcl.m4 (TEA_TCL_64BIT_FLAGS): replace AC_TRY_RUN test with AC_TRY_COMPILE for the long vs. long long check. (kenny) 2004-04-26 Jeff Hobbs <jeffh@ActiveState.com> * tcl.m4 (TEA_TCL_64BIT_FLAGS): update against core tcl.m4 to define TCL_WIDE_INT_IS_LONG if 'using long'. 2004-03-19 Jeff Hobbs <jeffh@ActiveState.com> * tcl.m4: correct Windows builds getting LDFLAGS info in MAKE_LIB 2004-02-11 Jeff Hobbs <jeffh@ActiveState.com> * tcl.m4: correct TCL_INCLUDES for private headers on Windows - it doesn't need the eval. 2004-02-10 Jeff Hobbs <jeffh@ActiveState.com> * tcl.m4: don't require TK_INCLUDES and TCL_INCLUDES to have the DIR_NATIVE vars defined when using private headers on unix. Allow $... to TEA_ADD_SOURCES for constructs like TEA_ADD_SOURCES([\$(WIN_OBJECTS)]), that allow the developer to place more in the Makefile.in. tkUnixPort.h checks for HAVE_LIMITS_H, so do both HAVE and CHECK on limits.h 2003-12-10 Jeff Hobbs <jeffh@ActiveState.com> * Makefile.in: added TEA_ADD_LIBS, TEA_ADD_INCLUDES and * configure: TEA_ADD_CFLAGS to configurable parameters with * configure.in: PKG_* equivs in the Makefile. This allows the * tclconfig/tcl.m4: user to worry less about actual magic VAR names. Corrected Makefile.in to note that TEA_ADD_TCL_SOURCES requires exact file names. 2003-12-09 Jeff Hobbs <jeffh@ActiveState.com> * tcl.m4: updated OpenBSD support based on [Patch #775246] (cassoff) 2003-12-05 Jeff Hobbs <jeffh@ActiveState.com> * configure: * configure.in: * Makefile.in (VPATH): readd $(srcdir) to front of VPATH as the first part of VPATH can get chopped off. Change .c.$(OBJEXT) rule to .c.@OBJEXT@ to support more makes. * tclconfig/tcl.m4: add TEA_ADD_STUB_SOURCES to support libstub generation and TEA_ADD_TCL_SOURCES to replace RUNTIME_SOURCES as the way the user specifies library files. 2003-12-03 Jeff Hobbs <jeffh@ActiveState.com> * configure: Update of TEA spec to (hopefully) simplify * configure.in: some aspects of TEA by making use of more * Makefile.in: AC 2.5x features. Use PACKAGE_NAME (instead * generic/tclsample.c: of PACKAGE) and PACKAGE_VERSION (instead of * tclconfig/tcl.m4: VERSION) arguments to AC_INIT as the TEA package name and version. Provide a version argument to TEA_INIT - starting with 3.0. Drop all use of interior shell substs that older makefiles didn't like. Use PKG_* naming convention instead. Move specification of source files and public headers into configure.in with TEA_ADD_SOURCES and TEA_ADD_HEADERS. These will be munged during ./configure into the right obj file names (no $(SOURCES:.c=.obj) needed). There is almost nothing that should be touched in Makefile.in now for the developer. May want to add a TEA_ADD_TCL_SOURCES for the RUNTIME_SOURCES that remains. Use SHLID_LD_FLAGS (instead of SHLID_LDFLAGS) as Tcl does. Only specify the user requested LDFLAGS/CFLAGS in the Makefile, don't mention the _OPTIMIZE/_DEBUG variants. 2003-10-15 Jeff Hobbs <jeffh@ActiveState.com> * tcl.m4: create a TEA_SETUP_COMPILER_CC the precedes the TEA_SETUP_COMPILER macro. They are split so the check for CC occurs before any use of CC. Also add AC_PROG_CPP to the compiler checks. 2003-10-06 Jeff Hobbs <jeffh@ActiveState.com> * tcl.m4: Updated for autoconf 2.5x prereq. Where TCL_WIDE_INT_TYPE would be __int64, defer to the code checks in tcl.h, which also handles TCL_LL_MODIFIER* properly. 2003-04-22 Jeff Hobbs <jeffh@ActiveState.com> * tcl.m4: correct default setting of ARCH for WinCE builds. Correct \ escaping for CE sed macros. 2003-04-10 Jeff Hobbs <jeffh@ActiveState.com> * tcl.m4: replace $(syscal) construct with older `syscall` for systems where sh != bash. 2003-04-09 Jeff Hobbs <jeffh@ActiveState.com> * tcl.m4 (TEA_WITH_CELIB): add --enable-wince and --with-celib options for Windows/CE compilation support. Requires the Microsoft eMbedded SDK and Keuchel's celib emulation layer. 2003-02-18 Jeff Hobbs <jeffh@ActiveState.com> * tcl.m4 (TEA_ENABLE_THREADS): Make sure -lpthread gets passed on the link line when checking for the pthread_attr_setstacksize symbol. (dejong) * tcl.m4 (TEA_SETUP_COMPILER): added default calls to TEA_TCL_EARLY_FLAGS, TEA_TCL_64BIT_FLAGS, TEA_MISSING_POSIX_HEADERS and TEA_BUGGY_STRTOD. 2003-02-14 Jeff Hobbs <jeffh@ActiveState.com> * tcl.m4: correct HP-UX ia64 --enable-64bit build flags 2003-01-29 Jeff Hobbs <jeffh@ActiveState.com> * tcl.m4: check $prefix/lib as well as $exec_prefix/lib when looking for tcl|tkConfig.sh, as this check is done before we would set exec_prefix when the user does not define it. 2003-01-21 Mo DeJong <mdejong@users.sourceforge.net> * tcl.m4 (TEA_CONFIG_CFLAGS): Fix build support for mingw, the previous implementation would use VC++ when compiling with mingw gcc. Don't pass -fPIC since gcc always compiles pic code under win32. Change some hard coded cases of gcc to ${CC}. 2002-10-15 Jeff Hobbs <jeffh@ActiveState.com> * tcl.m4: move the CFLAGS definition from TEA_ENABLE_SHARED to TEA_MAKE_LIB because setting too early confuses other AC_* macros. Correct the HP-11 SHLIB_LD_LIBS setting. * tcl.m4: add the CFLAGS definition into TEA_ENABLE_SHARED and make it pick up the env CFLAGS at configure time. 2002-10-09 Jeff Hobbs <jeffh@ActiveState.com> * tcl.m4: add --enable-symbols=mem option to enable TCL_MEM_DEBUG. Improved AIX 64-bit build support, allow it on AIX-4 as well. Enable 64-bit HP-11 compilation with gcc. Enable 64-bit IRIX64-6 cc build support. Correct FreeBSD thread library linkage. Add OSF1 static build support. Improve SunOS-5 shared build SHLIB_LD macro. 2002-07-20 Zoran Vasiljevic <zoran@archiware.com> * tcl.m4: Added MINGW32 to list of systems checked for Windows build. Also, fixes some indentation issues with "--with-XXX" options. 2002-04-23 Jeff Hobbs <jeffh@ActiveState.com> * tcl.m4 (TEA_ENABLE_THREADS): added USE_THREAD_ALLOC define to use new threaded allocatory by default on Unix for Tcl 8.4. (TEA_CONFIG_CFLAGS): corrected LD_SEARCH_FLAGS for FreeBSD-3+. 2002-04-22 Jeff Hobbs <jeffh@ActiveState.com> * tcl.m4 (TEA_SETUP_COMPILER): removed call to AC_CYGWIN so that we can use autoconf 2.5x as well as 2.13. This prevents us from being able to warn against the use of cygwin gcc at configure time, but allows autoconf 2.5x, which is what is shipped with most newer systems. 2002-04-11 Jeff Hobbs <jeffh@ActiveState.com> * tcl.m4: Enabled COFF as well as CV style debug info with --enable-symbols to allow Dr. Watson users to see function info. More info on debugging levels can be obtained at: http://msdn.microsoft.com/library/en-us/dnvc60/html/gendepdebug.asp 2002-04-03 Jeff Hobbs <jeffh@ActiveState.com> * tcl.m4: change all SC_* macros to TEA_*. The SC_ was for Scriptics, which is no more. TEA represents a better, independent prefix that won't need changing. Added preliminary mingw gcc support. [Patch #538772] Added TEA_PREFIX macro that handles defaulting the prefix and exec_prefix vars to those used by Tcl if none were specified. Added TEA_SETUP_COMPILER macro that encompasses the AC_PROG_CC check and several other basic AC_PROG checks needed for making executables. This greatly simplifies user's configure.in files. Collapsed AIX-5 defines into AIX-* with extra checks for doing the ELF stuff on AIX-5-ia64. Updated TEA_ENABLE_THREADS to take an optional arg to allow switching it on by default (for Thread) and add sanity checking to warn the user if configuring threads incompatibly. 2002-03-29 Jeff Hobbs <jeffh@ActiveState.com> * tcl.m4: made sure that SHLIB_LDFLAGS was set to LDFLAGS_DEFAULT. Removed --enable-64bit support for AIX-4 because it wasn't correct. Added -MT or -MD Windows linker switches to properly support symbols-enabled builds. 2002-03-28 Jeff Hobbs <jeffh@ActiveState.com> * tcl.m4: called AC_MSG_ERROR when SC_TEA_INIT wasn't called first instead of calling it as that inlines it each time in shell code. Changed Windows CFLAGS_OPTIMIZE to use -O2 instead of -Oti. Noted TCL_LIB_VERSIONS_OK=nodots for Windows builds. A few changes to support itcl (and perhaps others): Added support for making your own stub libraries to SC_MAKE_LIB. New SC_PATH_CONFIG and SC_LOAD_CONFIG that take a package name arg and find that ${pkg}Config.sh file. itk uses this for itcl. 2002-03-27 Jeff Hobbs <jeffh@ActiveState.com> * tcl.m4: made SC_LOAD_TKCONFIG recognize when working with a Tk build dir setup. Added EXTRA_CFLAGS and SHLIB_LD_LIBS substs to SC_CONFIG_CFLAGS. Added XLIBSW onto LIBS when it is defined. Remove TCL_LIBS from MAKE_LIB and correctly use SHLIB_LD_LIBS instead to not rely as much on tclConfig.sh cached info. Add TK_BIN_DIR to paths to find wish in SC_PROG_WISH. These move towards making TEA much more independent of *Config.sh. 2002-03-19 Jeff Hobbs <jeffh@ActiveState.com> * tcl.m4: corrected forgotten (UN)SHARED_LIB_SUFFIX and SHLIB_SUFFIX defines for Win. (SC_PATH_X): made this only do the check on unix platforms. 2002-03-12 Jeff Hobbs <jeffh@ActiveState.com> * README.txt: updated to reflect fewer files 2002-03-06 Jeff Hobbs <jeffh@ActiveState.com> * config.guess (removed): * config.sub (removed): removed unnecessary files * installFile.tcl (removed): * mkinstalldirs (removed): these aren't really necessary for making TEA work * tcl.m4 (SC_PUBLIC_TCL_HEADERS, SC_PUBLIC_TK_HEADERS): don't check /usr(/local)/include for includes on Windows when not using gcc 2002-03-05 Jeff Hobbs <jeffh@ActiveState.com> * tcl.m4: added warnings on Windows, removed RELPATH define and added TCL_LIBS to MAKE_LIB macro. This import represents 2.0.0, or a new start at attempting to make TEA much easier for C extension developers. **** moved from tclpro project to core tcl project, **** **** renamed to 'tclconfig' **** 2001-03-15 Karl Lehenbauer <karl@procplace.com> * installFile.tcl: Added updating of the modification time of the target file whether we overwrote it or decided that it hadn't changed. This was necessary for us to be able to determine whether or not a module install touched the file. 2001-03-08 Karl Lehenbauer <karl@procplace.com> * installFile.tcl: Added support for converting new-style (1.1+) Cygnus drive paths to Tcl-style. 2001-01-15 <brent.welch@interwoven.com> * tcl.m4: Added FreeBSD clause. 2001-01-03 <brent.welch@interwoven.com> * tcl.m4: Fixed typo in SC_LIB_SPEC where it is checking for exec-prefix. 2000-12-01 <brent.welch@interwoven.com> * tcl.m4: Concatenated most of the Ajuba acsite.m4 file so we don't need to modify the autoconf installation. * config.guess: * config.sub: * installFile.tcl: Added files from the itcl config subdirectory, which should go away. 2000-7-29 <welch@ajubasolutions.com> * Fixed the use of TCL_SRC_DIR and TK_SRC_DIR within TCL_PRIVATE_INCLUDES and TK_PRIVATE_INCLUDES to match their recent change from $(srcdir) to $(srcdir)/.. �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������tkHTML-4ee7aaa953d6cb59/tclconfig/README.txt��������������������������������������������������������0000644�0000000�0000000�00000001454�11512242631�0017567�0����������������������������������������������������������������������������������������������������ustar�00nobody��������������������������nobody�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������These files comprise the basic building blocks for a Tcl Extension Architecture (TEA) extension. For more information on TEA see: http://www.tcl.tk/doc/tea/ This package is part of the Tcl project at SourceForge, and latest sources should be available there: http://tcl.sourceforge.net/ This package is a freely available open source package. You can do virtually anything you like with it, such as modifying it, redistributing it, and selling it either in whole or in part. CONTENTS ======== The following is a short description of the files you will find in the sample extension. README.txt This file install-sh Program used for copying binaries and script files to their install locations. tcl.m4 Collection of Tcl autoconf macros. Included by a package's aclocal.m4 to define TEA_* macros. ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������tkHTML-4ee7aaa953d6cb59/tclconfig/install-sh��������������������������������������������������������0000755�0000000�0000000�00000004212�11512242631�0020070�0����������������������������������������������������������������������������������������������������ustar�00nobody��������������������������nobody�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#!/bin/sh # # install - install a program, script, or datafile # This comes from X11R5; it is not part of GNU. # # $XConsortium: install.sh,v 1.2 89/12/18 14:47:22 jim Exp $ # # This script is compatible with the BSD install script, but was written # from scratch. # # set DOITPROG to echo to test this script # Don't use :- since 4.3BSD and earlier shells don't like it. doit="${DOITPROG-}" # put in absolute paths if you don't have them in your path; or use env. vars. mvprog="${MVPROG-mv}" cpprog="${CPPROG-cp}" chmodprog="${CHMODPROG-chmod}" chownprog="${CHOWNPROG-chown}" chgrpprog="${CHGRPPROG-chgrp}" stripprog="${STRIPPROG-strip}" rmprog="${RMPROG-rm}" instcmd="$mvprog" chmodcmd="" chowncmd="" chgrpcmd="" stripcmd="" rmcmd="$rmprog -f" mvcmd="$mvprog" src="" dst="" while [ x"$1" != x ]; do case $1 in -c) instcmd="$cpprog" shift continue;; -m) chmodcmd="$chmodprog $2" shift shift continue;; -o) chowncmd="$chownprog $2" shift shift continue;; -g) chgrpcmd="$chgrpprog $2" shift shift continue;; -s) stripcmd="$stripprog" shift continue;; *) if [ x"$src" = x ] then src=$1 else dst=$1 fi shift continue;; esac done if [ x"$src" = x ] then echo "install: no input file specified" exit 1 fi if [ x"$dst" = x ] then echo "install: no destination specified" exit 1 fi # If destination is a directory, append the input filename; if your system # does not like double slashes in filenames, you may need to add some logic if [ -d $dst ] then dst="$dst"/`basename $src` fi # Make a temp file name in the proper directory. dstdir=`dirname $dst` dsttmp=$dstdir/#inst.$$# # Move or copy the file name to the temp name $doit $instcmd $src $dsttmp # and set any options; do chmod last to preserve setuid bits if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; fi if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; fi if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; fi if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; fi # Now rename the file to the real destination. $doit $rmcmd $dst $doit $mvcmd $dsttmp $dst exit 0 ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������tkHTML-4ee7aaa953d6cb59/tclconfig/tcl.m4������������������������������������������������������������0000644�0000000�0000000�00000361641�11512242631�0017124�0����������������������������������������������������������������������������������������������������ustar�00nobody��������������������������nobody�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������# tcl.m4 -- # # This file provides a set of autoconf macros to help TEA-enable # a Tcl extension. # # Copyright (c) 1999-2000 Ajuba Solutions. # Copyright (c) 2002-2005 ActiveState Corporation. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. # # RCS: @(#) $Id: tcl.m4,v 1.4 2006/03/07 10:35:58 danielk1977 Exp $ AC_PREREQ(2.50) dnl TEA extensions pass this us the version of TEA they think they dnl are compatible with (must be set in TEA_INIT below) dnl TEA_VERSION="3.5" # Possible values for key variables defined: # # TEA_WINDOWINGSYSTEM - win32 aqua x11 (mirrors 'tk windowingsystem') # TEA_PLATFORM - windows unix # #------------------------------------------------------------------------ # TEA_PATH_TCLCONFIG -- # # Locate the tclConfig.sh file and perform a sanity check on # the Tcl compile flags # # Arguments: # none # # Results: # # Adds the following arguments to configure: # --with-tcl=... # # Defines the following vars: # TCL_BIN_DIR Full path to the directory containing # the tclConfig.sh file #------------------------------------------------------------------------ AC_DEFUN(TEA_PATH_TCLCONFIG, [ dnl Make sure we are initialized AC_REQUIRE([TEA_INIT]) # # Ok, lets find the tcl configuration # First, look for one uninstalled. # the alternative search directory is invoked by --with-tcl # if test x"${no_tcl}" = x ; then # we reset no_tcl in case something fails here no_tcl=true AC_ARG_WITH(tcl, AC_HELP_STRING([--with-tcl], [directory containing tcl configuration (tclConfig.sh)]), with_tclconfig=${withval}) AC_MSG_CHECKING([for Tcl configuration]) AC_CACHE_VAL(ac_cv_c_tclconfig,[ # First check to see if --with-tcl was specified. if test x"${with_tclconfig}" != x ; then case ${with_tclconfig} in */tclConfig.sh ) if test -f ${with_tclconfig}; then AC_MSG_WARN([--with-tcl argument should refer to directory containing tclConfig.sh, not to tclConfig.sh itself]) with_tclconfig=`echo ${with_tclconfig} | sed 's!/tclConfig\.sh$!!'` fi ;; esac if test -f "${with_tclconfig}/tclConfig.sh" ; then ac_cv_c_tclconfig=`(cd ${with_tclconfig}; pwd)` else AC_MSG_ERROR([${with_tclconfig} directory doesn't contain tclConfig.sh]) fi fi # then check for a private Tcl installation if test x"${ac_cv_c_tclconfig}" = x ; then for i in \ ../tcl \ `ls -dr ../tcl[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \ `ls -dr ../tcl[[8-9]].[[0-9]] 2>/dev/null` \ `ls -dr ../tcl[[8-9]].[[0-9]]* 2>/dev/null` \ ../../tcl \ `ls -dr ../../tcl[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \ `ls -dr ../../tcl[[8-9]].[[0-9]] 2>/dev/null` \ `ls -dr ../../tcl[[8-9]].[[0-9]]* 2>/dev/null` \ ../../../tcl \ `ls -dr ../../../tcl[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \ `ls -dr ../../../tcl[[8-9]].[[0-9]] 2>/dev/null` \ `ls -dr ../../../tcl[[8-9]].[[0-9]]* 2>/dev/null` ; do if test -f "$i/unix/tclConfig.sh" ; then ac_cv_c_tclconfig=`(cd $i/unix; pwd)` break fi done fi # on Darwin, check in Framework installation locations if test "`uname -s`" = "Darwin" -a x"${ac_cv_c_tclconfig}" = x ; then for i in `ls -d ~/Library/Frameworks 2>/dev/null` \ `ls -d /Library/Frameworks 2>/dev/null` \ `ls -d /Network/Library/Frameworks 2>/dev/null` \ `ls -d /System/Library/Frameworks 2>/dev/null` \ ; do if test -f "$i/Tcl.framework/tclConfig.sh" ; then ac_cv_c_tclconfig=`(cd $i/Tcl.framework; pwd)` break fi done fi # on Windows, check in common installation locations if test "${TEA_PLATFORM}" = "windows" \ -a x"${ac_cv_c_tclconfig}" = x ; then for i in `ls -d C:/Tcl/lib 2>/dev/null` \ `ls -d C:/Progra~1/Tcl/lib 2>/dev/null` \ ; do if test -f "$i/tclConfig.sh" ; then ac_cv_c_tclconfig=`(cd $i; pwd)` break fi done fi # check in a few common install locations if test x"${ac_cv_c_tclconfig}" = x ; then for i in `ls -d ${libdir} 2>/dev/null` \ `ls -d ${exec_prefix}/lib 2>/dev/null` \ `ls -d ${prefix}/lib 2>/dev/null` \ `ls -d /usr/local/lib 2>/dev/null` \ `ls -d /usr/contrib/lib 2>/dev/null` \ `ls -d /usr/lib 2>/dev/null` \ ; do if test -f "$i/tclConfig.sh" ; then ac_cv_c_tclconfig=`(cd $i; pwd)` break fi done fi # check in a few other private locations if test x"${ac_cv_c_tclconfig}" = x ; then for i in \ ${srcdir}/../tcl \ `ls -dr ${srcdir}/../tcl[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \ `ls -dr ${srcdir}/../tcl[[8-9]].[[0-9]] 2>/dev/null` \ `ls -dr ${srcdir}/../tcl[[8-9]].[[0-9]]* 2>/dev/null` ; do if test -f "$i/unix/tclConfig.sh" ; then ac_cv_c_tclconfig=`(cd $i/unix; pwd)` break fi done fi ]) if test x"${ac_cv_c_tclconfig}" = x ; then TCL_BIN_DIR="# no Tcl configs found" AC_MSG_WARN([Can't find Tcl configuration definitions]) exit 0 else no_tcl= TCL_BIN_DIR=${ac_cv_c_tclconfig} AC_MSG_RESULT([found ${TCL_BIN_DIR}/tclConfig.sh]) fi fi ]) #------------------------------------------------------------------------ # TEA_PATH_TKCONFIG -- # # Locate the tkConfig.sh file # # Arguments: # none # # Results: # # Adds the following arguments to configure: # --with-tk=... # # Defines the following vars: # TK_BIN_DIR Full path to the directory containing # the tkConfig.sh file #------------------------------------------------------------------------ AC_DEFUN(TEA_PATH_TKCONFIG, [ # # Ok, lets find the tk configuration # First, look for one uninstalled. # the alternative search directory is invoked by --with-tk # if test x"${no_tk}" = x ; then # we reset no_tk in case something fails here no_tk=true AC_ARG_WITH(tk, AC_HELP_STRING([--with-tk], [directory containing tk configuration (tkConfig.sh)]), with_tkconfig=${withval}) AC_MSG_CHECKING([for Tk configuration]) AC_CACHE_VAL(ac_cv_c_tkconfig,[ # First check to see if --with-tkconfig was specified. if test x"${with_tkconfig}" != x ; then case ${with_tkconfig} in */tkConfig.sh ) if test -f ${with_tkconfig}; then AC_MSG_WARN([--with-tk argument should refer to directory containing tkConfig.sh, not to tkConfig.sh itself]) with_tkconfig=`echo ${with_tkconfig} | sed 's!/tkConfig\.sh$!!'` fi ;; esac if test -f "${with_tkconfig}/tkConfig.sh" ; then ac_cv_c_tkconfig=`(cd ${with_tkconfig}; pwd)` else AC_MSG_ERROR([${with_tkconfig} directory doesn't contain tkConfig.sh]) fi fi # then check for a private Tk library if test x"${ac_cv_c_tkconfig}" = x ; then for i in \ ../tk \ `ls -dr ../tk[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \ `ls -dr ../tk[[8-9]].[[0-9]] 2>/dev/null` \ `ls -dr ../tk[[8-9]].[[0-9]]* 2>/dev/null` \ ../../tk \ `ls -dr ../../tk[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \ `ls -dr ../../tk[[8-9]].[[0-9]] 2>/dev/null` \ `ls -dr ../../tk[[8-9]].[[0-9]]* 2>/dev/null` \ ../../../tk \ `ls -dr ../../../tk[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \ `ls -dr ../../../tk[[8-9]].[[0-9]] 2>/dev/null` \ `ls -dr ../../../tk[[8-9]].[[0-9]]* 2>/dev/null` ; do if test -f "$i/unix/tkConfig.sh" ; then ac_cv_c_tkconfig=`(cd $i/unix; pwd)` break fi done fi # on Darwin, check in Framework installation locations if test "`uname -s`" = "Darwin" -a x"${ac_cv_c_tkconfig}" = x ; then for i in `ls -d ~/Library/Frameworks 2>/dev/null` \ `ls -d /Library/Frameworks 2>/dev/null` \ `ls -d /Network/Library/Frameworks 2>/dev/null` \ `ls -d /System/Library/Frameworks 2>/dev/null` \ ; do if test -f "$i/Tk.framework/tkConfig.sh" ; then ac_cv_c_tkconfig=`(cd $i/Tk.framework; pwd)` break fi done fi # check in a few common install locations if test x"${ac_cv_c_tkconfig}" = x ; then for i in `ls -d ${libdir} 2>/dev/null` \ `ls -d ${exec_prefix}/lib 2>/dev/null` \ `ls -d ${prefix}/lib 2>/dev/null` \ `ls -d /usr/local/lib 2>/dev/null` \ `ls -d /usr/contrib/lib 2>/dev/null` \ `ls -d /usr/lib 2>/dev/null` \ ; do if test -f "$i/tkConfig.sh" ; then ac_cv_c_tkconfig=`(cd $i; pwd)` break fi done fi # on Windows, check in common installation locations if test "${TEA_PLATFORM}" = "windows" \ -a x"${ac_cv_c_tclconfig}" = x ; then for i in `ls -d C:/Tcl/lib 2>/dev/null` \ `ls -d C:/Progra~1/Tcl/lib 2>/dev/null` \ ; do if test -f "$i/tclConfig.sh" ; then ac_cv_c_tclconfig=`(cd $i; pwd)` break fi done fi # check in a few other private locations if test x"${ac_cv_c_tkconfig}" = x ; then for i in \ ${srcdir}/../tk \ `ls -dr ${srcdir}/../tk[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \ `ls -dr ${srcdir}/../tk[[8-9]].[[0-9]] 2>/dev/null` \ `ls -dr ${srcdir}/../tk[[8-9]].[[0-9]]* 2>/dev/null` ; do if test -f "$i/unix/tkConfig.sh" ; then ac_cv_c_tkconfig=`(cd $i/unix; pwd)` break fi done fi ]) if test x"${ac_cv_c_tkconfig}" = x ; then TK_BIN_DIR="# no Tk configs found" AC_MSG_WARN([Can't find Tk configuration definitions]) exit 0 else no_tk= TK_BIN_DIR=${ac_cv_c_tkconfig} AC_MSG_RESULT([found ${TK_BIN_DIR}/tkConfig.sh]) fi fi ]) #------------------------------------------------------------------------ # TEA_LOAD_TCLCONFIG -- # # Load the tclConfig.sh file # # Arguments: # # Requires the following vars to be set: # TCL_BIN_DIR # # Results: # # Subst the following vars: # TCL_BIN_DIR # TCL_SRC_DIR # TCL_LIB_FILE # #------------------------------------------------------------------------ AC_DEFUN(TEA_LOAD_TCLCONFIG, [ AC_MSG_CHECKING([for existence of ${TCL_BIN_DIR}/tclConfig.sh]) if test -f "${TCL_BIN_DIR}/tclConfig.sh" ; then AC_MSG_RESULT([loading]) . ${TCL_BIN_DIR}/tclConfig.sh else AC_MSG_RESULT([could not find ${TCL_BIN_DIR}/tclConfig.sh]) fi # eval is required to do the TCL_DBGX substitution eval "TCL_LIB_FILE=\"${TCL_LIB_FILE}\"" eval "TCL_STUB_LIB_FILE=\"${TCL_STUB_LIB_FILE}\"" # If the TCL_BIN_DIR is the build directory (not the install directory), # then set the common variable name to the value of the build variables. # For example, the variable TCL_LIB_SPEC will be set to the value # of TCL_BUILD_LIB_SPEC. An extension should make use of TCL_LIB_SPEC # instead of TCL_BUILD_LIB_SPEC since it will work with both an # installed and uninstalled version of Tcl. if test -f ${TCL_BIN_DIR}/Makefile ; then TCL_LIB_SPEC=${TCL_BUILD_LIB_SPEC} TCL_STUB_LIB_SPEC=${TCL_BUILD_STUB_LIB_SPEC} TCL_STUB_LIB_PATH=${TCL_BUILD_STUB_LIB_PATH} elif test "`uname -s`" = "Darwin"; then # If Tcl was built as a framework, attempt to use the libraries # from the framework at the given location so that linking works # against Tcl.framework installed in an arbitary location. case ${TCL_DEFS} in *TCL_FRAMEWORK*) if test -f ${TCL_BIN_DIR}/${TCL_LIB_FILE}; then for i in "`cd ${TCL_BIN_DIR}; pwd`" \ "`cd ${TCL_BIN_DIR}/../..; pwd`"; do if test "`basename "$i"`" = "${TCL_LIB_FILE}.framework"; then TCL_LIB_SPEC="-F`dirname "$i"` -framework ${TCL_LIB_FILE}" break fi done fi if test -f ${TCL_BIN_DIR}/${TCL_STUB_LIB_FILE}; then TCL_STUB_LIB_SPEC="-L${TCL_BIN_DIR} ${TCL_STUB_LIB_FLAG}" TCL_STUB_LIB_PATH="${TCL_BIN_DIR}/${TCL_STUB_LIB_FILE}" fi ;; esac fi # eval is required to do the TCL_DBGX substitution eval "TCL_LIB_FLAG=\"${TCL_LIB_FLAG}\"" eval "TCL_LIB_SPEC=\"${TCL_LIB_SPEC}\"" eval "TCL_STUB_LIB_FLAG=\"${TCL_STUB_LIB_FLAG}\"" eval "TCL_STUB_LIB_SPEC=\"${TCL_STUB_LIB_SPEC}\"" AC_SUBST(TCL_VERSION) AC_SUBST(TCL_BIN_DIR) AC_SUBST(TCL_SRC_DIR) AC_SUBST(TCL_LIB_FILE) AC_SUBST(TCL_LIB_FLAG) AC_SUBST(TCL_LIB_SPEC) AC_SUBST(TCL_STUB_LIB_FILE) AC_SUBST(TCL_STUB_LIB_FLAG) AC_SUBST(TCL_STUB_LIB_SPEC) AC_SUBST(TCL_LIBS) AC_SUBST(TCL_DEFS) AC_SUBST(TCL_EXTRA_CFLAGS) AC_SUBST(TCL_LD_FLAGS) AC_SUBST(TCL_SHLIB_LD_LIBS) ]) #------------------------------------------------------------------------ # TEA_LOAD_TKCONFIG -- # # Load the tkConfig.sh file # # Arguments: # # Requires the following vars to be set: # TK_BIN_DIR # # Results: # # Sets the following vars that should be in tkConfig.sh: # TK_BIN_DIR #------------------------------------------------------------------------ AC_DEFUN(TEA_LOAD_TKCONFIG, [ AC_MSG_CHECKING([for existence of ${TK_BIN_DIR}/tkConfig.sh]) if test -f "${TK_BIN_DIR}/tkConfig.sh" ; then AC_MSG_RESULT([loading]) . ${TK_BIN_DIR}/tkConfig.sh else AC_MSG_RESULT([could not find ${TK_BIN_DIR}/tkConfig.sh]) fi # eval is required to do the TK_DBGX substitution eval "TK_LIB_FILE=\"${TK_LIB_FILE}\"" eval "TK_STUB_LIB_FILE=\"${TK_STUB_LIB_FILE}\"" # If the TK_BIN_DIR is the build directory (not the install directory), # then set the common variable name to the value of the build variables. # For example, the variable TK_LIB_SPEC will be set to the value # of TK_BUILD_LIB_SPEC. An extension should make use of TK_LIB_SPEC # instead of TK_BUILD_LIB_SPEC since it will work with both an # installed and uninstalled version of Tcl. if test -f ${TK_BIN_DIR}/Makefile ; then TK_LIB_SPEC=${TK_BUILD_LIB_SPEC} TK_STUB_LIB_SPEC=${TK_BUILD_STUB_LIB_SPEC} TK_STUB_LIB_PATH=${TK_BUILD_STUB_LIB_PATH} elif test "`uname -s`" = "Darwin"; then # If Tk was built as a framework, attempt to use the libraries # from the framework at the given location so that linking works # against Tk.framework installed in an arbitary location. case ${TK_DEFS} in *TK_FRAMEWORK*) if test -f ${TK_BIN_DIR}/${TK_LIB_FILE}; then for i in "`cd ${TK_BIN_DIR}; pwd`" \ "`cd ${TK_BIN_DIR}/../..; pwd`"; do if test "`basename "$i"`" = "${TK_LIB_FILE}.framework"; then TK_LIB_SPEC="-F`dirname "$i"` -framework ${TK_LIB_FILE}" break fi done fi if test -f ${TK_BIN_DIR}/${TK_STUB_LIB_FILE}; then TK_STUB_LIB_SPEC="-L${TK_BIN_DIR} ${TK_STUB_LIB_FLAG}" TK_STUB_LIB_PATH="${TK_BIN_DIR}/${TK_STUB_LIB_FILE}" fi ;; esac fi # eval is required to do the TK_DBGX substitution eval "TK_LIB_FLAG=\"${TK_LIB_FLAG}\"" eval "TK_LIB_SPEC=\"${TK_LIB_SPEC}\"" eval "TK_STUB_LIB_FLAG=\"${TK_STUB_LIB_FLAG}\"" eval "TK_STUB_LIB_SPEC=\"${TK_STUB_LIB_SPEC}\"" # Ensure windowingsystem is defined if test "${TEA_PLATFORM}" = "unix" ; then case ${TK_DEFS} in *MAC_OSX_TK*) AC_DEFINE(MAC_OSX_TK, 1, [Are we building against Mac OS X TkAqua?]) TEA_WINDOWINGSYSTEM="aqua" ;; *) TEA_WINDOWINGSYSTEM="x11" ;; esac elif test "${TEA_PLATFORM}" = "windows" ; then TEA_WINDOWINGSYSTEM="win32" fi AC_SUBST(TK_VERSION) AC_SUBST(TK_BIN_DIR) AC_SUBST(TK_SRC_DIR) AC_SUBST(TK_LIB_FILE) AC_SUBST(TK_LIB_FLAG) AC_SUBST(TK_LIB_SPEC) AC_SUBST(TK_STUB_LIB_FILE) AC_SUBST(TK_STUB_LIB_FLAG) AC_SUBST(TK_STUB_LIB_SPEC) AC_SUBST(TK_LIBS) AC_SUBST(TK_XINCLUDES) ]) #------------------------------------------------------------------------ # TEA_ENABLE_SHARED -- # # Allows the building of shared libraries # # Arguments: # none # # Results: # # Adds the following arguments to configure: # --enable-shared=yes|no # # Defines the following vars: # STATIC_BUILD Used for building import/export libraries # on Windows. # # Sets the following vars: # SHARED_BUILD Value of 1 or 0 #------------------------------------------------------------------------ AC_DEFUN(TEA_ENABLE_SHARED, [ AC_MSG_CHECKING([how to build libraries]) AC_ARG_ENABLE(shared, AC_HELP_STRING([--enable-shared], [build and link with shared libraries (default: on)]), [tcl_ok=$enableval], [tcl_ok=yes]) if test "${enable_shared+set}" = set; then enableval="$enable_shared" tcl_ok=$enableval else tcl_ok=yes fi if test "$tcl_ok" = "yes" ; then AC_MSG_RESULT([shared]) SHARED_BUILD=1 else AC_MSG_RESULT([static]) SHARED_BUILD=0 AC_DEFINE(STATIC_BUILD, 1, [Is this a static build?]) fi AC_SUBST(SHARED_BUILD) ]) #------------------------------------------------------------------------ # TEA_ENABLE_THREADS -- # # Specify if thread support should be enabled. If "yes" is specified # as an arg (optional), threads are enabled by default, "no" means # threads are disabled. "yes" is the default. # # TCL_THREADS is checked so that if you are compiling an extension # against a threaded core, your extension must be compiled threaded # as well. # # Note that it is legal to have a thread enabled extension run in a # threaded or non-threaded Tcl core, but a non-threaded extension may # only run in a non-threaded Tcl core. # # Arguments: # none # # Results: # # Adds the following arguments to configure: # --enable-threads # # Sets the following vars: # THREADS_LIBS Thread library(s) # # Defines the following vars: # TCL_THREADS # _REENTRANT # _THREAD_SAFE # #------------------------------------------------------------------------ AC_DEFUN(TEA_ENABLE_THREADS, [ AC_ARG_ENABLE(threads, AC_HELP_STRING([--enable-threads], [build with threads]), [tcl_ok=$enableval], [tcl_ok=yes]) if test "${enable_threads+set}" = set; then enableval="$enable_threads" tcl_ok=$enableval else tcl_ok=yes fi if test "$tcl_ok" = "yes" -o "${TCL_THREADS}" = 1; then TCL_THREADS=1 if test "${TEA_PLATFORM}" != "windows" ; then # We are always OK on Windows, so check what this platform wants: # USE_THREAD_ALLOC tells us to try the special thread-based # allocator that significantly reduces lock contention AC_DEFINE(USE_THREAD_ALLOC, 1, [Do we want to use the threaded memory allocator?]) AC_DEFINE(_REENTRANT, 1, [Do we want the reentrant OS API?]) if test "`uname -s`" = "SunOS" ; then AC_DEFINE(_POSIX_PTHREAD_SEMANTICS, 1, [Do we really want to follow the standard? Yes we do!]) fi AC_DEFINE(_THREAD_SAFE, 1, [Do we want the thread-safe OS API?]) AC_CHECK_LIB(pthread,pthread_mutex_init,tcl_ok=yes,tcl_ok=no) if test "$tcl_ok" = "no"; then # Check a little harder for __pthread_mutex_init in the same # library, as some systems hide it there until pthread.h is # defined. We could alternatively do an AC_TRY_COMPILE with # pthread.h, but that will work with libpthread really doesn't # exist, like AIX 4.2. [Bug: 4359] AC_CHECK_LIB(pthread, __pthread_mutex_init, tcl_ok=yes, tcl_ok=no) fi if test "$tcl_ok" = "yes"; then # The space is needed THREADS_LIBS=" -lpthread" else AC_CHECK_LIB(pthreads, pthread_mutex_init, tcl_ok=yes, tcl_ok=no) if test "$tcl_ok" = "yes"; then # The space is needed THREADS_LIBS=" -lpthreads" else AC_CHECK_LIB(c, pthread_mutex_init, tcl_ok=yes, tcl_ok=no) if test "$tcl_ok" = "no"; then AC_CHECK_LIB(c_r, pthread_mutex_init, tcl_ok=yes, tcl_ok=no) if test "$tcl_ok" = "yes"; then # The space is needed THREADS_LIBS=" -pthread" else TCL_THREADS=0 AC_MSG_WARN([Do not know how to find pthread lib on your system - thread support disabled]) fi fi fi fi fi else TCL_THREADS=0 fi # Do checking message here to not mess up interleaved configure output AC_MSG_CHECKING([for building with threads]) if test "${TCL_THREADS}" = 1; then AC_DEFINE(TCL_THREADS, 1, [Are we building with threads enabled?]) AC_MSG_RESULT([yes (default)]) else AC_MSG_RESULT([no]) fi # TCL_THREADS sanity checking. See if our request for building with # threads is the same as the way Tcl was built. If not, warn the user. case ${TCL_DEFS} in *THREADS=1*) if test "${TCL_THREADS}" = "0"; then AC_MSG_WARN([ Building ${PACKAGE_NAME} without threads enabled, but building against Tcl that IS thread-enabled. It is recommended to use --enable-threads.]) fi ;; *) if test "${TCL_THREADS}" = "1"; then AC_MSG_WARN([ --enable-threads requested, but building against a Tcl that is NOT thread-enabled. This is an OK configuration that will also run in a thread-enabled core.]) fi ;; esac AC_SUBST(TCL_THREADS) ]) #------------------------------------------------------------------------ # TEA_ENABLE_SYMBOLS -- # # Specify if debugging symbols should be used. # Memory (TCL_MEM_DEBUG) debugging can also be enabled. # # Arguments: # none # # TEA varies from core Tcl in that C|LDFLAGS_DEFAULT receives # the value of C|LDFLAGS_OPTIMIZE|DEBUG already substituted. # Requires the following vars to be set in the Makefile: # CFLAGS_DEFAULT # LDFLAGS_DEFAULT # # Results: # # Adds the following arguments to configure: # --enable-symbols # # Defines the following vars: # CFLAGS_DEFAULT Sets to $(CFLAGS_DEBUG) if true # Sets to $(CFLAGS_OPTIMIZE) if false # LDFLAGS_DEFAULT Sets to $(LDFLAGS_DEBUG) if true # Sets to $(LDFLAGS_OPTIMIZE) if false # DBGX Formerly used as debug library extension; # always blank now. # #------------------------------------------------------------------------ AC_DEFUN(TEA_ENABLE_SYMBOLS, [ dnl Make sure we are initialized AC_REQUIRE([TEA_CONFIG_CFLAGS]) AC_MSG_CHECKING([for build with symbols]) AC_ARG_ENABLE(symbols, AC_HELP_STRING([--enable-symbols], [build with debugging symbols (default: off)]), [tcl_ok=$enableval], [tcl_ok=no]) DBGX="" if test "$tcl_ok" = "no"; then CFLAGS_DEFAULT="${CFLAGS_OPTIMIZE}" LDFLAGS_DEFAULT="${LDFLAGS_OPTIMIZE}" AC_MSG_RESULT([no]) else CFLAGS_DEFAULT="${CFLAGS_DEBUG}" LDFLAGS_DEFAULT="${LDFLAGS_DEBUG}" if test "$tcl_ok" = "yes"; then AC_MSG_RESULT([yes (standard debugging)]) fi fi if test "${TEA_PLATFORM}" != "windows" ; then LDFLAGS_DEFAULT="${LDFLAGS}" fi AC_SUBST(TCL_DBGX) AC_SUBST(CFLAGS_DEFAULT) AC_SUBST(LDFLAGS_DEFAULT) if test "$tcl_ok" = "mem" -o "$tcl_ok" = "all"; then AC_DEFINE(TCL_MEM_DEBUG, 1, [Is memory debugging enabled?]) fi if test "$tcl_ok" != "yes" -a "$tcl_ok" != "no"; then if test "$tcl_ok" = "all"; then AC_MSG_RESULT([enabled symbols mem debugging]) else AC_MSG_RESULT([enabled $tcl_ok debugging]) fi fi ]) #------------------------------------------------------------------------ # TEA_ENABLE_LANGINFO -- # # Allows use of modern nl_langinfo check for better l10n. # This is only relevant for Unix. # # Arguments: # none # # Results: # # Adds the following arguments to configure: # --enable-langinfo=yes|no (default is yes) # # Defines the following vars: # HAVE_LANGINFO Triggers use of nl_langinfo if defined. # #------------------------------------------------------------------------ AC_DEFUN(TEA_ENABLE_LANGINFO, [ AC_ARG_ENABLE(langinfo, AC_HELP_STRING([--enable-langinfo], [use nl_langinfo if possible to determine encoding at startup, otherwise use old heuristic (default: on)]), [langinfo_ok=$enableval], [langinfo_ok=yes]) HAVE_LANGINFO=0 if test "$langinfo_ok" = "yes"; then AC_CHECK_HEADER(langinfo.h,[langinfo_ok=yes],[langinfo_ok=no]) fi AC_MSG_CHECKING([whether to use nl_langinfo]) if test "$langinfo_ok" = "yes"; then AC_CACHE_VAL(tcl_cv_langinfo_h, AC_TRY_COMPILE([#include <langinfo.h>], [nl_langinfo(CODESET);], [tcl_cv_langinfo_h=yes],[tcl_cv_langinfo_h=no])) AC_MSG_RESULT([$tcl_cv_langinfo_h]) if test $tcl_cv_langinfo_h = yes; then AC_DEFINE(HAVE_LANGINFO, 1, [Do we have nl_langinfo()?]) fi else AC_MSG_RESULT([$langinfo_ok]) fi ]) #-------------------------------------------------------------------- # TEA_CONFIG_SYSTEM # # Determine what the system is (some things cannot be easily checked # on a feature-driven basis, alas). This can usually be done via the # "uname" command, but there are a few systems, like Next, where # this doesn't work. # # Arguments: # none # # Results: # Defines the following var: # # system - System/platform/version identification code. # #-------------------------------------------------------------------- AC_DEFUN(TEA_CONFIG_SYSTEM, [ AC_CACHE_CHECK([system version], tcl_cv_sys_version, [ if test "${TEA_PLATFORM}" = "windows" ; then tcl_cv_sys_version=windows elif test -f /usr/lib/NextStep/software_version; then tcl_cv_sys_version=NEXTSTEP-`awk '/3/,/3/' /usr/lib/NextStep/software_version` else tcl_cv_sys_version=`uname -s`-`uname -r` if test "$?" -ne 0 ; then AC_MSG_WARN([can't find uname command]) tcl_cv_sys_version=unknown else # Special check for weird MP-RAS system (uname returns weird # results, and the version is kept in special file). if test -r /etc/.relid -a "X`uname -n`" = "X`uname -s`" ; then tcl_cv_sys_version=MP-RAS-`awk '{print $3}' /etc/.relid` fi if test "`uname -s`" = "AIX" ; then tcl_cv_sys_version=AIX-`uname -v`.`uname -r` fi fi fi ]) system=$tcl_cv_sys_version ]) #-------------------------------------------------------------------- # TEA_CONFIG_CFLAGS # # Try to determine the proper flags to pass to the compiler # for building shared libraries and other such nonsense. # # Arguments: # none # # Results: # # Defines and substitutes the following vars: # # DL_OBJS - Name of the object file that implements dynamic # loading for Tcl on this system. # DL_LIBS - Library file(s) to include in tclsh and other base # applications in order for the "load" command to work. # LDFLAGS - Flags to pass to the compiler when linking object # files into an executable application binary such # as tclsh. # LD_SEARCH_FLAGS-Flags to pass to ld, such as "-R /usr/local/tcl/lib", # that tell the run-time dynamic linker where to look # for shared libraries such as libtcl.so. Depends on # the variable LIB_RUNTIME_DIR in the Makefile. Could # be the same as CC_SEARCH_FLAGS if ${CC} is used to link. # CC_SEARCH_FLAGS-Flags to pass to ${CC}, such as "-Wl,-rpath,/usr/local/tcl/lib", # that tell the run-time dynamic linker where to look # for shared libraries such as libtcl.so. Depends on # the variable LIB_RUNTIME_DIR in the Makefile. # SHLIB_CFLAGS - Flags to pass to cc when compiling the components # of a shared library (may request position-independent # code, among other things). # SHLIB_LD - Base command to use for combining object files # into a shared library. # SHLIB_LD_LIBS - Dependent libraries for the linker to scan when # creating shared libraries. This symbol typically # goes at the end of the "ld" commands that build # shared libraries. The value of the symbol is # "${LIBS}" if all of the dependent libraries should # be specified when creating a shared library. If # dependent libraries should not be specified (as on # SunOS 4.x, where they cause the link to fail, or in # general if Tcl and Tk aren't themselves shared # libraries), then this symbol has an empty string # as its value. # SHLIB_SUFFIX - Suffix to use for the names of dynamically loadable # extensions. An empty string means we don't know how # to use shared libraries on this platform. # LIB_SUFFIX - Specifies everything that comes after the "libfoo" # in a static or shared library name, using the $VERSION variable # to put the version in the right place. This is used # by platforms that need non-standard library names. # Examples: ${VERSION}.so.1.1 on NetBSD, since it needs # to have a version after the .so, and ${VERSION}.a # on AIX, since a shared library needs to have # a .a extension whereas shared objects for loadable # extensions have a .so extension. Defaults to # ${VERSION}${SHLIB_SUFFIX}. # TCL_NEEDS_EXP_FILE - # 1 means that an export file is needed to link to a # shared library. # TCL_EXP_FILE - The name of the installed export / import file which # should be used to link to the Tcl shared library. # Empty if Tcl is unshared. # TCL_BUILD_EXP_FILE - # The name of the built export / import file which # should be used to link to the Tcl shared library. # Empty if Tcl is unshared. # CFLAGS_DEBUG - # Flags used when running the compiler in debug mode # CFLAGS_OPTIMIZE - # Flags used when running the compiler in optimize mode # CFLAGS - Additional CFLAGS added as necessary (usually 64-bit) # #-------------------------------------------------------------------- AC_DEFUN(TEA_CONFIG_CFLAGS, [ dnl Make sure we are initialized AC_REQUIRE([TEA_INIT]) # Step 0.a: Enable 64 bit support? AC_MSG_CHECKING([if 64bit support is requested]) AC_ARG_ENABLE(64bit, AC_HELP_STRING([--enable-64bit], [enable 64bit support (default: off)]), [do64bit=$enableval], [do64bit=no]) AC_MSG_RESULT([$do64bit]) # Step 0.b: Enable Solaris 64 bit VIS support? AC_MSG_CHECKING([if 64bit Sparc VIS support is requested]) AC_ARG_ENABLE(64bit-vis, AC_HELP_STRING([--enable-64bit-vis], [enable 64bit Sparc VIS support (default: off)]), [do64bitVIS=$enableval], [do64bitVIS=no]) AC_MSG_RESULT([$do64bitVIS]) if test "$do64bitVIS" = "yes"; then # Force 64bit on with VIS do64bit=yes fi # Step 0.c: Cross-compiling options for Windows/CE builds? if test "${TEA_PLATFORM}" = "windows" ; then AC_MSG_CHECKING([if Windows/CE build is requested]) AC_ARG_ENABLE(wince,[ --enable-wince enable Win/CE support (where applicable)], [doWince=$enableval], [doWince=no]) AC_MSG_RESULT([$doWince]) fi # Step 1: set the variable "system" to hold the name and version number # for the system. TEA_CONFIG_SYSTEM # Step 2: check for existence of -ldl library. This is needed because # Linux can use either -ldl or -ldld for dynamic loading. AC_CHECK_LIB(dl, dlopen, have_dl=yes, have_dl=no) # Require ranlib early so we can override it in special cases below. AC_REQUIRE([AC_PROG_RANLIB]) # Step 3: set configuration options based on system name and version. # This is similar to Tcl's unix/tcl.m4 except that we've added a # "windows" case. do64bit_ok=no LDFLAGS_ORIG="$LDFLAGS" # When ld needs options to work in 64-bit mode, put them in # LDFLAGS_ARCH so they eventually end up in LDFLAGS even if [load] # is disabled by the user. [Bug 1016796] LDFLAGS_ARCH="" TCL_EXPORT_FILE_SUFFIX="" UNSHARED_LIB_SUFFIX="" TCL_TRIM_DOTS='`echo ${PACKAGE_VERSION} | tr -d .`' ECHO_VERSION='`echo ${PACKAGE_VERSION}`' TCL_LIB_VERSIONS_OK=ok CFLAGS_DEBUG=-g CFLAGS_OPTIMIZE=-O if test "$GCC" = "yes" ; then CFLAGS_OPTIMIZE=-O2 CFLAGS_WARNING="-Wall -Wno-implicit-int" else CFLAGS_WARNING="" fi TCL_NEEDS_EXP_FILE=0 TCL_BUILD_EXP_FILE="" TCL_EXP_FILE="" dnl FIXME: Replace AC_CHECK_PROG with AC_CHECK_TOOL once cross compiling is fixed. dnl AC_CHECK_TOOL(AR, ar) AC_CHECK_PROG(AR, ar, ar) STLIB_LD='${AR} cr' LD_LIBRARY_PATH_VAR="LD_LIBRARY_PATH" case $system in windows) # This is a 2-stage check to make sure we have the 64-bit SDK # We have to know where the SDK is installed. # This magic is based on MS Platform SDK for Win2003 SP1 - hobbs # MACHINE is IX86 for LINK, but this is used by the manifest, # which requires x86|amd64|ia64. MACHINE="X86" if test "$do64bit" != "no" ; then if test "x${MSSDK}x" = "xx" ; then MSSDK="C:/Progra~1/Microsoft Platform SDK" fi MSSDK=`echo "$MSSDK" | sed -e 's!\\\!/!g'` PATH64="" case "$do64bit" in amd64|x64|yes) MACHINE="AMD64" ; # default to AMD64 64-bit build PATH64="${MSSDK}/Bin/Win64/x86/AMD64" ;; ia64) MACHINE="IA64" PATH64="${MSSDK}/Bin/Win64" ;; esac if test ! -d "${PATH64}" ; then AC_MSG_WARN([Could not find 64-bit $MACHINE SDK to enable 64bit mode]) AC_MSG_WARN([Ensure latest Platform SDK is installed]) do64bit="no" else AC_MSG_RESULT([ Using 64-bit $MACHINE mode]) do64bit_ok="yes" fi fi if test "$doWince" != "no" ; then if test "$do64bit" != "no" ; then AC_MSG_ERROR([Windows/CE and 64-bit builds incompatible]) fi if test "$GCC" = "yes" ; then AC_MSG_ERROR([Windows/CE and GCC builds incompatible]) fi TEA_PATH_CELIB # Set defaults for common evc4/PPC2003 setup # Currently Tcl requires 300+, possibly 420+ for sockets CEVERSION=420; # could be 211 300 301 400 420 ... TARGETCPU=ARMV4; # could be ARMV4 ARM MIPS SH3 X86 ... ARCH=ARM; # could be ARM MIPS X86EM ... PLATFORM="Pocket PC 2003"; # or "Pocket PC 2002" if test "$doWince" != "yes"; then # If !yes then the user specified something # Reset ARCH to allow user to skip specifying it ARCH= eval `echo $doWince | awk -F, '{ \ if (length([$]1)) { printf "CEVERSION=\"%s\"\n", [$]1; \ if ([$]1 < 400) { printf "PLATFORM=\"Pocket PC 2002\"\n" } }; \ if (length([$]2)) { printf "TARGETCPU=\"%s\"\n", toupper([$]2) }; \ if (length([$]3)) { printf "ARCH=\"%s\"\n", toupper([$]3) }; \ if (length([$]4)) { printf "PLATFORM=\"%s\"\n", [$]4 }; \ }'` if test "x${ARCH}" = "x" ; then ARCH=$TARGETCPU; fi fi OSVERSION=WCE$CEVERSION; if test "x${WCEROOT}" = "x" ; then WCEROOT="C:/Program Files/Microsoft eMbedded C++ 4.0" if test ! -d "${WCEROOT}" ; then WCEROOT="C:/Program Files/Microsoft eMbedded Tools" fi fi if test "x${SDKROOT}" = "x" ; then SDKROOT="C:/Program Files/Windows CE Tools" if test ! -d "${SDKROOT}" ; then SDKROOT="C:/Windows CE Tools" fi fi WCEROOT=`echo "$WCEROOT" | sed -e 's!\\\!/!g'` SDKROOT=`echo "$SDKROOT" | sed -e 's!\\\!/!g'` if test ! -d "${SDKROOT}/${OSVERSION}/${PLATFORM}/Lib/${TARGETCPU}" \ -o ! -d "${WCEROOT}/EVC/${OSVERSION}/bin"; then AC_MSG_ERROR([could not find PocketPC SDK or target compiler to enable WinCE mode [$CEVERSION,$TARGETCPU,$ARCH,$PLATFORM]]) doWince="no" else # We could PATH_NOSPACE these, but that's not important, # as long as we quote them when used. CEINCLUDE="${SDKROOT}/${OSVERSION}/${PLATFORM}/include" if test -d "${CEINCLUDE}/${TARGETCPU}" ; then CEINCLUDE="${CEINCLUDE}/${TARGETCPU}" fi CELIBPATH="${SDKROOT}/${OSVERSION}/${PLATFORM}/Lib/${TARGETCPU}" fi fi if test "$GCC" != "yes" ; then if test "${SHARED_BUILD}" = "0" ; then runtime=-MT else runtime=-MD fi if test "$do64bit" != "no" ; then # All this magic is necessary for the Win64 SDK RC1 - hobbs CC="\"${PATH64}/cl.exe\"" CFLAGS="${CFLAGS} -I\"${MSSDK}/Include\" -I\"${MSSDK}/Include/crt\" -I\"${MSSDK}/Include/crt/sys\"" RC="\"${MSSDK}/bin/rc.exe\"" lflags="-nologo -MACHINE:${MACHINE} -LIBPATH:\"${MSSDK}/Lib/${MACHINE}\"" LINKBIN="\"${PATH64}/link.exe\"" CFLAGS_DEBUG="-nologo -Zi -Od -W3 ${runtime}d" CFLAGS_OPTIMIZE="-nologo -O2 -W2 ${runtime}" # Avoid 'unresolved external symbol __security_cookie' # errors, c.f. http://support.microsoft.com/?id=894573 TEA_ADD_LIBS([bufferoverflowU.lib]) elif test "$doWince" != "no" ; then CEBINROOT="${WCEROOT}/EVC/${OSVERSION}/bin" if test "${TARGETCPU}" = "X86"; then CC="\"${CEBINROOT}/cl.exe\"" else CC="\"${CEBINROOT}/cl${ARCH}.exe\"" fi CFLAGS="$CFLAGS -I\"${CELIB_DIR}/inc\" -I\"${CEINCLUDE}\"" RC="\"${WCEROOT}/Common/EVC/bin/rc.exe\"" arch=`echo ${ARCH} | awk '{print tolower([$]0)}'` defs="${ARCH} _${ARCH}_ ${arch} PALM_SIZE _MT _WINDOWS" if test "${SHARED_BUILD}" = "1" ; then # Static CE builds require static celib as well defs="${defs} _DLL" fi for i in $defs ; do AC_DEFINE_UNQUOTED($i, 1, [WinCE def ]$i) done AC_DEFINE_UNQUOTED(_WIN32_WCE, $CEVERSION, [_WIN32_WCE version]) AC_DEFINE_UNQUOTED(UNDER_CE, $CEVERSION, [UNDER_CE version]) CFLAGS_DEBUG="-nologo -Zi -Od" CFLAGS_OPTIMIZE="-nologo -Ox" lversion=`echo ${CEVERSION} | sed -e 's/\(.\)\(..\)/\1\.\2/'` lflags="-MACHINE:${ARCH} -LIBPATH:\"${CELIBPATH}\" -subsystem:windowsce,${lversion} -nologo" LINKBIN="\"${CEBINROOT}/link.exe\"" AC_SUBST(CELIB_DIR) else RC="rc" lflags="-nologo" LINKBIN="link" CFLAGS_DEBUG="-nologo -Z7 -Od -W3 -WX ${runtime}d" CFLAGS_OPTIMIZE="-nologo -O2 -W2 ${runtime}" fi fi if test "$GCC" = "yes"; then # mingw gcc mode RC="windres" CFLAGS_DEBUG="-g" CFLAGS_OPTIMIZE="-O2 -fomit-frame-pointer" SHLIB_LD="$CC -shared" UNSHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.a' LDFLAGS_CONSOLE="-wl,--subsystem,console ${lflags}" LDFLAGS_WINDOW="-wl,--subsystem,windows ${lflags}" else SHLIB_LD="${LINKBIN} -dll ${lflags}" # link -lib only works when -lib is the first arg STLIB_LD="${LINKBIN} -lib ${lflags}" UNSHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.lib' PATHTYPE=-w # For information on what debugtype is most useful, see: # http://msdn.microsoft.com/library/en-us/dnvc60/html/gendepdebug.asp # This essentially turns it all on. LDFLAGS_DEBUG="-debug:full -debugtype:both -warn:2" LDFLAGS_OPTIMIZE="-release" if test "$doWince" != "no" ; then LDFLAGS_CONSOLE="-link ${lflags}" LDFLAGS_WINDOW=${LDFLAGS_CONSOLE} else LDFLAGS_CONSOLE="-link -subsystem:console ${lflags}" LDFLAGS_WINDOW="-link -subsystem:windows ${lflags}" fi fi SHLIB_LD_LIBS='${LIBS}' SHLIB_SUFFIX=".dll" SHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.dll' TCL_LIB_VERSIONS_OK=nodots # Bogus to avoid getting this turned off DL_OBJS="tclLoadNone.obj" ;; AIX-*) if test "${TCL_THREADS}" = "1" -a "$GCC" != "yes" ; then # AIX requires the _r compiler when gcc isn't being used case "${CC}" in *_r) # ok ... ;; *) CC=${CC}_r ;; esac AC_MSG_RESULT([Using $CC for compiling with threads]) fi LIBS="$LIBS -lc" SHLIB_CFLAGS="" SHLIB_LD_LIBS='${LIBS}' SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" LD_LIBRARY_PATH_VAR="LIBPATH" # Check to enable 64-bit flags for compiler/linker on AIX 4+ if test "$do64bit" = "yes" -a "`uname -v`" -gt "3" ; then if test "$GCC" = "yes" ; then AC_MSG_WARN([64bit mode not supported with GCC on $system]) else do64bit_ok=yes CFLAGS="$CFLAGS -q64" LDFLAGS_ARCH="-q64" RANLIB="${RANLIB} -X64" AR="${AR} -X64" SHLIB_LD_FLAGS="-b64" fi fi if test "`uname -m`" = "ia64" ; then # AIX-5 uses ELF style dynamic libraries on IA-64, but not PPC SHLIB_LD="/usr/ccs/bin/ld -G -z text" # AIX-5 has dl* in libc.so DL_LIBS="" if test "$GCC" = "yes" ; then CC_SEARCH_FLAGS='-Wl,-R,${LIB_RUNTIME_DIR}' else CC_SEARCH_FLAGS='-R${LIB_RUNTIME_DIR}' fi LD_SEARCH_FLAGS='-R ${LIB_RUNTIME_DIR}' else if test "$GCC" = "yes" ; then SHLIB_LD="gcc -shared" else SHLIB_LD="/bin/ld -bhalt:4 -bM:SRE -bE:lib.exp -H512 -T512 -bnoentry" fi SHLIB_LD="${TCL_SRC_DIR}/unix/ldAix ${SHLIB_LD} ${SHLIB_LD_FLAGS}" DL_LIBS="-ldl" CC_SEARCH_FLAGS='-L${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} TCL_NEEDS_EXP_FILE=1 TCL_EXPORT_FILE_SUFFIX='${PACKAGE_VERSION}.exp' fi # AIX v<=4.1 has some different flags than 4.2+ if test "$system" = "AIX-4.1" -o "`uname -v`" -lt "4" ; then AC_LIBOBJ([tclLoadAix]) DL_LIBS="-lld" fi # On AIX <=v4 systems, libbsd.a has to be linked in to support # non-blocking file IO. This library has to be linked in after # the MATH_LIBS or it breaks the pow() function. The way to # insure proper sequencing, is to add it to the tail of MATH_LIBS. # This library also supplies gettimeofday. # # AIX does not have a timezone field in struct tm. When the AIX # bsd library is used, the timezone global and the gettimeofday # methods are to be avoided for timezone deduction instead, we # deduce the timezone by comparing the localtime result on a # known GMT value. AC_CHECK_LIB(bsd, gettimeofday, libbsd=yes, libbsd=no) if test $libbsd = yes; then MATH_LIBS="$MATH_LIBS -lbsd" AC_DEFINE(USE_DELTA_FOR_TZ, 1, [Do we need a special AIX hack for timezones?]) fi ;; BeOS*) SHLIB_CFLAGS="-fPIC" SHLIB_LD="${CC} -nostart" SHLIB_LD_LIBS='${LIBS}' SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" DL_LIBS="-ldl" #----------------------------------------------------------- # Check for inet_ntoa in -lbind, for BeOS (which also needs # -lsocket, even if the network functions are in -lnet which # is always linked to, for compatibility. #----------------------------------------------------------- AC_CHECK_LIB(bind, inet_ntoa, [LIBS="$LIBS -lbind -lsocket"]) ;; BSD/OS-2.1*|BSD/OS-3*) SHLIB_CFLAGS="" SHLIB_LD="shlicc -r" SHLIB_LD_LIBS='${LIBS}' SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" DL_LIBS="-ldl" CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" ;; BSD/OS-4.*) SHLIB_CFLAGS="-export-dynamic -fPIC" SHLIB_LD="cc -shared" SHLIB_LD_LIBS='${LIBS}' SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" DL_LIBS="-ldl" LDFLAGS="$LDFLAGS -export-dynamic" CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" ;; dgux*) SHLIB_CFLAGS="-K PIC" SHLIB_LD="cc -G" SHLIB_LD_LIBS="" SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" DL_LIBS="-ldl" CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" ;; HP-UX-*.11.*) # Use updated header definitions where possible AC_DEFINE(_XOPEN_SOURCE_EXTENDED, 1, [Do we want to use the XOPEN network library?]) # Needed by Tcl, but not most extensions #AC_DEFINE(_XOPEN_SOURCE, 1, [Do we want to use the XOPEN network library?]) #LIBS="$LIBS -lxnet" # Use the XOPEN network library SHLIB_SUFFIX=".sl" AC_CHECK_LIB(dld, shl_load, tcl_ok=yes, tcl_ok=no) if test "$tcl_ok" = yes; then SHLIB_CFLAGS="+z" SHLIB_LD="ld -b" SHLIB_LD_LIBS='${LIBS}' DL_OBJS="tclLoadShl.o" DL_LIBS="-ldld" LDFLAGS="$LDFLAGS -Wl,-E" CC_SEARCH_FLAGS='-Wl,+s,+b,${LIB_RUNTIME_DIR}:.' LD_SEARCH_FLAGS='+s +b ${LIB_RUNTIME_DIR}:.' LD_LIBRARY_PATH_VAR="SHLIB_PATH" fi if test "$GCC" = "yes" ; then SHLIB_LD="gcc -shared" SHLIB_LD_LIBS='${LIBS}' LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} fi # Users may want PA-RISC 1.1/2.0 portable code - needs HP cc #CFLAGS="$CFLAGS +DAportable" # Check to enable 64-bit flags for compiler/linker if test "$do64bit" = "yes" ; then if test "$GCC" = "yes" ; then hpux_arch=`${CC} -dumpmachine` case $hpux_arch in hppa64*) # 64-bit gcc in use. Fix flags for GNU ld. do64bit_ok=yes SHLIB_LD="${CC} -shared" SHLIB_LD_LIBS='${LIBS}' CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} ;; *) AC_MSG_WARN([64bit mode not supported with GCC on $system]) ;; esac else do64bit_ok=yes CFLAGS="$CFLAGS +DD64" LDFLAGS_ARCH="+DD64" fi fi ;; HP-UX-*.08.*|HP-UX-*.09.*|HP-UX-*.10.*) SHLIB_SUFFIX=".sl" AC_CHECK_LIB(dld, shl_load, tcl_ok=yes, tcl_ok=no) if test "$tcl_ok" = yes; then SHLIB_CFLAGS="+z" SHLIB_LD="ld -b" SHLIB_LD_LIBS="" DL_OBJS="tclLoadShl.o" DL_LIBS="-ldld" LDFLAGS="$LDFLAGS -Wl,-E" CC_SEARCH_FLAGS='-Wl,+s,+b,${LIB_RUNTIME_DIR}:.' LD_SEARCH_FLAGS='+s +b ${LIB_RUNTIME_DIR}:.' LD_LIBRARY_PATH_VAR="SHLIB_PATH" fi ;; IRIX-5.*) SHLIB_CFLAGS="" SHLIB_LD="ld -shared -rdata_shared" SHLIB_LD_LIBS='${LIBS}' SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" DL_LIBS="" CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS='-rpath ${LIB_RUNTIME_DIR}' ;; IRIX-6.*) SHLIB_CFLAGS="" SHLIB_LD="ld -n32 -shared -rdata_shared" SHLIB_LD_LIBS='${LIBS}' SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" DL_LIBS="" CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS='-rpath ${LIB_RUNTIME_DIR}' if test "$GCC" = "yes" ; then CFLAGS="$CFLAGS -mabi=n32" LDFLAGS="$LDFLAGS -mabi=n32" else case $system in IRIX-6.3) # Use to build 6.2 compatible binaries on 6.3. CFLAGS="$CFLAGS -n32 -D_OLD_TERMIOS" ;; *) CFLAGS="$CFLAGS -n32" ;; esac LDFLAGS="$LDFLAGS -n32" fi ;; IRIX64-6.*) SHLIB_CFLAGS="" SHLIB_LD="ld -n32 -shared -rdata_shared" SHLIB_LD_LIBS='${LIBS}' SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" DL_LIBS="" CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS='-rpath ${LIB_RUNTIME_DIR}' # Check to enable 64-bit flags for compiler/linker if test "$do64bit" = "yes" ; then if test "$GCC" = "yes" ; then AC_MSG_WARN([64bit mode not supported by gcc]) else do64bit_ok=yes SHLIB_LD="ld -64 -shared -rdata_shared" CFLAGS="$CFLAGS -64" LDFLAGS_ARCH="-64" fi fi ;; Linux*) SHLIB_CFLAGS="-fPIC" SHLIB_LD_LIBS='${LIBS}' SHLIB_SUFFIX=".so" CFLAGS_OPTIMIZE="-O2 -fomit-frame-pointer" # egcs-2.91.66 on Redhat Linux 6.0 generates lots of warnings # when you inline the string and math operations. Turn this off to # get rid of the warnings. #CFLAGS_OPTIMIZE="${CFLAGS_OPTIMIZE} -D__NO_STRING_INLINES -D__NO_MATH_INLINES" SHLIB_LD="${CC} -shared" DL_OBJS="tclLoadDl.o" DL_LIBS="-ldl" LDFLAGS="$LDFLAGS -Wl,--export-dynamic" CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} if test "`uname -m`" = "alpha" ; then CFLAGS="$CFLAGS -mieee" fi # The combo of gcc + glibc has a bug related # to inlining of functions like strtod(). The # -fno-builtin flag should address this problem # but it does not work. The -fno-inline flag # is kind of overkill but it works. # Disable inlining only when one of the # files in compat/*.c is being linked in. if test x"${USE_COMPAT}" != x ; then CFLAGS="$CFLAGS -fno-inline" fi ;; GNU*) SHLIB_CFLAGS="-fPIC" SHLIB_LD_LIBS='${LIBS}' SHLIB_SUFFIX=".so" SHLIB_LD="${CC} -shared" DL_OBJS="" DL_LIBS="-ldl" LDFLAGS="$LDFLAGS -Wl,--export-dynamic" CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" if test "`uname -m`" = "alpha" ; then CFLAGS="$CFLAGS -mieee" fi ;; Lynx*) SHLIB_CFLAGS="-fPIC" SHLIB_LD_LIBS='${LIBS}' SHLIB_SUFFIX=".so" CFLAGS_OPTIMIZE=-02 SHLIB_LD="${CC} -shared " DL_OBJS="tclLoadDl.o" DL_LIBS="-mshared -ldl" LD_FLAGS="-Wl,--export-dynamic" CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' ;; MP-RAS-02*) SHLIB_CFLAGS="-K PIC" SHLIB_LD="cc -G" SHLIB_LD_LIBS="" SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" DL_LIBS="-ldl" CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" ;; MP-RAS-*) SHLIB_CFLAGS="-K PIC" SHLIB_LD="cc -G" SHLIB_LD_LIBS="" SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" DL_LIBS="-ldl" LDFLAGS="$LDFLAGS -Wl,-Bexport" CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" ;; NetBSD-*|FreeBSD-[[1-2]].*) # NetBSD/SPARC needs -fPIC, -fpic will not do. SHLIB_CFLAGS="-fPIC" SHLIB_LD="ld -Bshareable -x" SHLIB_LD_LIBS="" SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" DL_LIBS="" CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS='-rpath ${LIB_RUNTIME_DIR}' AC_CACHE_CHECK([for ELF], tcl_cv_ld_elf, [ AC_EGREP_CPP(yes, [ #ifdef __ELF__ yes #endif ], tcl_cv_ld_elf=yes, tcl_cv_ld_elf=no)]) if test $tcl_cv_ld_elf = yes; then SHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.so' else SHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.so.1.0' fi # Ancient FreeBSD doesn't handle version numbers with dots. UNSHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.a' TCL_LIB_VERSIONS_OK=nodots ;; OpenBSD-*) # OpenBSD/SPARC[64] needs -fPIC, -fpic will not do. case `machine` in sparc|sparc64) SHLIB_CFLAGS="-fPIC";; *) SHLIB_CFLAGS="-fpic";; esac SHLIB_LD="${CC} -shared ${SHLIB_CFLAGS}" SHLIB_LD_LIBS='${LIBS}' SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" DL_LIBS="" CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} SHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.so.1.0' AC_CACHE_CHECK([for ELF], tcl_cv_ld_elf, [ AC_EGREP_CPP(yes, [ #ifdef __ELF__ yes #endif ], tcl_cv_ld_elf=yes, tcl_cv_ld_elf=no)]) if test $tcl_cv_ld_elf = yes; then LDFLAGS=-Wl,-export-dynamic else LDFLAGS="" fi # OpenBSD doesn't do version numbers with dots. UNSHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.a' TCL_LIB_VERSIONS_OK=nodots ;; FreeBSD-*) # FreeBSD 3.* and greater have ELF. SHLIB_CFLAGS="-fPIC" SHLIB_LD="ld -Bshareable -x" SHLIB_LD_LIBS='${LIBS}' SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" DL_LIBS="" LDFLAGS="$LDFLAGS -export-dynamic" CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS='-rpath ${LIB_RUNTIME_DIR}' if test "${TCL_THREADS}" = "1" ; then # The -pthread needs to go in the CFLAGS, not LIBS LIBS=`echo $LIBS | sed s/-pthread//` CFLAGS="$CFLAGS -pthread" LDFLAGS="$LDFLAGS -pthread" fi case $system in FreeBSD-3.*) # FreeBSD-3 doesn't handle version numbers with dots. UNSHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.a' SHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.so' TCL_LIB_VERSIONS_OK=nodots ;; esac ;; Darwin-*) CFLAGS_OPTIMIZE="-Os" SHLIB_CFLAGS="-fno-common" if test $do64bit = yes; then do64bit_ok=yes CFLAGS="$CFLAGS -arch ppc64 -mpowerpc64 -mcpu=G5" fi # TEA specific: use LDFLAGS_DEFAULT instead of LDFLAGS here: SHLIB_LD='${CC} -dynamiclib ${CFLAGS} ${LDFLAGS_DEFAULT}' AC_CACHE_CHECK([if ld accepts -single_module flag], tcl_cv_ld_single_module, [ hold_ldflags=$LDFLAGS LDFLAGS="$LDFLAGS -dynamiclib -Wl,-single_module" AC_TRY_LINK(, [int i;], tcl_cv_ld_single_module=yes, tcl_cv_ld_single_module=no) LDFLAGS=$hold_ldflags]) if test $tcl_cv_ld_single_module = yes; then SHLIB_LD="${SHLIB_LD} -Wl,-single_module" fi SHLIB_LD_LIBS='${LIBS}' SHLIB_SUFFIX=".dylib" DL_OBJS="tclLoadDyld.o" DL_LIBS="" # Don't use -prebind when building for Mac OS X 10.4 or later only: test -z "${MACOSX_DEPLOYMENT_TARGET}" || \ test "`echo "${MACOSX_DEPLOYMENT_TARGET}" | awk -F. '{print [$]2}'`" -lt 4 && \ LDFLAGS="$LDFLAGS -prebind" LDFLAGS="$LDFLAGS -headerpad_max_install_names" AC_CACHE_CHECK([if ld accepts -search_paths_first flag], tcl_cv_ld_search_paths_first, [ hold_ldflags=$LDFLAGS LDFLAGS="$LDFLAGS -Wl,-search_paths_first" AC_TRY_LINK(, [int i;], tcl_cv_ld_search_paths_first=yes, tcl_cv_ld_search_paths_first=no) LDFLAGS=$hold_ldflags]) if test $tcl_cv_ld_search_paths_first = yes; then LDFLAGS="$LDFLAGS -Wl,-search_paths_first" fi CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" LD_LIBRARY_PATH_VAR="DYLD_LIBRARY_PATH" # TEA specific: for Tk extensions, remove -arch ppc64 from CFLAGS # for fat builds, as neither TkAqua nor TkX11 can be built for 64bit # at present (no 64bit GUI libraries). test $do64bit_ok = no && test -n "${TK_BIN_DIR}" && \ CFLAGS="`echo "$CFLAGS" | sed -e 's/-arch ppc64/-arch ppc/g'`" ;; NEXTSTEP-*) SHLIB_CFLAGS="" SHLIB_LD="cc -nostdlib -r" SHLIB_LD_LIBS="" SHLIB_SUFFIX=".so" DL_OBJS="tclLoadNext.o" DL_LIBS="" CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" ;; OS/390-*) CFLAGS_OPTIMIZE="" # Optimizer is buggy AC_DEFINE(_OE_SOCKETS, 1, # needed in sys/socket.h [Should OS/390 do the right thing with sockets?]) ;; OSF1-1.0|OSF1-1.1|OSF1-1.2) # OSF/1 1.[012] from OSF, and derivatives, including Paragon OSF/1 SHLIB_CFLAGS="" # Hack: make package name same as library name SHLIB_LD='ld -R -export $@:' SHLIB_LD_LIBS="" SHLIB_SUFFIX=".so" DL_OBJS="tclLoadOSF.o" DL_LIBS="" CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" ;; OSF1-1.*) # OSF/1 1.3 from OSF using ELF, and derivatives, including AD2 SHLIB_CFLAGS="-fPIC" if test "$SHARED_BUILD" = "1" ; then SHLIB_LD="ld -shared" else SHLIB_LD="ld -non_shared" fi SHLIB_LD_LIBS="" SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" DL_LIBS="" CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" ;; OSF1-V*) # Digital OSF/1 SHLIB_CFLAGS="" if test "$SHARED_BUILD" = "1" ; then SHLIB_LD='ld -shared -expect_unresolved "*"' else SHLIB_LD='ld -non_shared -expect_unresolved "*"' fi SHLIB_LD_LIBS="" SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" DL_LIBS="" CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS='-rpath ${LIB_RUNTIME_DIR}' if test "$GCC" = "yes" ; then CFLAGS="$CFLAGS -mieee" else CFLAGS="$CFLAGS -DHAVE_TZSET -std1 -ieee" fi # see pthread_intro(3) for pthread support on osf1, k.furukawa if test "${TCL_THREADS}" = "1" ; then CFLAGS="$CFLAGS -DHAVE_PTHREAD_ATTR_SETSTACKSIZE" CFLAGS="$CFLAGS -DTCL_THREAD_STACK_MIN=PTHREAD_STACK_MIN*64" LIBS=`echo $LIBS | sed s/-lpthreads//` if test "$GCC" = "yes" ; then LIBS="$LIBS -lpthread -lmach -lexc" else CFLAGS="$CFLAGS -pthread" LDFLAGS="$LDFLAGS -pthread" fi fi ;; QNX-6*) # QNX RTP # This may work for all QNX, but it was only reported for v6. SHLIB_CFLAGS="-fPIC" SHLIB_LD="ld -Bshareable -x" SHLIB_LD_LIBS="" SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" # dlopen is in -lc on QNX DL_LIBS="" CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" ;; SCO_SV-3.2*) # Note, dlopen is available only on SCO 3.2.5 and greater. However, # this test works, since "uname -s" was non-standard in 3.2.4 and # below. if test "$GCC" = "yes" ; then SHLIB_CFLAGS="-fPIC -melf" LDFLAGS="$LDFLAGS -melf -Wl,-Bexport" else SHLIB_CFLAGS="-Kpic -belf" LDFLAGS="$LDFLAGS -belf -Wl,-Bexport" fi SHLIB_LD="ld -G" SHLIB_LD_LIBS="" SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" DL_LIBS="" CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" ;; SINIX*5.4*) SHLIB_CFLAGS="-K PIC" SHLIB_LD="cc -G" SHLIB_LD_LIBS="" SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" DL_LIBS="-ldl" CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" ;; SunOS-4*) SHLIB_CFLAGS="-PIC" SHLIB_LD="ld" SHLIB_LD_LIBS="" SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" DL_LIBS="-ldl" CC_SEARCH_FLAGS='-L${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} # SunOS can't handle version numbers with dots in them in library # specs, like -ltcl7.5, so use -ltcl75 instead. Also, it # requires an extra version number at the end of .so file names. # So, the library has to have a name like libtcl75.so.1.0 SHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.so.1.0' UNSHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.a' TCL_LIB_VERSIONS_OK=nodots ;; SunOS-5.[[0-6]]) # Careful to not let 5.10+ fall into this case # Note: If _REENTRANT isn't defined, then Solaris # won't define thread-safe library routines. AC_DEFINE(_REENTRANT, 1, [Do we want the reentrant OS API?]) AC_DEFINE(_POSIX_PTHREAD_SEMANTICS, 1, [Do we really want to follow the standard? Yes we do!]) SHLIB_CFLAGS="-KPIC" # Note: need the LIBS below, otherwise Tk won't find Tcl's # symbols when dynamically loaded into tclsh. SHLIB_LD_LIBS='${LIBS}' SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" DL_LIBS="-ldl" if test "$GCC" = "yes" ; then SHLIB_LD="$CC -shared" CC_SEARCH_FLAGS='-Wl,-R,${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} else SHLIB_LD="/usr/ccs/bin/ld -G -z text" CC_SEARCH_FLAGS='-R ${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} fi ;; SunOS-5*) # Note: If _REENTRANT isn't defined, then Solaris # won't define thread-safe library routines. AC_DEFINE(_REENTRANT, 1, [Do we want the reentrant OS API?]) AC_DEFINE(_POSIX_PTHREAD_SEMANTICS, 1, [Do we really want to follow the standard? Yes we do!]) SHLIB_CFLAGS="-KPIC" # Check to enable 64-bit flags for compiler/linker if test "$do64bit" = "yes" ; then arch=`isainfo` if test "$arch" = "sparcv9 sparc" ; then if test "$GCC" = "yes" ; then if test "`gcc -dumpversion | awk -F. '{print [$]1}'`" -lt "3" ; then AC_MSG_WARN([64bit mode not supported with GCC < 3.2 on $system]) else do64bit_ok=yes CFLAGS="$CFLAGS -m64 -mcpu=v9" LDFLAGS="$LDFLAGS -m64 -mcpu=v9" SHLIB_CFLAGS="-fPIC" fi else do64bit_ok=yes if test "$do64bitVIS" = "yes" ; then CFLAGS="$CFLAGS -xarch=v9a" LDFLAGS_ARCH="-xarch=v9a" else CFLAGS="$CFLAGS -xarch=v9" LDFLAGS_ARCH="-xarch=v9" fi # Solaris 64 uses this as well #LD_LIBRARY_PATH_VAR="LD_LIBRARY_PATH_64" fi elif test "$arch" = "amd64 i386" ; then if test "$GCC" = "yes" ; then AC_MSG_WARN([64bit mode not supported with GCC on $system]) else do64bit_ok=yes CFLAGS="$CFLAGS -xarch=amd64" LDFLAGS="$LDFLAGS -xarch=amd64" fi else AC_MSG_WARN([64bit mode not supported for $arch]) fi fi # Note: need the LIBS below, otherwise Tk won't find Tcl's # symbols when dynamically loaded into tclsh. SHLIB_LD_LIBS='${LIBS}' SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" DL_LIBS="-ldl" if test "$GCC" = "yes" ; then SHLIB_LD="$CC -shared" CC_SEARCH_FLAGS='-Wl,-R,${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} if test "$do64bit_ok" = "yes" ; then # We need to specify -static-libgcc or we need to # add the path to the sparv9 libgcc. # JH: static-libgcc is necessary for core Tcl, but may # not be necessary for extensions. SHLIB_LD="$SHLIB_LD -m64 -mcpu=v9 -static-libgcc" # for finding sparcv9 libgcc, get the regular libgcc # path, remove so name and append 'sparcv9' #v9gcclibdir="`gcc -print-file-name=libgcc_s.so` | ..." #CC_SEARCH_FLAGS="${CC_SEARCH_FLAGS},-R,$v9gcclibdir" fi else SHLIB_LD="/usr/ccs/bin/ld -G -z text" CC_SEARCH_FLAGS='-Wl,-R,${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS='-R ${LIB_RUNTIME_DIR}' fi ;; UNIX_SV* | UnixWare-5*) SHLIB_CFLAGS="-KPIC" SHLIB_LD="cc -G" SHLIB_LD_LIBS="" SHLIB_SUFFIX=".so" DL_OBJS="tclLoadDl.o" DL_LIBS="-ldl" # Some UNIX_SV* systems (unixware 1.1.2 for example) have linkers # that don't grok the -Bexport option. Test that it does. AC_CACHE_CHECK([for ld accepts -Bexport flag], tcl_cv_ld_Bexport, [ hold_ldflags=$LDFLAGS LDFLAGS="$LDFLAGS -Wl,-Bexport" AC_TRY_LINK(, [int i;], tcl_cv_ld_Bexport=yes, tcl_cv_ld_Bexport=no) LDFLAGS=$hold_ldflags]) if test $tcl_cv_ld_Bexport = yes; then LDFLAGS="$LDFLAGS -Wl,-Bexport" fi CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" ;; esac if test "$do64bit" = "yes" -a "$do64bit_ok" = "no" ; then AC_MSG_WARN([64bit support being disabled -- don't know magic for this platform]) fi # Step 4: disable dynamic loading if requested via a command-line switch. AC_ARG_ENABLE(load, AC_HELP_STRING([--disable-load], [disallow dynamic loading and "load" command (default: enabled)]), [tcl_ok=$enableval], [tcl_ok=yes]) if test "$tcl_ok" = "no"; then DL_OBJS="" fi if test "x$DL_OBJS" != "x" ; then BUILD_DLTEST="\$(DLTEST_TARGETS)" else echo "Can't figure out how to do dynamic loading or shared libraries" echo "on this system." SHLIB_CFLAGS="" SHLIB_LD="" SHLIB_SUFFIX="" DL_OBJS="tclLoadNone.o" DL_LIBS="" LDFLAGS="$LDFLAGS_ORIG" CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" BUILD_DLTEST="" fi LDFLAGS="$LDFLAGS $LDFLAGS_ARCH" # If we're running gcc, then change the C flags for compiling shared # libraries to the right flags for gcc, instead of those for the # standard manufacturer compiler. if test "$DL_OBJS" != "tclLoadNone.o" ; then if test "$GCC" = "yes" ; then case $system in AIX-*) ;; BSD/OS*) ;; IRIX*) ;; NetBSD-*|FreeBSD-*) ;; Darwin-*) ;; SCO_SV-3.2*) ;; windows) ;; *) SHLIB_CFLAGS="-fPIC" ;; esac fi fi if test "$SHARED_LIB_SUFFIX" = "" ; then SHARED_LIB_SUFFIX='${PACKAGE_VERSION}${SHLIB_SUFFIX}' fi if test "$UNSHARED_LIB_SUFFIX" = "" ; then UNSHARED_LIB_SUFFIX='${PACKAGE_VERSION}.a' fi AC_SUBST(DL_LIBS) AC_SUBST(CFLAGS_DEBUG) AC_SUBST(CFLAGS_OPTIMIZE) AC_SUBST(CFLAGS_WARNING) AC_SUBST(STLIB_LD) AC_SUBST(SHLIB_LD) AC_SUBST(SHLIB_LD_LIBS) AC_SUBST(SHLIB_CFLAGS) AC_SUBST(LD_LIBRARY_PATH_VAR) # These must be called after we do the basic CFLAGS checks and # verify any possible 64-bit or similar switches are necessary TEA_TCL_EARLY_FLAGS TEA_TCL_64BIT_FLAGS ]) #-------------------------------------------------------------------- # TEA_SERIAL_PORT # # Determine which interface to use to talk to the serial port. # Note that #include lines must begin in leftmost column for # some compilers to recognize them as preprocessor directives, # and some build environments have stdin not pointing at a # pseudo-terminal (usually /dev/null instead.) # # Arguments: # none # # Results: # # Defines only one of the following vars: # HAVE_SYS_MODEM_H # USE_TERMIOS # USE_TERMIO # USE_SGTTY # #-------------------------------------------------------------------- AC_DEFUN(TEA_SERIAL_PORT, [ AC_CHECK_HEADERS(sys/modem.h) AC_CACHE_CHECK([termios vs. termio vs. sgtty], tcl_cv_api_serial, [ AC_TRY_RUN([ #include <termios.h> int main() { struct termios t; if (tcgetattr(0, &t) == 0) { cfsetospeed(&t, 0); t.c_cflag |= PARENB | PARODD | CSIZE | CSTOPB; return 0; } return 1; }], tcl_cv_api_serial=termios, tcl_cv_api_serial=no, tcl_cv_api_serial=no) if test $tcl_cv_api_serial = no ; then AC_TRY_RUN([ #include <termio.h> int main() { struct termio t; if (ioctl(0, TCGETA, &t) == 0) { t.c_cflag |= CBAUD | PARENB | PARODD | CSIZE | CSTOPB; return 0; } return 1; }], tcl_cv_api_serial=termio, tcl_cv_api_serial=no, tcl_cv_api_serial=no) fi if test $tcl_cv_api_serial = no ; then AC_TRY_RUN([ #include <sgtty.h> int main() { struct sgttyb t; if (ioctl(0, TIOCGETP, &t) == 0) { t.sg_ospeed = 0; t.sg_flags |= ODDP | EVENP | RAW; return 0; } return 1; }], tcl_cv_api_serial=sgtty, tcl_cv_api_serial=no, tcl_cv_api_serial=no) fi if test $tcl_cv_api_serial = no ; then AC_TRY_RUN([ #include <termios.h> #include <errno.h> int main() { struct termios t; if (tcgetattr(0, &t) == 0 || errno == ENOTTY || errno == ENXIO || errno == EINVAL) { cfsetospeed(&t, 0); t.c_cflag |= PARENB | PARODD | CSIZE | CSTOPB; return 0; } return 1; }], tcl_cv_api_serial=termios, tcl_cv_api_serial=no, tcl_cv_api_serial=no) fi if test $tcl_cv_api_serial = no; then AC_TRY_RUN([ #include <termio.h> #include <errno.h> int main() { struct termio t; if (ioctl(0, TCGETA, &t) == 0 || errno == ENOTTY || errno == ENXIO || errno == EINVAL) { t.c_cflag |= CBAUD | PARENB | PARODD | CSIZE | CSTOPB; return 0; } return 1; }], tcl_cv_api_serial=termio, tcl_cv_api_serial=no, tcl_cv_api_serial=no) fi if test $tcl_cv_api_serial = no; then AC_TRY_RUN([ #include <sgtty.h> #include <errno.h> int main() { struct sgttyb t; if (ioctl(0, TIOCGETP, &t) == 0 || errno == ENOTTY || errno == ENXIO || errno == EINVAL) { t.sg_ospeed = 0; t.sg_flags |= ODDP | EVENP | RAW; return 0; } return 1; }], tcl_cv_api_serial=sgtty, tcl_cv_api_serial=none, tcl_cv_api_serial=none) fi]) case $tcl_cv_api_serial in termios) AC_DEFINE(USE_TERMIOS, 1, [Use the termios API for serial lines]);; termio) AC_DEFINE(USE_TERMIO, 1, [Use the termio API for serial lines]);; sgtty) AC_DEFINE(USE_SGTTY, 1, [Use the sgtty API for serial lines]);; esac ]) #-------------------------------------------------------------------- # TEA_MISSING_POSIX_HEADERS # # Supply substitutes for missing POSIX header files. Special # notes: # - stdlib.h doesn't define strtol, strtoul, or # strtod insome versions of SunOS # - some versions of string.h don't declare procedures such # as strstr # # Arguments: # none # # Results: # # Defines some of the following vars: # NO_DIRENT_H # NO_ERRNO_H # NO_VALUES_H # HAVE_LIMITS_H or NO_LIMITS_H # NO_STDLIB_H # NO_STRING_H # NO_SYS_WAIT_H # NO_DLFCN_H # HAVE_SYS_PARAM_H # # HAVE_STRING_H ? # # tkUnixPort.h checks for HAVE_LIMITS_H, so do both HAVE and # CHECK on limits.h #-------------------------------------------------------------------- AC_DEFUN(TEA_MISSING_POSIX_HEADERS, [ AC_CACHE_CHECK([dirent.h], tcl_cv_dirent_h, AC_TRY_LINK([#include <sys/types.h> #include <dirent.h>], [ #ifndef _POSIX_SOURCE # ifdef __Lynx__ /* * Generate compilation error to make the test fail: Lynx headers * are only valid if really in the POSIX environment. */ missing_procedure(); # endif #endif DIR *d; struct dirent *entryPtr; char *p; d = opendir("foobar"); entryPtr = readdir(d); p = entryPtr->d_name; closedir(d); ], tcl_cv_dirent_h=yes, tcl_cv_dirent_h=no)) if test $tcl_cv_dirent_h = no; then AC_DEFINE(NO_DIRENT_H, 1, [Do we have <dirent.h>?]) fi AC_CHECK_HEADER(errno.h, , [AC_DEFINE(NO_ERRNO_H, 1, [Do we have <errno.h>?])]) AC_CHECK_HEADER(float.h, , [AC_DEFINE(NO_FLOAT_H, 1, [Do we have <float.h>?])]) AC_CHECK_HEADER(values.h, , [AC_DEFINE(NO_VALUES_H, 1, [Do we have <values.h>?])]) AC_CHECK_HEADER(limits.h, [AC_DEFINE(HAVE_LIMITS_H, 1, [Do we have <limits.h>?])], [AC_DEFINE(NO_LIMITS_H, 1, [Do we have <limits.h>?])]) AC_CHECK_HEADER(stdlib.h, tcl_ok=1, tcl_ok=0) AC_EGREP_HEADER(strtol, stdlib.h, , tcl_ok=0) AC_EGREP_HEADER(strtoul, stdlib.h, , tcl_ok=0) AC_EGREP_HEADER(strtod, stdlib.h, , tcl_ok=0) if test $tcl_ok = 0; then AC_DEFINE(NO_STDLIB_H, 1, [Do we have <stdlib.h>?]) fi AC_CHECK_HEADER(string.h, tcl_ok=1, tcl_ok=0) AC_EGREP_HEADER(strstr, string.h, , tcl_ok=0) AC_EGREP_HEADER(strerror, string.h, , tcl_ok=0) # See also memmove check below for a place where NO_STRING_H can be # set and why. if test $tcl_ok = 0; then AC_DEFINE(NO_STRING_H, 1, [Do we have <string.h>?]) fi AC_CHECK_HEADER(sys/wait.h, , [AC_DEFINE(NO_SYS_WAIT_H, 1, [Do we have <sys/wait.h>?])]) AC_CHECK_HEADER(dlfcn.h, , [AC_DEFINE(NO_DLFCN_H, 1, [Do we have <dlfcn.h>?])]) # OS/390 lacks sys/param.h (and doesn't need it, by chance). AC_HAVE_HEADERS(sys/param.h) ]) #-------------------------------------------------------------------- # TEA_PATH_X # # Locate the X11 header files and the X11 library archive. Try # the ac_path_x macro first, but if it doesn't find the X stuff # (e.g. because there's no xmkmf program) then check through # a list of possible directories. Under some conditions the # autoconf macro will return an include directory that contains # no include files, so double-check its result just to be safe. # # This should be called after TEA_CONFIG_CFLAGS as setting the # LIBS line can confuse some configure macro magic. # # Arguments: # none # # Results: # # Sets the following vars: # XINCLUDES # XLIBSW # PKG_LIBS (appends to) # #-------------------------------------------------------------------- AC_DEFUN(TEA_PATH_X, [ if test "${TEA_WINDOWINGSYSTEM}" = "x11" ; then TEA_PATH_UNIX_X fi ]) AC_DEFUN(TEA_PATH_UNIX_X, [ AC_PATH_X not_really_there="" if test "$no_x" = ""; then if test "$x_includes" = ""; then AC_TRY_CPP([#include <X11/XIntrinsic.h>], , not_really_there="yes") else if test ! -r $x_includes/X11/Intrinsic.h; then not_really_there="yes" fi fi fi if test "$no_x" = "yes" -o "$not_really_there" = "yes"; then AC_MSG_CHECKING([for X11 header files]) found_xincludes="no" AC_TRY_CPP([#include <X11/Intrinsic.h>], found_xincludes="yes", found_xincludes="no") if test "$found_xincludes" = "no"; then dirs="/usr/unsupported/include /usr/local/include /usr/X386/include /usr/X11R6/include /usr/X11R5/include /usr/include/X11R5 /usr/include/X11R4 /usr/openwin/include /usr/X11/include /usr/sww/include" for i in $dirs ; do if test -r $i/X11/Intrinsic.h; then AC_MSG_RESULT([$i]) XINCLUDES=" -I$i" found_xincludes="yes" break fi done fi else if test "$x_includes" != ""; then XINCLUDES="-I$x_includes" found_xincludes="yes" fi fi if test found_xincludes = "no"; then AC_MSG_RESULT([couldn't find any!]) fi if test "$no_x" = yes; then AC_MSG_CHECKING([for X11 libraries]) XLIBSW=nope dirs="/usr/unsupported/lib /usr/local/lib /usr/X386/lib /usr/X11R6/lib /usr/X11R5/lib /usr/lib/X11R5 /usr/lib/X11R4 /usr/openwin/lib /usr/X11/lib /usr/sww/X11/lib" for i in $dirs ; do if test -r $i/libX11.a -o -r $i/libX11.so -o -r $i/libX11.sl; then AC_MSG_RESULT([$i]) XLIBSW="-L$i -lX11" x_libraries="$i" break fi done else if test "$x_libraries" = ""; then XLIBSW=-lX11 else XLIBSW="-L$x_libraries -lX11" fi fi if test "$XLIBSW" = nope ; then AC_CHECK_LIB(Xwindow, XCreateWindow, XLIBSW=-lXwindow) fi if test "$XLIBSW" = nope ; then AC_MSG_RESULT([could not find any! Using -lX11.]) XLIBSW=-lX11 fi if test x"${XLIBSW}" != x ; then PKG_LIBS="${PKG_LIBS} ${XLIBSW}" fi ]) #-------------------------------------------------------------------- # TEA_BLOCKING_STYLE # # The statements below check for systems where POSIX-style # non-blocking I/O (O_NONBLOCK) doesn't work or is unimplemented. # On these systems (mostly older ones), use the old BSD-style # FIONBIO approach instead. # # Arguments: # none # # Results: # # Defines some of the following vars: # HAVE_SYS_IOCTL_H # HAVE_SYS_FILIO_H # USE_FIONBIO # O_NONBLOCK # #-------------------------------------------------------------------- AC_DEFUN(TEA_BLOCKING_STYLE, [ AC_CHECK_HEADERS(sys/ioctl.h) AC_CHECK_HEADERS(sys/filio.h) TEA_CONFIG_SYSTEM AC_MSG_CHECKING([FIONBIO vs. O_NONBLOCK for nonblocking I/O]) case $system in # There used to be code here to use FIONBIO under AIX. However, it # was reported that FIONBIO doesn't work under AIX 3.2.5. Since # using O_NONBLOCK seems fine under AIX 4.*, I removed the FIONBIO # code (JO, 5/31/97). OSF*) AC_DEFINE(USE_FIONBIO, 1, [Should we use FIONBIO?]) AC_MSG_RESULT([FIONBIO]) ;; SunOS-4*) AC_DEFINE(USE_FIONBIO, 1, [Should we use FIONBIO?]) AC_MSG_RESULT([FIONBIO]) ;; *) AC_MSG_RESULT([O_NONBLOCK]) ;; esac ]) #-------------------------------------------------------------------- # TEA_TIME_HANLDER # # Checks how the system deals with time.h, what time structures # are used on the system, and what fields the structures have. # # Arguments: # none # # Results: # # Defines some of the following vars: # USE_DELTA_FOR_TZ # HAVE_TM_GMTOFF # HAVE_TM_TZADJ # HAVE_TIMEZONE_VAR # #-------------------------------------------------------------------- AC_DEFUN(TEA_TIME_HANDLER, [ AC_CHECK_HEADERS(sys/time.h) AC_HEADER_TIME AC_STRUCT_TIMEZONE AC_CHECK_FUNCS(gmtime_r localtime_r) AC_CACHE_CHECK([tm_tzadj in struct tm], tcl_cv_member_tm_tzadj, AC_TRY_COMPILE([#include <time.h>], [struct tm tm; tm.tm_tzadj;], tcl_cv_member_tm_tzadj=yes, tcl_cv_member_tm_tzadj=no)) if test $tcl_cv_member_tm_tzadj = yes ; then AC_DEFINE(HAVE_TM_TZADJ, 1, [Should we use the tm_tzadj field of struct tm?]) fi AC_CACHE_CHECK([tm_gmtoff in struct tm], tcl_cv_member_tm_gmtoff, AC_TRY_COMPILE([#include <time.h>], [struct tm tm; tm.tm_gmtoff;], tcl_cv_member_tm_gmtoff=yes, tcl_cv_member_tm_gmtoff=no)) if test $tcl_cv_member_tm_gmtoff = yes ; then AC_DEFINE(HAVE_TM_GMTOFF, 1, [Should we use the tm_gmtoff field of struct tm?]) fi # # Its important to include time.h in this check, as some systems # (like convex) have timezone functions, etc. # AC_CACHE_CHECK([long timezone variable], tcl_cv_timezone_long, AC_TRY_COMPILE([#include <time.h>], [extern long timezone; timezone += 1; exit (0);], tcl_cv_timezone_long=yes, tcl_cv_timezone_long=no)) if test $tcl_cv_timezone_long = yes ; then AC_DEFINE(HAVE_TIMEZONE_VAR, 1, [Should we use the global timezone variable?]) else # # On some systems (eg IRIX 6.2), timezone is a time_t and not a long. # AC_CACHE_CHECK([time_t timezone variable], tcl_cv_timezone_time, AC_TRY_COMPILE([#include <time.h>], [extern time_t timezone; timezone += 1; exit (0);], tcl_cv_timezone_time=yes, tcl_cv_timezone_time=no)) if test $tcl_cv_timezone_time = yes ; then AC_DEFINE(HAVE_TIMEZONE_VAR, 1, [Should we use the global timezone variable?]) fi fi ]) #-------------------------------------------------------------------- # TEA_BUGGY_STRTOD # # Under Solaris 2.4, strtod returns the wrong value for the # terminating character under some conditions. Check for this # and if the problem exists use a substitute procedure # "fixstrtod" (provided by Tcl) that corrects the error. # Also, on Compaq's Tru64 Unix 5.0, # strtod(" ") returns 0.0 instead of a failure to convert. # # Arguments: # none # # Results: # # Might defines some of the following vars: # strtod (=fixstrtod) # #-------------------------------------------------------------------- AC_DEFUN(TEA_BUGGY_STRTOD, [ AC_CHECK_FUNC(strtod, tcl_strtod=1, tcl_strtod=0) if test "$tcl_strtod" = 1; then AC_CACHE_CHECK([for Solaris2.4/Tru64 strtod bugs], tcl_cv_strtod_buggy,[ AC_TRY_RUN([ extern double strtod(); int main() { char *infString="Inf", *nanString="NaN", *spaceString=" "; char *term; double value; value = strtod(infString, &term); if ((term != infString) && (term[-1] == 0)) { exit(1); } value = strtod(nanString, &term); if ((term != nanString) && (term[-1] == 0)) { exit(1); } value = strtod(spaceString, &term); if (term == (spaceString+1)) { exit(1); } exit(0); }], tcl_cv_strtod_buggy=ok, tcl_cv_strtod_buggy=buggy, tcl_cv_strtod_buggy=buggy)]) if test "$tcl_cv_strtod_buggy" = buggy; then AC_LIBOBJ([fixstrtod]) USE_COMPAT=1 AC_DEFINE(strtod, fixstrtod, [Do we want to use the strtod() in compat?]) fi fi ]) #-------------------------------------------------------------------- # TEA_TCL_LINK_LIBS # # Search for the libraries needed to link the Tcl shell. # Things like the math library (-lm) and socket stuff (-lsocket vs. # -lnsl) are dealt with here. # # Arguments: # Requires the following vars to be set in the Makefile: # DL_LIBS # LIBS # MATH_LIBS # # Results: # # Subst's the following var: # TCL_LIBS # MATH_LIBS # # Might append to the following vars: # LIBS # # Might define the following vars: # HAVE_NET_ERRNO_H # #-------------------------------------------------------------------- AC_DEFUN(TEA_TCL_LINK_LIBS, [ #-------------------------------------------------------------------- # On a few very rare systems, all of the libm.a stuff is # already in libc.a. Set compiler flags accordingly. # Also, Linux requires the "ieee" library for math to work # right (and it must appear before "-lm"). #-------------------------------------------------------------------- AC_CHECK_FUNC(sin, MATH_LIBS="", MATH_LIBS="-lm") AC_CHECK_LIB(ieee, main, [MATH_LIBS="-lieee $MATH_LIBS"]) #-------------------------------------------------------------------- # Interactive UNIX requires -linet instead of -lsocket, plus it # needs net/errno.h to define the socket-related error codes. #-------------------------------------------------------------------- AC_CHECK_LIB(inet, main, [LIBS="$LIBS -linet"]) AC_CHECK_HEADER(net/errno.h, [ AC_DEFINE(HAVE_NET_ERRNO_H, 1, [Do we have <net/errno.h>?])]) #-------------------------------------------------------------------- # Check for the existence of the -lsocket and -lnsl libraries. # The order here is important, so that they end up in the right # order in the command line generated by make. Here are some # special considerations: # 1. Use "connect" and "accept" to check for -lsocket, and # "gethostbyname" to check for -lnsl. # 2. Use each function name only once: can't redo a check because # autoconf caches the results of the last check and won't redo it. # 3. Use -lnsl and -lsocket only if they supply procedures that # aren't already present in the normal libraries. This is because # IRIX 5.2 has libraries, but they aren't needed and they're # bogus: they goof up name resolution if used. # 4. On some SVR4 systems, can't use -lsocket without -lnsl too. # To get around this problem, check for both libraries together # if -lsocket doesn't work by itself. #-------------------------------------------------------------------- tcl_checkBoth=0 AC_CHECK_FUNC(connect, tcl_checkSocket=0, tcl_checkSocket=1) if test "$tcl_checkSocket" = 1; then AC_CHECK_FUNC(setsockopt, , [AC_CHECK_LIB(socket, setsockopt, LIBS="$LIBS -lsocket", tcl_checkBoth=1)]) fi if test "$tcl_checkBoth" = 1; then tk_oldLibs=$LIBS LIBS="$LIBS -lsocket -lnsl" AC_CHECK_FUNC(accept, tcl_checkNsl=0, [LIBS=$tk_oldLibs]) fi AC_CHECK_FUNC(gethostbyname, , [AC_CHECK_LIB(nsl, gethostbyname, [LIBS="$LIBS -lnsl"])]) # Don't perform the eval of the libraries here because DL_LIBS # won't be set until we call TEA_CONFIG_CFLAGS TCL_LIBS='${DL_LIBS} ${LIBS} ${MATH_LIBS}' AC_SUBST(TCL_LIBS) AC_SUBST(MATH_LIBS) ]) #-------------------------------------------------------------------- # TEA_TCL_EARLY_FLAGS # # Check for what flags are needed to be passed so the correct OS # features are available. # # Arguments: # None # # Results: # # Might define the following vars: # _ISOC99_SOURCE # _LARGEFILE64_SOURCE # _LARGEFILE_SOURCE64 # #-------------------------------------------------------------------- AC_DEFUN(TEA_TCL_EARLY_FLAG,[ AC_CACHE_VAL([tcl_cv_flag_]translit($1,[A-Z],[a-z]), AC_TRY_COMPILE([$2], $3, [tcl_cv_flag_]translit($1,[A-Z],[a-z])=no, AC_TRY_COMPILE([[#define ]$1[ 1 ]$2], $3, [tcl_cv_flag_]translit($1,[A-Z],[a-z])=yes, [tcl_cv_flag_]translit($1,[A-Z],[a-z])=no))) if test ["x${tcl_cv_flag_]translit($1,[A-Z],[a-z])[}" = "xyes"] ; then AC_DEFINE($1, 1, [Add the ]$1[ flag when building]) tcl_flags="$tcl_flags $1" fi ]) AC_DEFUN(TEA_TCL_EARLY_FLAGS,[ AC_MSG_CHECKING([for required early compiler flags]) tcl_flags="" TEA_TCL_EARLY_FLAG(_ISOC99_SOURCE,[#include <stdlib.h>], [char *p = (char *)strtoll; char *q = (char *)strtoull;]) TEA_TCL_EARLY_FLAG(_LARGEFILE64_SOURCE,[#include <sys/stat.h>], [struct stat64 buf; int i = stat64("/", &buf);]) TEA_TCL_EARLY_FLAG(_LARGEFILE_SOURCE64,[#include <sys/stat.h>], [char *p = (char *)open64;]) if test "x${tcl_flags}" = "x" ; then AC_MSG_RESULT([none]) else AC_MSG_RESULT([${tcl_flags}]) fi ]) #-------------------------------------------------------------------- # TEA_TCL_64BIT_FLAGS # # Check for what is defined in the way of 64-bit features. # # Arguments: # None # # Results: # # Might define the following vars: # TCL_WIDE_INT_IS_LONG # TCL_WIDE_INT_TYPE # HAVE_STRUCT_DIRENT64 # HAVE_STRUCT_STAT64 # HAVE_TYPE_OFF64_T # #-------------------------------------------------------------------- AC_DEFUN(TEA_TCL_64BIT_FLAGS, [ AC_MSG_CHECKING([for 64-bit integer type]) AC_CACHE_VAL(tcl_cv_type_64bit,[ tcl_cv_type_64bit=none # See if the compiler knows natively about __int64 AC_TRY_COMPILE(,[__int64 value = (__int64) 0;], tcl_type_64bit=__int64, tcl_type_64bit="long long") # See if we should use long anyway Note that we substitute in the # type that is our current guess for a 64-bit type inside this check # program, so it should be modified only carefully... AC_TRY_COMPILE(,[switch (0) { case 1: case (sizeof(]${tcl_type_64bit}[)==sizeof(long)): ; }],tcl_cv_type_64bit=${tcl_type_64bit})]) if test "${tcl_cv_type_64bit}" = none ; then AC_DEFINE(TCL_WIDE_INT_IS_LONG, 1, [Are wide integers to be implemented with C 'long's?]) AC_MSG_RESULT([using long]) elif test "${tcl_cv_type_64bit}" = "__int64" \ -a "${TEA_PLATFORM}" = "windows" ; then # We actually want to use the default tcl.h checks in this # case to handle both TCL_WIDE_INT_TYPE and TCL_LL_MODIFIER* AC_MSG_RESULT([using Tcl header defaults]) else AC_DEFINE_UNQUOTED(TCL_WIDE_INT_TYPE,${tcl_cv_type_64bit}, [What type should be used to define wide integers?]) AC_MSG_RESULT([${tcl_cv_type_64bit}]) # Now check for auxiliary declarations AC_CACHE_CHECK([for struct dirent64], tcl_cv_struct_dirent64,[ AC_TRY_COMPILE([#include <sys/types.h> #include <sys/dirent.h>],[struct dirent64 p;], tcl_cv_struct_dirent64=yes,tcl_cv_struct_dirent64=no)]) if test "x${tcl_cv_struct_dirent64}" = "xyes" ; then AC_DEFINE(HAVE_STRUCT_DIRENT64, 1, [Is 'struct dirent64' in <sys/types.h>?]) fi AC_CACHE_CHECK([for struct stat64], tcl_cv_struct_stat64,[ AC_TRY_COMPILE([#include <sys/stat.h>],[struct stat64 p; ], tcl_cv_struct_stat64=yes,tcl_cv_struct_stat64=no)]) if test "x${tcl_cv_struct_stat64}" = "xyes" ; then AC_DEFINE(HAVE_STRUCT_STAT64, 1, [Is 'struct stat64' in <sys/stat.h>?]) fi AC_CHECK_FUNCS(open64 lseek64) AC_MSG_CHECKING([for off64_t]) AC_CACHE_VAL(tcl_cv_type_off64_t,[ AC_TRY_COMPILE([#include <sys/types.h>],[off64_t offset; ], tcl_cv_type_off64_t=yes,tcl_cv_type_off64_t=no)]) dnl Define HAVE_TYPE_OFF64_T only when the off64_t type and the dnl functions lseek64 and open64 are defined. if test "x${tcl_cv_type_off64_t}" = "xyes" && \ test "x${ac_cv_func_lseek64}" = "xyes" && \ test "x${ac_cv_func_open64}" = "xyes" ; then AC_DEFINE(HAVE_TYPE_OFF64_T, 1, [Is off64_t in <sys/types.h>?]) AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) fi fi ]) ## ## Here ends the standard Tcl configuration bits and starts the ## TEA specific functions ## #------------------------------------------------------------------------ # TEA_INIT -- # # Init various Tcl Extension Architecture (TEA) variables. # This should be the first called TEA_* macro. # # Arguments: # none # # Results: # # Defines and substs the following vars: # CYGPATH # EXEEXT # Defines only: # TEA_VERSION # TEA_INITED # TEA_PLATFORM (windows or unix) # # "cygpath" is used on windows to generate native path names for include # files. These variables should only be used with the compiler and linker # since they generate native path names. # # EXEEXT # Select the executable extension based on the host type. This # is a lightweight replacement for AC_EXEEXT that doesn't require # a compiler. #------------------------------------------------------------------------ AC_DEFUN(TEA_INIT, [ # TEA extensions pass this us the version of TEA they think they # are compatible with. TEA_VERSION="3.5" AC_MSG_CHECKING([for correct TEA configuration]) if test x"${PACKAGE_NAME}" = x ; then AC_MSG_ERROR([ The PACKAGE_NAME variable must be defined by your TEA configure.in]) fi if test x"$1" = x ; then AC_MSG_ERROR([ TEA version not specified.]) elif test "$1" != "${TEA_VERSION}" ; then AC_MSG_RESULT([warning: requested TEA version "$1", have "${TEA_VERSION}"]) else AC_MSG_RESULT([ok (TEA ${TEA_VERSION})]) fi case "`uname -s`" in *win32*|*WIN32*|*CYGWIN_NT*|*CYGWIN_9*|*CYGWIN_ME*|*MINGW32_*) AC_CHECK_PROG(CYGPATH, cygpath, cygpath -w, echo) EXEEXT=".exe" TEA_PLATFORM="windows" ;; *) CYGPATH=echo EXEEXT="" TEA_PLATFORM="unix" ;; esac # Check if exec_prefix is set. If not use fall back to prefix. # Note when adjusted, so that TEA_PREFIX can correct for this. # This is needed for recursive configures, since autoconf propagates # $prefix, but not $exec_prefix (doh!). if test x$exec_prefix = xNONE ; then exec_prefix_default=yes exec_prefix=$prefix fi AC_SUBST(EXEEXT) AC_SUBST(CYGPATH) # This package name must be replaced statically for AC_SUBST to work AC_SUBST(PKG_LIB_FILE) # Substitute STUB_LIB_FILE in case package creates a stub library too. AC_SUBST(PKG_STUB_LIB_FILE) # We AC_SUBST these here to ensure they are subst'ed, # in case the user doesn't call TEA_ADD_... AC_SUBST(PKG_STUB_SOURCES) AC_SUBST(PKG_STUB_OBJECTS) AC_SUBST(PKG_TCL_SOURCES) AC_SUBST(PKG_HEADERS) AC_SUBST(PKG_INCLUDES) AC_SUBST(PKG_LIBS) AC_SUBST(PKG_CFLAGS) ]) #------------------------------------------------------------------------ # TEA_ADD_SOURCES -- # # Specify one or more source files. Users should check for # the right platform before adding to their list. # It is not important to specify the directory, as long as it is # in the generic, win or unix subdirectory of $(srcdir). # # Arguments: # one or more file names # # Results: # # Defines and substs the following vars: # PKG_SOURCES # PKG_OBJECTS #------------------------------------------------------------------------ AC_DEFUN(TEA_ADD_SOURCES, [ vars="$@" for i in $vars; do case $i in [\$]*) # allow $-var names PKG_SOURCES="$PKG_SOURCES $i" PKG_OBJECTS="$PKG_OBJECTS $i" ;; *) # check for existence - allows for generic/win/unix VPATH if test ! -f "${srcdir}/$i" -a ! -f "${srcdir}/src/$i" \ -a ! -f "${srcdir}/win/$i" -a ! -f "${srcdir}/unix/$i" \ ; then AC_MSG_ERROR([could not find source file '$i']) fi PKG_SOURCES="$PKG_SOURCES $i" # this assumes it is in a VPATH dir i=`basename $i` # handle user calling this before or after TEA_SETUP_COMPILER if test x"${OBJEXT}" != x ; then j="`echo $i | sed -e 's/\.[[^.]]*$//'`.${OBJEXT}" else j="`echo $i | sed -e 's/\.[[^.]]*$//'`.\${OBJEXT}" fi PKG_OBJECTS="$PKG_OBJECTS $j" ;; esac done AC_SUBST(PKG_SOURCES) AC_SUBST(PKG_OBJECTS) ]) #------------------------------------------------------------------------ # TEA_ADD_STUB_SOURCES -- # # Specify one or more source files. Users should check for # the right platform before adding to their list. # It is not important to specify the directory, as long as it is # in the generic, win or unix subdirectory of $(srcdir). # # Arguments: # one or more file names # # Results: # # Defines and substs the following vars: # PKG_STUB_SOURCES # PKG_STUB_OBJECTS #------------------------------------------------------------------------ AC_DEFUN(TEA_ADD_STUB_SOURCES, [ vars="$@" for i in $vars; do # check for existence - allows for generic/win/unix VPATH if test ! -f "${srcdir}/$i" -a ! -f "${srcdir}/generic/$i" \ -a ! -f "${srcdir}/win/$i" -a ! -f "${srcdir}/unix/$i" \ ; then AC_MSG_ERROR([could not find stub source file '$i']) fi PKG_STUB_SOURCES="$PKG_STUB_SOURCES $i" # this assumes it is in a VPATH dir i=`basename $i` # handle user calling this before or after TEA_SETUP_COMPILER if test x"${OBJEXT}" != x ; then j="`echo $i | sed -e 's/\.[[^.]]*$//'`.${OBJEXT}" else j="`echo $i | sed -e 's/\.[[^.]]*$//'`.\${OBJEXT}" fi PKG_STUB_OBJECTS="$PKG_STUB_OBJECTS $j" done AC_SUBST(PKG_STUB_SOURCES) AC_SUBST(PKG_STUB_OBJECTS) ]) #------------------------------------------------------------------------ # TEA_ADD_TCL_SOURCES -- # # Specify one or more Tcl source files. These should be platform # independent runtime files. # # Arguments: # one or more file names # # Results: # # Defines and substs the following vars: # PKG_TCL_SOURCES #------------------------------------------------------------------------ AC_DEFUN(TEA_ADD_TCL_SOURCES, [ vars="$@" for i in $vars; do # check for existence, be strict because it is installed if test ! -f "${srcdir}/$i" ; then AC_MSG_ERROR([could not find tcl source file '${srcdir}/$i']) fi PKG_TCL_SOURCES="$PKG_TCL_SOURCES $i" done AC_SUBST(PKG_TCL_SOURCES) ]) #------------------------------------------------------------------------ # TEA_ADD_HEADERS -- # # Specify one or more source headers. Users should check for # the right platform before adding to their list. # # Arguments: # one or more file names # # Results: # # Defines and substs the following vars: # PKG_HEADERS #------------------------------------------------------------------------ AC_DEFUN(TEA_ADD_HEADERS, [ vars="$@" for i in $vars; do # check for existence, be strict because it is installed if test ! -f "${srcdir}/$i" ; then AC_MSG_ERROR([could not find header file '${srcdir}/$i']) fi PKG_HEADERS="$PKG_HEADERS $i" done AC_SUBST(PKG_HEADERS) ]) #------------------------------------------------------------------------ # TEA_ADD_INCLUDES -- # # Specify one or more include dirs. Users should check for # the right platform before adding to their list. # # Arguments: # one or more file names # # Results: # # Defines and substs the following vars: # PKG_INCLUDES #------------------------------------------------------------------------ AC_DEFUN(TEA_ADD_INCLUDES, [ vars="$@" for i in $vars; do PKG_INCLUDES="$PKG_INCLUDES $i" done AC_SUBST(PKG_INCLUDES) ]) #------------------------------------------------------------------------ # TEA_ADD_LIBS -- # # Specify one or more libraries. Users should check for # the right platform before adding to their list. For Windows, # libraries provided in "foo.lib" format will be converted to # "-lfoo" when using GCC (mingw). # # Arguments: # one or more file names # # Results: # # Defines and substs the following vars: # PKG_LIBS #------------------------------------------------------------------------ AC_DEFUN(TEA_ADD_LIBS, [ vars="$@" for i in $vars; do if test "${TEA_PLATFORM}" = "windows" -a "$GCC" = "yes" ; then # Convert foo.lib to -lfoo for GCC. No-op if not *.lib i=`echo "$i" | sed -e 's/^\([[^-]].*\)\.lib[$]/-l\1/i'` fi PKG_LIBS="$PKG_LIBS $i" done AC_SUBST(PKG_LIBS) ]) #------------------------------------------------------------------------ # TEA_ADD_CFLAGS -- # # Specify one or more CFLAGS. Users should check for # the right platform before adding to their list. # # Arguments: # one or more file names # # Results: # # Defines and substs the following vars: # PKG_CFLAGS #------------------------------------------------------------------------ AC_DEFUN(TEA_ADD_CFLAGS, [ PKG_CFLAGS="$PKG_CFLAGS $@" AC_SUBST(PKG_CFLAGS) ]) #------------------------------------------------------------------------ # TEA_PREFIX -- # # Handle the --prefix=... option by defaulting to what Tcl gave # # Arguments: # none # # Results: # # If --prefix or --exec-prefix was not specified, $prefix and # $exec_prefix will be set to the values given to Tcl when it was # configured. #------------------------------------------------------------------------ AC_DEFUN(TEA_PREFIX, [ if test "${prefix}" = "NONE"; then prefix_default=yes if test x"${TCL_PREFIX}" != x; then AC_MSG_NOTICE([--prefix defaulting to TCL_PREFIX ${TCL_PREFIX}]) prefix=${TCL_PREFIX} else AC_MSG_NOTICE([--prefix defaulting to /usr/local]) prefix=/usr/local fi fi if test "${exec_prefix}" = "NONE" -a x"${prefix_default}" = x"yes" \ -o x"${exec_prefix_default}" = x"yes" ; then if test x"${TCL_EXEC_PREFIX}" != x; then AC_MSG_NOTICE([--exec-prefix defaulting to TCL_EXEC_PREFIX ${TCL_EXEC_PREFIX}]) exec_prefix=${TCL_EXEC_PREFIX} else AC_MSG_NOTICE([--exec-prefix defaulting to ${prefix}]) exec_prefix=$prefix fi fi ]) #------------------------------------------------------------------------ # TEA_SETUP_COMPILER_CC -- # # Do compiler checks the way we want. This is just a replacement # for AC_PROG_CC in TEA configure.in files to make them cleaner. # # Arguments: # none # # Results: # # Sets up CC var and other standard bits we need to make executables. #------------------------------------------------------------------------ AC_DEFUN(TEA_SETUP_COMPILER_CC, [ # Don't put any macros that use the compiler (e.g. AC_TRY_COMPILE) # in this macro, they need to go into TEA_SETUP_COMPILER instead. # If the user did not set CFLAGS, set it now to keep # the AC_PROG_CC macro from adding "-g -O2". if test "${CFLAGS+set}" != "set" ; then CFLAGS="" fi AC_PROG_CC AC_PROG_CPP AC_PROG_INSTALL #-------------------------------------------------------------------- # Checks to see if the make program sets the $MAKE variable. #-------------------------------------------------------------------- AC_PROG_MAKE_SET #-------------------------------------------------------------------- # Find ranlib #-------------------------------------------------------------------- AC_PROG_RANLIB #-------------------------------------------------------------------- # Determines the correct binary file extension (.o, .obj, .exe etc.) #-------------------------------------------------------------------- AC_OBJEXT AC_EXEEXT ]) #------------------------------------------------------------------------ # TEA_SETUP_COMPILER -- # # Do compiler checks that use the compiler. This must go after # TEA_SETUP_COMPILER_CC, which does the actual compiler check. # # Arguments: # none # # Results: # # Sets up CC var and other standard bits we need to make executables. #------------------------------------------------------------------------ AC_DEFUN(TEA_SETUP_COMPILER, [ # Any macros that use the compiler (e.g. AC_TRY_COMPILE) have to go here. AC_REQUIRE([TEA_SETUP_COMPILER_CC]) #------------------------------------------------------------------------ # If we're using GCC, see if the compiler understands -pipe. If so, use it. # It makes compiling go faster. (This is only a performance feature.) #------------------------------------------------------------------------ if test -z "$no_pipe" -a -n "$GCC"; then AC_MSG_CHECKING([if the compiler understands -pipe]) OLDCC="$CC" CC="$CC -pipe" AC_TRY_COMPILE(,, AC_MSG_RESULT([yes]), CC="$OLDCC" AC_MSG_RESULT([no])) fi #-------------------------------------------------------------------- # Common compiler flag setup #-------------------------------------------------------------------- AC_C_BIGENDIAN if test "${TEA_PLATFORM}" = "unix" ; then TEA_TCL_LINK_LIBS TEA_MISSING_POSIX_HEADERS # Let the user call this, because if it triggers, they will # need a compat/strtod.c that is correct. Users can also # use Tcl_GetDouble(FromObj) instead. #TEA_BUGGY_STRTOD fi ]) #------------------------------------------------------------------------ # TEA_MAKE_LIB -- # # Generate a line that can be used to build a shared/unshared library # in a platform independent manner. # # Arguments: # none # # Requires: # # Results: # # Defines the following vars: # CFLAGS - Done late here to note disturb other AC macros # MAKE_LIB - Command to execute to build the Tcl library; # differs depending on whether or not Tcl is being # compiled as a shared library. # MAKE_SHARED_LIB Makefile rule for building a shared library # MAKE_STATIC_LIB Makefile rule for building a static library # MAKE_STUB_LIB Makefile rule for building a stub library #------------------------------------------------------------------------ AC_DEFUN(TEA_MAKE_LIB, [ if test "${TEA_PLATFORM}" = "windows" -a "$GCC" != "yes"; then MAKE_STATIC_LIB="\${STLIB_LD} -out:\[$]@ \$(PKG_OBJECTS)" MAKE_SHARED_LIB="\${SHLIB_LD} \${SHLIB_LD_LIBS} \${LDFLAGS_DEFAULT} -out:\[$]@ \$(PKG_OBJECTS)" MAKE_STUB_LIB="\${STLIB_LD} -out:\[$]@ \$(PKG_STUB_OBJECTS)" else MAKE_STATIC_LIB="\${STLIB_LD} \[$]@ \$(PKG_OBJECTS)" MAKE_SHARED_LIB="\${SHLIB_LD} -o \[$]@ \$(PKG_OBJECTS) \${SHLIB_LD_LIBS}" MAKE_STUB_LIB="\${STLIB_LD} \[$]@ \$(PKG_STUB_OBJECTS)" fi if test "${SHARED_BUILD}" = "1" ; then MAKE_LIB="${MAKE_SHARED_LIB} " else MAKE_LIB="${MAKE_STATIC_LIB} " fi #-------------------------------------------------------------------- # Shared libraries and static libraries have different names. # Use the double eval to make sure any variables in the suffix is # substituted. (@@@ Might not be necessary anymore) #-------------------------------------------------------------------- if test "${TEA_PLATFORM}" = "windows" ; then if test "${SHARED_BUILD}" = "1" ; then # We force the unresolved linking of symbols that are really in # the private libraries of Tcl and Tk. SHLIB_LD_LIBS="${SHLIB_LD_LIBS} \"`${CYGPATH} ${TCL_BIN_DIR}/${TCL_STUB_LIB_FILE}`\"" if test x"${TK_BIN_DIR}" != x ; then SHLIB_LD_LIBS="${SHLIB_LD_LIBS} \"`${CYGPATH} ${TK_BIN_DIR}/${TK_STUB_LIB_FILE}`\"" fi eval eval "PKG_LIB_FILE=${PACKAGE_NAME}${SHARED_LIB_SUFFIX}" else eval eval "PKG_LIB_FILE=${PACKAGE_NAME}${UNSHARED_LIB_SUFFIX}" fi # Some packages build their own stubs libraries eval eval "PKG_STUB_LIB_FILE=${PACKAGE_NAME}stub${UNSHARED_LIB_SUFFIX}" # These aren't needed on Windows (either MSVC or gcc) RANLIB=: RANLIB_STUB=: else RANLIB_STUB="${RANLIB}" if test "${SHARED_BUILD}" = "1" ; then SHLIB_LD_LIBS="${SHLIB_LD_LIBS} ${TCL_STUB_LIB_SPEC}" if test x"${TK_BIN_DIR}" != x ; then SHLIB_LD_LIBS="${SHLIB_LD_LIBS} ${TK_STUB_LIB_SPEC}" fi eval eval "PKG_LIB_FILE=lib${PACKAGE_NAME}${SHARED_LIB_SUFFIX}" RANLIB=: else eval eval "PKG_LIB_FILE=lib${PACKAGE_NAME}${UNSHARED_LIB_SUFFIX}" fi # Some packages build their own stubs libraries eval eval "PKG_STUB_LIB_FILE=lib${PACKAGE_NAME}stub${UNSHARED_LIB_SUFFIX}" fi # These are escaped so that only CFLAGS is picked up at configure time. # The other values will be substituted at make time. CFLAGS="${CFLAGS} \${CFLAGS_DEFAULT} \${CFLAGS_WARNING}" if test "${SHARED_BUILD}" = "1" ; then CFLAGS="${CFLAGS} \${SHLIB_CFLAGS}" fi AC_SUBST(MAKE_LIB) AC_SUBST(MAKE_SHARED_LIB) AC_SUBST(MAKE_STATIC_LIB) AC_SUBST(MAKE_STUB_LIB) AC_SUBST(RANLIB_STUB) ]) #------------------------------------------------------------------------ # TEA_LIB_SPEC -- # # Compute the name of an existing object library located in libdir # from the given base name and produce the appropriate linker flags. # # Arguments: # basename The base name of the library without version # numbers, extensions, or "lib" prefixes. # extra_dir Extra directory in which to search for the # library. This location is used first, then # $prefix/$exec-prefix, then some defaults. # # Requires: # TEA_INIT and TEA_PREFIX must be called first. # # Results: # # Defines the following vars: # ${basename}_LIB_NAME The computed library name. # ${basename}_LIB_SPEC The computed linker flags. #------------------------------------------------------------------------ AC_DEFUN(TEA_LIB_SPEC, [ AC_MSG_CHECKING([for $1 library]) # Look in exec-prefix for the library (defined by TEA_PREFIX). tea_lib_name_dir="${exec_prefix}/lib" # Or in a user-specified location. if test x"$2" != x ; then tea_extra_lib_dir=$2 else tea_extra_lib_dir=NONE fi for i in \ `ls -dr ${tea_extra_lib_dir}/$1[[0-9]]*.lib 2>/dev/null ` \ `ls -dr ${tea_extra_lib_dir}/lib$1[[0-9]]* 2>/dev/null ` \ `ls -dr ${tea_lib_name_dir}/$1[[0-9]]*.lib 2>/dev/null ` \ `ls -dr ${tea_lib_name_dir}/lib$1[[0-9]]* 2>/dev/null ` \ `ls -dr /usr/lib/$1[[0-9]]*.lib 2>/dev/null ` \ `ls -dr /usr/lib/lib$1[[0-9]]* 2>/dev/null ` \ `ls -dr /usr/local/lib/$1[[0-9]]*.lib 2>/dev/null ` \ `ls -dr /usr/local/lib/lib$1[[0-9]]* 2>/dev/null ` ; do if test -f "$i" ; then tea_lib_name_dir=`dirname $i` $1_LIB_NAME=`basename $i` $1_LIB_PATH_NAME=$i break fi done if test "${TEA_PLATFORM}" = "windows"; then $1_LIB_SPEC=\"`${CYGPATH} ${$1_LIB_PATH_NAME} 2>/dev/null`\" else # Strip off the leading "lib" and trailing ".a" or ".so" tea_lib_name_lib=`echo ${$1_LIB_NAME}|sed -e 's/^lib//' -e 's/\.[[^.]]*$//' -e 's/\.so.*//'` $1_LIB_SPEC="-L${tea_lib_name_dir} -l${tea_lib_name_lib}" fi if test "x${$1_LIB_NAME}" = x ; then AC_MSG_ERROR([not found]) else AC_MSG_RESULT([${$1_LIB_SPEC}]) fi ]) #------------------------------------------------------------------------ # TEA_PRIVATE_TCL_HEADERS -- # # Locate the private Tcl include files # # Arguments: # # Requires: # TCL_SRC_DIR Assumes that TEA_LOAD_TCLCONFIG has # already been called. # # Results: # # Substs the following vars: # TCL_TOP_DIR_NATIVE # TCL_GENERIC_DIR_NATIVE # TCL_UNIX_DIR_NATIVE # TCL_WIN_DIR_NATIVE # TCL_BMAP_DIR_NATIVE # TCL_TOOL_DIR_NATIVE # TCL_PLATFORM_DIR_NATIVE # TCL_BIN_DIR_NATIVE # TCL_INCLUDES #------------------------------------------------------------------------ AC_DEFUN(TEA_PRIVATE_TCL_HEADERS, [ AC_MSG_CHECKING([for Tcl private include files]) TCL_SRC_DIR_NATIVE=`${CYGPATH} ${TCL_SRC_DIR}` TCL_TOP_DIR_NATIVE=\"${TCL_SRC_DIR_NATIVE}\" TCL_GENERIC_DIR_NATIVE=\"${TCL_SRC_DIR_NATIVE}/generic\" TCL_UNIX_DIR_NATIVE=\"${TCL_SRC_DIR_NATIVE}/unix\" TCL_WIN_DIR_NATIVE=\"${TCL_SRC_DIR_NATIVE}/win\" TCL_BMAP_DIR_NATIVE=\"${TCL_SRC_DIR_NATIVE}/bitmaps\" TCL_TOOL_DIR_NATIVE=\"${TCL_SRC_DIR_NATIVE}/tools\" TCL_COMPAT_DIR_NATIVE=\"${TCL_SRC_DIR_NATIVE}/compat\" if test "${TEA_PLATFORM}" = "windows"; then TCL_PLATFORM_DIR_NATIVE=${TCL_WIN_DIR_NATIVE} else TCL_PLATFORM_DIR_NATIVE=${TCL_UNIX_DIR_NATIVE} fi # We want to ensure these are substituted so as not to require # any *_NATIVE vars be defined in the Makefile TCL_INCLUDES="-I${TCL_GENERIC_DIR_NATIVE} -I${TCL_PLATFORM_DIR_NATIVE}" if test "`uname -s`" = "Darwin"; then # If Tcl was built as a framework, attempt to use # the framework's Headers and PrivateHeaders directories case ${TCL_DEFS} in *TCL_FRAMEWORK*) if test -d "${TCL_BIN_DIR}/Headers" -a -d "${TCL_BIN_DIR}/PrivateHeaders"; then TCL_INCLUDES="-I\"${TCL_BIN_DIR}/Headers\" -I\"${TCL_BIN_DIR}/PrivateHeaders\" ${TCL_INCLUDES}"; else TCL_INCLUDES="${TCL_INCLUDES} ${TCL_INCLUDE_SPEC} `echo "${TCL_INCLUDE_SPEC}" | sed -e 's/Headers/PrivateHeaders/'`"; fi ;; esac fi AC_SUBST(TCL_TOP_DIR_NATIVE) AC_SUBST(TCL_GENERIC_DIR_NATIVE) AC_SUBST(TCL_UNIX_DIR_NATIVE) AC_SUBST(TCL_WIN_DIR_NATIVE) AC_SUBST(TCL_BMAP_DIR_NATIVE) AC_SUBST(TCL_TOOL_DIR_NATIVE) AC_SUBST(TCL_PLATFORM_DIR_NATIVE) AC_SUBST(TCL_INCLUDES) AC_MSG_RESULT([Using srcdir found in tclConfig.sh: ${TCL_SRC_DIR}]) ]) #------------------------------------------------------------------------ # TEA_PUBLIC_TCL_HEADERS -- # # Locate the installed public Tcl header files # # Arguments: # None. # # Requires: # CYGPATH must be set # # Results: # # Adds a --with-tclinclude switch to configure. # Result is cached. # # Substs the following vars: # TCL_INCLUDES #------------------------------------------------------------------------ AC_DEFUN(TEA_PUBLIC_TCL_HEADERS, [ AC_MSG_CHECKING([for Tcl public headers]) AC_ARG_WITH(tclinclude, [ --with-tclinclude directory containing the public Tcl header files], with_tclinclude=${withval}) AC_CACHE_VAL(ac_cv_c_tclh, [ # Use the value from --with-tclinclude, if it was given if test x"${with_tclinclude}" != x ; then if test -f "${with_tclinclude}/tcl.h" ; then ac_cv_c_tclh=${with_tclinclude} else AC_MSG_ERROR([${with_tclinclude} directory does not contain tcl.h]) fi else if test "`uname -s`" = "Darwin"; then # If Tcl was built as a framework, attempt to use # the framework's Headers directory case ${TCL_DEFS} in *TCL_FRAMEWORK*) list="`ls -d ${TCL_BIN_DIR}/Headers 2>/dev/null`" ;; esac fi # Look in the source dir only if Tcl is not installed, # and in that situation, look there before installed locations. if test -f "${TCL_BIN_DIR}/Makefile" ; then list="$list `ls -d ${TCL_SRC_DIR}/generic 2>/dev/null`" fi # Check order: pkg --prefix location, Tcl's --prefix location, # relative to directory of tclConfig.sh. eval "temp_includedir=${includedir}" list="$list \ `ls -d ${temp_includedir} 2>/dev/null` \ `ls -d ${TCL_PREFIX}/include 2>/dev/null` \ `ls -d ${TCL_BIN_DIR}/../include 2>/dev/null`" if test "${TEA_PLATFORM}" != "windows" -o "$GCC" = "yes"; then list="$list /usr/local/include /usr/include" if test x"${TCL_INCLUDE_SPEC}" != x ; then d=`echo "${TCL_INCLUDE_SPEC}" | sed -e 's/^-I//'` list="$list `ls -d ${d} 2>/dev/null`" fi fi for i in $list ; do if test -f "$i/tcl.h" ; then ac_cv_c_tclh=$i break fi done fi ]) # Print a message based on how we determined the include path if test x"${ac_cv_c_tclh}" = x ; then AC_MSG_ERROR([tcl.h not found. Please specify its location with --with-tclinclude]) else AC_MSG_RESULT([${ac_cv_c_tclh}]) fi # Convert to a native path and substitute into the output files. INCLUDE_DIR_NATIVE=`${CYGPATH} ${ac_cv_c_tclh}` TCL_INCLUDES=-I\"${INCLUDE_DIR_NATIVE}\" AC_SUBST(TCL_INCLUDES) ]) #------------------------------------------------------------------------ # TEA_PRIVATE_TK_HEADERS -- # # Locate the private Tk include files # # Arguments: # # Requires: # TK_SRC_DIR Assumes that TEA_LOAD_TKCONFIG has # already been called. # # Results: # # Substs the following vars: # TK_INCLUDES #------------------------------------------------------------------------ AC_DEFUN(TEA_PRIVATE_TK_HEADERS, [ AC_MSG_CHECKING([for Tk private include files]) TK_SRC_DIR_NATIVE=`${CYGPATH} ${TK_SRC_DIR}` TK_TOP_DIR_NATIVE=\"${TK_SRC_DIR_NATIVE}\" TK_UNIX_DIR_NATIVE=\"${TK_SRC_DIR_NATIVE}/unix\" TK_WIN_DIR_NATIVE=\"${TK_SRC_DIR_NATIVE}/win\" TK_GENERIC_DIR_NATIVE=\"${TK_SRC_DIR_NATIVE}/generic\" TK_XLIB_DIR_NATIVE=\"${TK_SRC_DIR_NATIVE}/xlib\" if test "${TEA_PLATFORM}" = "windows"; then TK_PLATFORM_DIR_NATIVE=${TK_WIN_DIR_NATIVE} else TK_PLATFORM_DIR_NATIVE=${TK_UNIX_DIR_NATIVE} fi # We want to ensure these are substituted so as not to require # any *_NATIVE vars be defined in the Makefile TK_INCLUDES="-I${TK_GENERIC_DIR_NATIVE} -I${TK_PLATFORM_DIR_NATIVE}" if test "${TEA_WINDOWINGSYSTEM}" = "win32" \ -o "${TEA_WINDOWINGSYSTEM}" = "aqua"; then TK_INCLUDES="${TK_INCLUDES} -I${TK_XLIB_DIR_NATIVE}" fi if test "${TEA_WINDOWINGSYSTEM}" = "aqua"; then TK_INCLUDES="${TK_INCLUDES} -I${TK_SRC_DIR_NATIVE}/macosx" fi if test "`uname -s`" = "Darwin"; then # If Tk was built as a framework, attempt to use # the framework's Headers and PrivateHeaders directories case ${TK_DEFS} in *TK_FRAMEWORK*) if test -d "${TK_BIN_DIR}/Headers" -a -d "${TK_BIN_DIR}/PrivateHeaders"; then TK_INCLUDES="-I\"${TK_BIN_DIR}/Headers\" -I\"${TK_BIN_DIR}/PrivateHeaders\" ${TK_INCLUDES}"; fi ;; esac fi AC_SUBST(TK_TOP_DIR_NATIVE) AC_SUBST(TK_UNIX_DIR_NATIVE) AC_SUBST(TK_WIN_DIR_NATIVE) AC_SUBST(TK_GENERIC_DIR_NATIVE) AC_SUBST(TK_XLIB_DIR_NATIVE) AC_SUBST(TK_PLATFORM_DIR_NATIVE) AC_SUBST(TK_INCLUDES) AC_MSG_RESULT([Using srcdir found in tkConfig.sh: ${TK_SRC_DIR}]) ]) #------------------------------------------------------------------------ # TEA_PUBLIC_TK_HEADERS -- # # Locate the installed public Tk header files # # Arguments: # None. # # Requires: # CYGPATH must be set # # Results: # # Adds a --with-tkinclude switch to configure. # Result is cached. # # Substs the following vars: # TK_INCLUDES #------------------------------------------------------------------------ AC_DEFUN(TEA_PUBLIC_TK_HEADERS, [ AC_MSG_CHECKING([for Tk public headers]) AC_ARG_WITH(tkinclude, [ --with-tkinclude directory containing the public Tk header files.], with_tkinclude=${withval}) AC_CACHE_VAL(ac_cv_c_tkh, [ # Use the value from --with-tkinclude, if it was given if test x"${with_tkinclude}" != x ; then if test -f "${with_tkinclude}/tk.h" ; then ac_cv_c_tkh=${with_tkinclude} else AC_MSG_ERROR([${with_tkinclude} directory does not contain tk.h]) fi else if test "`uname -s`" = "Darwin"; then # If Tk was built as a framework, attempt to use # the framework's Headers directory. case ${TK_DEFS} in *TK_FRAMEWORK*) list="`ls -d ${TK_BIN_DIR}/Headers 2>/dev/null`" ;; esac fi # Look in the source dir only if Tk is not installed, # and in that situation, look there before installed locations. if test -f "${TK_BIN_DIR}/Makefile" ; then list="$list `ls -d ${TK_SRC_DIR}/generic 2>/dev/null`" fi # Check order: pkg --prefix location, Tk's --prefix location, # relative to directory of tkConfig.sh, Tcl's --prefix location, # relative to directory of tclConfig.sh. eval "temp_includedir=${includedir}" list="$list \ `ls -d ${temp_includedir} 2>/dev/null` \ `ls -d ${TK_PREFIX}/include 2>/dev/null` \ `ls -d ${TK_BIN_DIR}/../include 2>/dev/null` \ `ls -d ${TCL_PREFIX}/include 2>/dev/null` \ `ls -d ${TCL_BIN_DIR}/../include 2>/dev/null`" if test "${TEA_PLATFORM}" != "windows" -o "$GCC" = "yes"; then list="$list /usr/local/include /usr/include" fi for i in $list ; do if test -f "$i/tk.h" ; then ac_cv_c_tkh=$i break fi done fi ]) # Print a message based on how we determined the include path if test x"${ac_cv_c_tkh}" = x ; then AC_MSG_ERROR([tk.h not found. Please specify its location with --with-tkinclude]) else AC_MSG_RESULT([${ac_cv_c_tkh}]) fi # Convert to a native path and substitute into the output files. INCLUDE_DIR_NATIVE=`${CYGPATH} ${ac_cv_c_tkh}` TK_INCLUDES=-I\"${INCLUDE_DIR_NATIVE}\" AC_SUBST(TK_INCLUDES) if test "${TEA_WINDOWINGSYSTEM}" = "win32" \ -o "${TEA_WINDOWINGSYSTEM}" = "aqua"; then # On Windows and Aqua, we need the X compat headers AC_MSG_CHECKING([for X11 header files]) if test ! -r "${INCLUDE_DIR_NATIVE}/X11/Xlib.h"; then INCLUDE_DIR_NATIVE="`${CYGPATH} ${TK_SRC_DIR}/xlib`" TK_XINCLUDES=-I\"${INCLUDE_DIR_NATIVE}\" AC_SUBST(TK_XINCLUDES) fi AC_MSG_RESULT([${INCLUDE_DIR_NATIVE}]) fi ]) #------------------------------------------------------------------------ # TEA_PROG_TCLSH # Determine the fully qualified path name of the tclsh executable # in the Tcl build directory or the tclsh installed in a bin # directory. This macro will correctly determine the name # of the tclsh executable even if tclsh has not yet been # built in the build directory. The tclsh found is always # associated with a tclConfig.sh file. This tclsh should be used # only for running extension test cases. It should never be # or generation of files (like pkgIndex.tcl) at build time. # # Arguments # none # # Results # Subst's the following values: # TCLSH_PROG #------------------------------------------------------------------------ AC_DEFUN(TEA_PROG_TCLSH, [ AC_MSG_CHECKING([for tclsh]) if test -f "${TCL_BIN_DIR}/Makefile" ; then # tclConfig.sh is in Tcl build directory if test "${TEA_PLATFORM}" = "windows"; then TCLSH_PROG="${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}${TCL_DBGX}${EXEEXT}" else TCLSH_PROG="${TCL_BIN_DIR}/tclsh" fi else # tclConfig.sh is in install location if test "${TEA_PLATFORM}" = "windows"; then TCLSH_PROG="tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}${TCL_DBGX}${EXEEXT}" else TCLSH_PROG="tclsh${TCL_MAJOR_VERSION}.${TCL_MINOR_VERSION}${TCL_DBGX}" fi list="`ls -d ${TCL_BIN_DIR}/../bin 2>/dev/null` \ `ls -d ${TCL_BIN_DIR}/.. 2>/dev/null` \ `ls -d ${TCL_PREFIX}/bin 2>/dev/null`" for i in $list ; do if test -f "$i/${TCLSH_PROG}" ; then REAL_TCL_BIN_DIR="`cd "$i"; pwd`" break fi done TCLSH_PROG="${REAL_TCL_BIN_DIR}/${TCLSH_PROG}" fi AC_MSG_RESULT([${TCLSH_PROG}]) AC_SUBST(TCLSH_PROG) ]) #------------------------------------------------------------------------ # TEA_PROG_WISH # Determine the fully qualified path name of the wish executable # in the Tk build directory or the wish installed in a bin # directory. This macro will correctly determine the name # of the wish executable even if wish has not yet been # built in the build directory. The wish found is always # associated with a tkConfig.sh file. This wish should be used # only for running extension test cases. It should never be # or generation of files (like pkgIndex.tcl) at build time. # # Arguments # none # # Results # Subst's the following values: # WISH_PROG #------------------------------------------------------------------------ AC_DEFUN(TEA_PROG_WISH, [ AC_MSG_CHECKING([for wish]) if test -f "${TK_BIN_DIR}/Makefile" ; then # tkConfig.sh is in Tk build directory if test "${TEA_PLATFORM}" = "windows"; then WISH_PROG="${TK_BIN_DIR}/wish${TK_MAJOR_VERSION}${TK_MINOR_VERSION}${TK_DBGX}${EXEEXT}" else WISH_PROG="${TK_BIN_DIR}/wish" fi else # tkConfig.sh is in install location if test "${TEA_PLATFORM}" = "windows"; then WISH_PROG="wish${TK_MAJOR_VERSION}${TK_MINOR_VERSION}${TK_DBGX}${EXEEXT}" else WISH_PROG="wish${TK_MAJOR_VERSION}.${TK_MINOR_VERSION}${TK_DBGX}" fi list="`ls -d ${TK_BIN_DIR}/../bin 2>/dev/null` \ `ls -d ${TK_BIN_DIR}/.. 2>/dev/null` \ `ls -d ${TK_PREFIX}/bin 2>/dev/null`" for i in $list ; do if test -f "$i/${WISH_PROG}" ; then REAL_TK_BIN_DIR="`cd "$i"; pwd`" break fi done WISH_PROG="${REAL_TK_BIN_DIR}/${WISH_PROG}" fi AC_MSG_RESULT([${WISH_PROG}]) AC_SUBST(WISH_PROG) ]) #------------------------------------------------------------------------ # TEA_PATH_CONFIG -- # # Locate the ${1}Config.sh file and perform a sanity check on # the ${1} compile flags. These are used by packages like # [incr Tk] that load *Config.sh files from more than Tcl and Tk. # # Arguments: # none # # Results: # # Adds the following arguments to configure: # --with-$1=... # # Defines the following vars: # $1_BIN_DIR Full path to the directory containing # the $1Config.sh file #------------------------------------------------------------------------ AC_DEFUN(TEA_PATH_CONFIG, [ # # Ok, lets find the $1 configuration # First, look for one uninstalled. # the alternative search directory is invoked by --with-$1 # if test x"${no_$1}" = x ; then # we reset no_$1 in case something fails here no_$1=true AC_ARG_WITH($1, [ --with-$1 directory containing $1 configuration ($1Config.sh)], with_$1config=${withval}) AC_MSG_CHECKING([for $1 configuration]) AC_CACHE_VAL(ac_cv_c_$1config,[ # First check to see if --with-$1 was specified. if test x"${with_$1config}" != x ; then case ${with_$1config} in */$1Config.sh ) if test -f ${with_$1config}; then AC_MSG_WARN([--with-$1 argument should refer to directory containing $1Config.sh, not to $1Config.sh itself]) with_$1config=`echo ${with_$1config} | sed 's!/$1Config\.sh$!!'` fi;; esac if test -f "${with_$1config}/$1Config.sh" ; then ac_cv_c_$1config=`(cd ${with_$1config}; pwd)` else AC_MSG_ERROR([${with_$1config} directory doesn't contain $1Config.sh]) fi fi # then check for a private $1 installation if test x"${ac_cv_c_$1config}" = x ; then for i in \ ../$1 \ `ls -dr ../$1*[[0-9]].[[0-9]]*.[[0-9]]* 2>/dev/null` \ `ls -dr ../$1*[[0-9]].[[0-9]][[0-9]] 2>/dev/null` \ `ls -dr ../$1*[[0-9]].[[0-9]] 2>/dev/null` \ `ls -dr ../$1*[[0-9]].[[0-9]]* 2>/dev/null` \ ../../$1 \ `ls -dr ../../$1*[[0-9]].[[0-9]]*.[[0-9]]* 2>/dev/null` \ `ls -dr ../../$1*[[0-9]].[[0-9]][[0-9]] 2>/dev/null` \ `ls -dr ../../$1*[[0-9]].[[0-9]] 2>/dev/null` \ `ls -dr ../../$1*[[0-9]].[[0-9]]* 2>/dev/null` \ ../../../$1 \ `ls -dr ../../../$1*[[0-9]].[[0-9]]*.[[0-9]]* 2>/dev/null` \ `ls -dr ../../../$1*[[0-9]].[[0-9]][[0-9]] 2>/dev/null` \ `ls -dr ../../../$1*[[0-9]].[[0-9]] 2>/dev/null` \ `ls -dr ../../../$1*[[0-9]].[[0-9]]* 2>/dev/null` \ ${srcdir}/../$1 \ `ls -dr ${srcdir}/../$1*[[0-9]].[[0-9]]*.[[0-9]]* 2>/dev/null` \ `ls -dr ${srcdir}/../$1*[[0-9]].[[0-9]][[0-9]] 2>/dev/null` \ `ls -dr ${srcdir}/../$1*[[0-9]].[[0-9]] 2>/dev/null` \ `ls -dr ${srcdir}/../$1*[[0-9]].[[0-9]]* 2>/dev/null` \ ; do if test -f "$i/$1Config.sh" ; then ac_cv_c_$1config=`(cd $i; pwd)` break fi if test -f "$i/unix/$1Config.sh" ; then ac_cv_c_$1config=`(cd $i/unix; pwd)` break fi done fi # check in a few common install locations if test x"${ac_cv_c_$1config}" = x ; then for i in `ls -d ${libdir} 2>/dev/null` \ `ls -d ${exec_prefix}/lib 2>/dev/null` \ `ls -d ${prefix}/lib 2>/dev/null` \ `ls -d /usr/local/lib 2>/dev/null` \ `ls -d /usr/contrib/lib 2>/dev/null` \ `ls -d /usr/lib 2>/dev/null` \ ; do if test -f "$i/$1Config.sh" ; then ac_cv_c_$1config=`(cd $i; pwd)` break fi done fi ]) if test x"${ac_cv_c_$1config}" = x ; then $1_BIN_DIR="# no $1 configs found" AC_MSG_WARN([Cannot find $1 configuration definitions]) exit 0 else no_$1= $1_BIN_DIR=${ac_cv_c_$1config} AC_MSG_RESULT([found $$1_BIN_DIR/$1Config.sh]) fi fi ]) #------------------------------------------------------------------------ # TEA_LOAD_CONFIG -- # # Load the $1Config.sh file # # Arguments: # # Requires the following vars to be set: # $1_BIN_DIR # # Results: # # Subst the following vars: # $1_SRC_DIR # $1_LIB_FILE # $1_LIB_SPEC # #------------------------------------------------------------------------ AC_DEFUN(TEA_LOAD_CONFIG, [ AC_MSG_CHECKING([for existence of ${$1_BIN_DIR}/$1Config.sh]) if test -f "${$1_BIN_DIR}/$1Config.sh" ; then AC_MSG_RESULT([loading]) . ${$1_BIN_DIR}/$1Config.sh else AC_MSG_RESULT([file not found]) fi # # If the $1_BIN_DIR is the build directory (not the install directory), # then set the common variable name to the value of the build variables. # For example, the variable $1_LIB_SPEC will be set to the value # of $1_BUILD_LIB_SPEC. An extension should make use of $1_LIB_SPEC # instead of $1_BUILD_LIB_SPEC since it will work with both an # installed and uninstalled version of Tcl. # if test -f ${$1_BIN_DIR}/Makefile ; then AC_MSG_WARN([Found Makefile - using build library specs for $1]) $1_LIB_SPEC=${$1_BUILD_LIB_SPEC} $1_STUB_LIB_SPEC=${$1_BUILD_STUB_LIB_SPEC} $1_STUB_LIB_PATH=${$1_BUILD_STUB_LIB_PATH} fi AC_SUBST($1_VERSION) AC_SUBST($1_BIN_DIR) AC_SUBST($1_SRC_DIR) AC_SUBST($1_LIB_FILE) AC_SUBST($1_LIB_SPEC) AC_SUBST($1_STUB_LIB_FILE) AC_SUBST($1_STUB_LIB_SPEC) AC_SUBST($1_STUB_LIB_PATH) ]) #------------------------------------------------------------------------ # TEA_PATH_CELIB -- # # Locate Keuchel's celib emulation layer for targeting Win/CE # # Arguments: # none # # Results: # # Adds the following arguments to configure: # --with-celib=... # # Defines the following vars: # CELIB_DIR Full path to the directory containing # the include and platform lib files #------------------------------------------------------------------------ AC_DEFUN(TEA_PATH_CELIB, [ # First, look for one uninstalled. # the alternative search directory is invoked by --with-celib if test x"${no_celib}" = x ; then # we reset no_celib in case something fails here no_celib=true AC_ARG_WITH(celib,[ --with-celib=DIR use Windows/CE support library from DIR], with_celibconfig=${withval}) AC_MSG_CHECKING([for Windows/CE celib directory]) AC_CACHE_VAL(ac_cv_c_celibconfig,[ # First check to see if --with-celibconfig was specified. if test x"${with_celibconfig}" != x ; then if test -d "${with_celibconfig}/inc" ; then ac_cv_c_celibconfig=`(cd ${with_celibconfig}; pwd)` else AC_MSG_ERROR([${with_celibconfig} directory doesn't contain inc directory]) fi fi # then check for a celib library if test x"${ac_cv_c_celibconfig}" = x ; then for i in \ ../celib-palm-3.0 \ ../celib \ ../../celib-palm-3.0 \ ../../celib \ `ls -dr ../celib-*3.[[0-9]]* 2>/dev/null` \ ${srcdir}/../celib-palm-3.0 \ ${srcdir}/../celib \ `ls -dr ${srcdir}/../celib-*3.[[0-9]]* 2>/dev/null` \ ; do if test -d "$i/inc" ; then ac_cv_c_celibconfig=`(cd $i; pwd)` break fi done fi ]) if test x"${ac_cv_c_celibconfig}" = x ; then AC_MSG_ERROR([Cannot find celib support library directory]) else no_celib= CELIB_DIR=${ac_cv_c_celibconfig} CELIB_DIR=`echo "$CELIB_DIR" | sed -e 's!\\\!/!g'` AC_MSG_RESULT([found $CELIB_DIR]) fi fi ]) # Local Variables: # mode: autoconf # End: �����������������������������������������������������������������������������������������������tkHTML-4ee7aaa953d6cb59/tests�����������������������������������������������������������������������0000755�0000000�0000000�00000000000�11512242631�0015200�5����������������������������������������������������������������������������������������������������ustar�00nobody��������������������������nobody�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������tkHTML-4ee7aaa953d6cb59/tests/README����������������������������������������������������������������0000644�0000000�0000000�00000000065�11512242631�0016140�0����������������������������������������������������������������������������������������������������ustar�00nobody��������������������������nobody����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������� This directory contains tests for Tkhtml3 and Hv3. ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������tkHTML-4ee7aaa953d6cb59/tests/all.tcl���������������������������������������������������������������0000644�0000000�0000000�00000000402�11512242631�0016527�0����������������������������������������������������������������������������������������������������ustar�00nobody��������������������������nobody����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������� proc sourcefile {file} { set fname [file join [file dirname [info script]] $file] uplevel #0 [list source $fname] } sourcefile common.tcl sourcefile tree.test sourcefile style.test sourcefile dynamic.test sourcefile options.test catch { destroy . } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������tkHTML-4ee7aaa953d6cb59/tests/all.test��������������������������������������������������������������0000644�0000000�0000000�00000000242�11512242631�0016726�0����������������������������������������������������������������������������������������������������ustar�00nobody��������������������������nobody�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������# Run all tests # cd [file dirname $argv0] set me [file tail $argv0] foreach file [lsort -dictionary [glob *.test]] { if {$file==$me} continue source $file } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������tkHTML-4ee7aaa953d6cb59/tests/autotest.test���������������������������������������������������������0000644�0000000�0000000�00000001040�11512242631�0020023�0����������������������������������������������������������������������������������������������������ustar�00nobody��������������������������nobody����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������� if {[info exists INAUTOTEST]} return set testdir [file dirname [info script]] set files [list \ tree.test \ style.test \ ] ########################################################################### catch {memory init on} set auto_path [concat . $auto_path] package require Tkhtml package require tcltest tcltest::configure -verbose {body error pass} set INAUTOTEST 1 if {![info exists INTEST]} { foreach f $files { if {[catch {source $testdir/$f} msg]} { puts stderr $msg } } exit } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������tkHTML-4ee7aaa953d6cb59/tests/browsertest.tcl�������������������������������������������������������0000644�0000000�0000000�00000022330�11512242631�0020346�0����������������������������������������������������������������������������������������������������ustar�00nobody��������������������������nobody����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������� #---------------------------------------------------------------------- # DEFAULT BROWSER CONFIGURATION: # # This should be edited for site-specific browsers. On SUSE linux # the following works: # # lappend BROWSERS Firefox {/usr/lib/firefox/firefox-bin} lappend BROWSERS Firefox {/home/dan/sw/firefox/firefox-bin} if {![info exists env(LD_LIBRARY_PATH)]} { set env(LD_LIBRARY_PATH) "" } set env(LD_LIBRARY_PATH) $env(LD_LIBRARY_PATH):/home/dan/sw/firefox/ lappend BROWSERS Hv3 {./hwish ../htmlwidget/hv/hv3_main.tcl} lappend BROWSERS Opera {opera -nosession} set DEFAULT_BROWSERS [list Hv3 Firefox] #---------------------------------------------------------------------- # TEST ARCHITECTURE OVERVIEW: # # This program is a driver for a browser compatibility test framework. # In this framework, each test is specified as follows: # # A) A single HTML document. The document must contain the # following element in the head section: # # <SCRIPT src="/get_framework"></SCRIPT> # # The document should have no other external dependancies. The # <BODY> element should not have an onLoad event handler defined. # # B) The definition of a javascript function called "browser_test". # For example: # # function browser_test () { return document.images.length } # # # A test case is executed as follows: # # 1. A web-browser process is started. The browser connects to an # HTTP server embedded in the test driver (this script) and # retrieves the test document (A). # # 2. The <SCRIPT> tag in the test document causes the browser # to retrieve a javascript program from the same embedded # server. The browser_test() function is part of the # javascript program. # # 3. An "onLoad" event on the <BODY> of the test document in the # browser causes it to execute the browser_test() function. # The return value of browser_test() is converted to a string # and an HTTP GET request made to a URI of the form: # # /test_result?result=<Result of browser_test()> # # 4. Once the above request is seen by the embedded web-server, # the web-browser process is halted. # # Tcl proc [::browsertest::run] implements this procedure. # # The above 4 steps should be repeated with 2 or more browsers. The # strings returned by the browser_test() function are compared to # determine browser compatibility. Tcl proc [::browser::do_test] # implements this in terms of [::browsertest::run]. # #---------------------------------------------------------------------- # INTERFACE: # # ::browsertest::run BROWSER TIMEOUT DOCUMENT FUNCTION # # The low level interface. Execute a single test-case in a single # browser instance. # # # # ::browsertest::do_test NAME OPTIONS # # -browsers BROWSER-LIST (default is all configured) # -html HTML-DOCUMENT-BODY (default is "") # -timeout TIMEOUT (default is 10000) # -expected STRING (if not specified do not use) # -javascript SCRIPT-FUNCTION-BODY (mandatory) # # High level interface. # namespace eval browsertest { variable listen_socket "" ;# Socket returned by [socket -server] variable listen_port "" ;# Port number $listen_socket is listening on. variable test_document "" ;# Document for a "GET /get_test" request. variable test_script "" ;# Document for a "GET /get_script" request. variable test_result "" ;# Value returned by browser_test() # If the following variable is not set to an empty string, then # it is a [string match] style pattern applied to the name of each # test before it is executed. If the test-name does not match # the pattern, the test will not be executed. # # Note that this applies to invocations of [::browsertest::do_test] # only, [::browsertest::run] will still run anything passed to it. # variable pattern "" proc Init {} { variable listen_port variable listen_socket if {$listen_socket eq ""} { set cmd [namespace code Accept] set listen_socket [socket -server $cmd -myaddr 127.0.0.1 0] set listen_port [lindex [fconfigure $listen_socket -sockname] 2] } } proc Accept {sock host path} { fconfigure $sock -blocking 0 fileevent $sock readable [namespace code [list Request $sock]] } proc HttpResponse {sock content_type content} { set r "" append r "HTTP/1.0 200 OK\n" append r "Content-type: $content_type\n" append r "\n" append r "$content" append r "\n" puts -nonewline $sock $r close $sock } proc Decode {component} { set zIn $component set zOut "" while {[regexp {^([^%]*)(%..)(.*)$} $zIn -> start esc tail]} { append zOut $start set zIn $tail set hex "0x[string range $esc 1 end]" append zOut [format %c $hex] } append zOut $zIn return $zOut } proc Request {sock} { variable test_document variable test_script variable test_result set line [gets $sock] if {[fblocked $sock]} return if {[eof $sock]} { close $sock return } if {[regexp {^GET.*get_test} $line]} { HttpResponse $sock text/html $test_document } elseif {[regexp {^GET.*get_framework} $line]} { HttpResponse $sock text/javascript $test_script } elseif {[regexp {^GET.*test_result.result=([^ ]*)} $line -> result]} { set test_result [Decode $result] close $sock } elseif {[regexp {^GET.*} $line]} { close $sock } } # run -- # # run BROWSER TIMEOUT DOCUMENT FUNCTION # proc run {browser timeout document function} { variable listen_port variable test_document variable test_script variable test_result # Set up the listening socket (if it is not already ready) Init # Set the global variable $test_document. This is the content that # will be returned to a request on the /get_test URI. # set test_document $document # Set up the script infrastructure: set test_script $function append test_script "\n" append test_script { function run_browser_test() { result = browser_test().toString() enc_result = encodeURIComponent(result); req = new XMLHttpRequest() req.open("GET", "/test_result?result=" + enc_result) req.send("") } window.onload = run_browser_test } # If the specified browser is not in the global $::BROWSERS array, # raise a Tcl exception. # array set b $::BROWSERS if {![info exists b($browser)]} { error "No such configured browser: $browser" } # [exec] the browser. Load the /get_test URI initially. # after 500 set doc_uri "http://127.0.0.1:$listen_port/get_test" set pid [eval exec $b($browser) [list $doc_uri] &] set timeout_msg "BROWSER TIMEOUT ($timeout ms)" set afterscript [list set [namespace current]::test_result $timeout_msg] after $timeout $afterscript set test_result "" vwait [namespace current]::test_result after cancel $afterscript # [kill] the browser process. # exec kill $pid return $test_result } proc do_test {name args} { variable pattern if {$pattern ne "" && ![string match $pattern $name]} return # Argument processing: # set opts(-browsers) $::DEFAULT_BROWSERS set opts(-timeout) 10000 set opts(-html) "" array set opts $args if {![info exists opts(-javascript)]} { error "Missing mandatory -javascript option" } foreach option [array names opts] { switch -- $option { -browsers {} -timeout {} -html {} -javascript {} -expected {set results(Expected) $opts(-expected)} default { error "Unknown option: $option" } } } puts -nonewline "$name ." flush stdout # Figure out the complete HTML test document # set html {<HTML><HEAD><SCRIPT src="/get_framework"></SCRIPT></HEAD>} append html $opts(-html) # Figure out the complete javascript test function # set javascript "function browser_test () {\n" append javascript $opts(-javascript) append javascript "\n}\n" foreach browser $opts(-browsers) { set res [run $browser $opts(-timeout) $html $javascript] set results($browser) $res puts -nonewline "." flush stdout } set ok 1 foreach browser [array names results] { if {$results($browser) ne $res} {set ok 0} } if {$ok} { puts " Ok ($opts(-browsers))" } else { puts " Error:" foreach browser [lsort [array names results]] { puts [format { %-10s {%s}} ${browser}: $results($browser)] } } } } proc usage {} { puts stderr "Usage: " puts stderr " $::argv0 ?PATTERN?" exit } proc main {args} { if {[llength $args] > 1} usage set ::browsertest::pattern [lindex $args 0] source [file join [file dirname [info script]] tree1.bt] source [file join [file dirname [info script]] node.bt] source [file join [file dirname [info script]] events.bt] source [file join [file dirname [info script]] style.bt] source [file join [file dirname [info script]] form.bt] } eval main $argv ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������tkHTML-4ee7aaa953d6cb59/tests/canvas.tcl������������������������������������������������������������0000644�0000000�0000000�00000014706�11512242631�0017246�0����������������������������������������������������������������������������������������������������ustar�00nobody��������������������������nobody����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������� # catch {memory init on} # catch {memory onexit mem.out} # catch {memory validate on} # Required packages set auto_path [concat . $auto_path] package require Tkhtml catch { package require Img } # Procedure to return the contents of a file-system entry proc readFile {fname} { set ret {} catch { set fd [open $fname] set ret [read $fd] close $fd } return $ret } proc tree_to_html {indent tree} { set in [string repeat " " $indent] if {[regexp {^TEXT} $tree]} { puts -nonewline "$in" puts $tree } else { set tag [lindex $tree 0] puts "$in<$tag>" foreach child [lindex $tree 1] { tree_to_html [expr $indent + 2] $child } puts "$in</$tag>" } } proc scriptcommand {line_number tag tarargs script} { if {$tag=="style"} { append ::STYLE_TEXT $script puts $script } return "" } proc stylecmd {style} { append ::STYLE_TEXT $style append ::STYLE_TEXT "\n" return "" } proc scriptcmd {script} { return "" } proc linkcmd {node} { set rel [string tolower [$node attr rel]] set media [string tolower [$node attr media]] set media_list [list all visual screen ""] if {[string compare $rel stylesheet]==0 && [lsearch $media_list $media]!=-1} { set href [$node attr href] set filename [file join $::BASE $href] lappend ::STYLESHEET_FILES $filename } } set HTML .h proc main {document css} { html $::HTML $::HTML handler script script dummycmd $::HTML handler script style stylecmd $::HTML handler node link linkcmd set ::STYLESHEET_FILES {} set ::STYLE_TEXT {} set parsetime [time { $::HTML parse $document $::HTML style parse agent $css while {[llength $::STYLESHEET_FILES]>0} { set ss [lindex $::STYLESHEET_FILES 0] set ::STYLESHEET_FILES [lrange $::STYLESHEET_FILES 1 end] $::HTML style parse author [readFile $ss] } $::HTML style parse author $::STYLE_TEXT }] puts "Parse time [lrange $parsetime 0 1]" $::HTML style parse author.1 { img { -tkhtml-replace: tcl(replace_img) } object { -tkhtml-replace: tcl(replace_img) } input { -tkhtml-replace: tcl(replace_input) } select { -tkhtml-replace: tcl(replace_select) } } set s [$::HTML style syntax_errs] puts "$s syntax errors in style sheet" set styletime [time { $::HTML style apply }] puts "Style time [lrange $styletime 0 1]" } set W 800 proc redraw {{w 0}} { if {$w==0} { set w $::W } else { set ::W $w } set codetime [time {$::HTML layout force -width $w -win .c}] puts "Layout time [lrange $codetime 0 1]" set tclizetime [time {set code [$::HTML layout primitives]}] puts "Tclize time [lrange $tclizetime 0 1]" set drawtime [time {draw_to_canvas $code .c 0 0}] puts "Draw time [lrange $drawtime 0 1]" } proc replace_img {node} { if {[$node tag]=="object"} { set filename [file join $::BASE [$node attr data]] } else { set filename [file join $::BASE [$node attr src]] } if [catch { set img [image create photo -file $filename] } msg] { puts "Error: $msg" error $msg } return $img } set CONTROL 0 proc replace_input {node} { set tkname ".control[incr ::CONTROL]" set width [$node attr width] if {$width==""} { set width 20 } switch -exact [$node attr type] { image { return [replace_img $node] } hidden { return "" } checkbox { return [checkbutton $tkname] } radio { return [checkbutton $tkname] } submit { return [button $tkname -text Submit] } default { entry $tkname -width $width return $tkname } } return "" } proc replace_select {node} { set tkname ".control[incr ::CONTROL]" button $tkname -text Select return $tkname } proc draw_origin {x y} { upvar X X upvar Y Y upvar C C incr X $x incr Y $y } proc draw_text {x y font color string} { upvar X X upvar Y Y upvar C C incr x $X incr y $Y # The Y coordinate supplied by the layout code is for the baseline of the # text item. The canvas widget doesn't support this, so decrement Y by # the font metric 'ascent' value and anchor the nw corner of the text to # simulate it. set ascent [font metrics $font -ascent] incr y [expr -1*$ascent] $C create text $x $y -font $font -fill $color -text $string -anchor nw } proc draw_quad {x1 y1 x2 y2 x3 y3 x4 y4 color} { upvar X X upvar Y Y upvar C C foreach v {x1 x2 x3 x4} {incr $v $X} foreach v {y1 y2 y3 y4} {incr $v $Y} $C create polygon $x1 $y1 $x2 $y2 $x3 $y3 $x4 $y4 -fill $color } proc draw_image {x y image} { upvar X X upvar Y Y upvar C C incr x $X incr y $Y $C create image $x $y -image $image -anchor nw } proc draw_window {x y window} { upvar X X upvar Y Y upvar C C incr x $X incr y $Y $C create window $x $y -window $window -anchor nw } proc draw_background {color} { upvar C C $C configure -background $color } proc draw_to_canvas {code c x y} { $c delete all set X $x set Y $y set C $c foreach instruction $code { # puts $instruction eval $instruction } set scrollregion [$c bbox all] if {[llength $scrollregion]==4} { lset scrollregion 0 0 lset scrollregion 1 0 $c configure -scrollregion $scrollregion } puts "Scrollregion: $scrollregion" } proc new_document {{r 1}} { # catch {destroy $::HTML} if {[llength $::DOCS]==0} { rename $::HTML {} exit } set ::BASE [file dirname [lindex $::DOCS 0]] main [readFile [lindex $::DOCS 0]] $::CSS set ::DOCS [lrange $::DOCS 1 end] if {$r} redraw } wm geometry . 800x600 frame .buttons button .buttons.correct -text Incorrect -command new_document button .buttons.incorrect -text Correct -command new_document pack .buttons.correct .buttons.incorrect -side left pack .buttons -side bottom -fill x scrollbar .s -orient vertical scrollbar .s2 -orient horizontal canvas .c -background grey pack .s -side right -fill y pack .s2 -side bottom -fill x pack .c -fill both -expand true .c configure -yscrollcommand {.s set} .c configure -xscrollcommand {.s2 set} .s configure -command {.c yview} .s2 configure -command {.c xview} bind .c <Configure> {redraw [expr %w - 5]} bind .c <KeyPress-Down> {.c yview scroll 1 units} bind .c <KeyPress-Up> {.c yview scroll -1 units} focus .c set cssfile [file join [file dirname [info script]] html.css] set CSS [readFile $cssfile] set arg [lindex $argv 0] if {[file isdirectory $arg]} { set DOCS [lsort [glob [file join [lindex $argv 0] *.html]]] } else { set DOCS $arg } new_document 0 ����������������������������������������������������������tkHTML-4ee7aaa953d6cb59/tests/common.tcl������������������������������������������������������������0000644�0000000�0000000�00000000571�11512242631�0017256�0����������������������������������������������������������������������������������������������������ustar�00nobody��������������������������nobody����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������� package require Tkhtml package require tcltest tcltest::verbose {pass body error} catch {rename finish_test ""} if {[catch {incr ::nested_test_count}]} {set ::nested_test_count 1} proc finish_test {} { catch { destroy .h } incr ::nested_test_count -1 if {$::nested_test_count == 0} { catch { destroy . catch {::tkhtml::htmlalloc} } } } ���������������������������������������������������������������������������������������������������������������������������������������tkHTML-4ee7aaa953d6cb59/tests/dynamic.test����������������������������������������������������������0000644�0000000�0000000�00000004736�11512242631�0017616�0����������������������������������������������������������������������������������������������������ustar�00nobody��������������������������nobody����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������� # Test script for Tkhtml proc sourcefile {file} { set fname [file join [file dirname [info script]] $file] uplevel #0 [list source $fname] } sourcefile common.tcl html .h .h handler script style styleHandler proc styleHandler {data} { .h style $data } proc property {node prop} { array set properties [$node prop] return $properties($prop) } tcltest::test dynamic-1.0 {} -body { .h reset .h parse -final { <html> <body> <a>Some Text</a> <b>Some Text</b> </html> } set ::node_a [lindex [.h search a] 0] set ::node_b [lindex [.h search b] 0] $::node_a dynamic set } -result {} tcltest::test dynamic-1.1 {} -body { $::node_b dynamic set } -result {} tcltest::test dynamic-1.2 {} -body { $::node_a dynamic set hover } -result {hover} tcltest::test dynamic-1.3 {} -body { $::node_a dynamic set } -result {hover} tcltest::test dynamic-2.0 {} -body { .h reset .h parse -final { <html> <style> :hover {color:white} </style> <body> <a>Some Text</a> </html> } set ::node [lindex [.h search a] 0] property $::node color } -result {black} tcltest::test dynamic-2.1 {} -body { $::node dynamic set hover $::node dynamic set } -result {hover} tcltest::test dynamic-2.2 {} -body { property $::node color } -result {white} tcltest::test dynamic-3.0 {} -body { .h reset .h parse -final { <html> <style> a:link {color:white} a:visited {color:blue} a {color:black} </style> <body> <a>Some Text</a> </html> } set ::node [lindex [.h search a] 0] property $::node color } -result {black} tcltest::test dynamic-3.1 {} -body { $::node dynamic set visited $::node dynamic set } -result visited tcltest::test dynamic-3.2 {} -body { property $::node color } -result {blue} tcltest::test dynamic-3.3 {} -body { $::node dynamic set link property $::node color } -result {blue} tcltest::test dynamic-3.4 {} -body { $::node dynamic clear visited property $::node color } -result {white} tcltest::test dynamic-3.5 {} -body { $::node dynamic clear link $::node dynamic set } -result {} tcltest::test dynamic-3.6 {} -body { property $::node color } -result {black} tcltest::test dynamic-4.0 {} -body { .h reset .h parse -final { <html> <style> body a:hover {color:red} </style> <body> <a>Some Text</a> </html> } set ::node [lindex [.h search a] 0] $::node dynamic conditions } -result {:link {body a:hover}} finish_test ����������������������������������tkHTML-4ee7aaa953d6cb59/tests/encoding.bt�����������������������������������������������������������0000644�0000000�0000000�00000006214�11512242631�0017377�0����������������������������������������������������������������������������������������������������ustar�00nobody��������������������������nobody����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������� # This test script tests some browser behaviour related to encodings # (charsets). Test plan is as follows: # # encoding.1.* - Test that charsets specified as both HTTP # Content-Type headers or their <meta> tag equivalents # are handled. # # encoding.2.* - Test that Hv3 works around the polipo bug. This is # only really important for Hv3. # set str "\xC0\xC1" set encoding.1.javascript { var div = document.getElementById("div"); var str = div.firstChild.data return str.charCodeAt(0) + "." + str.charCodeAt(1) } #-------------------------------------------------------------------------- # START encoding.1.* # # Test with no <meta> tag and no Content-Type header. # do_browser_test encoding.1.1 -html [subst { <DIV id="div">[encoding convertto iso8859-1 $str]</DIV> }] -javascript ${encoding.1.javascript} # Test with a <meta> tag only. # do_browser_test encoding.1.2 -html [subst { <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <DIV id="div">[encoding convertto utf-8 $str]</DIV> }] -javascript ${encoding.1.javascript} # Test with Content-Type header only. # do_browser_test encoding.1.3 -encoding utf-8 -html [subst { <DIV id="div">[encoding convertto utf-8 $str]</DIV> }] -javascript ${encoding.1.javascript} # Test with Content-Type and matching <meta> tag. # do_browser_test encoding.1.4 -encoding utf-8 -html [subst { <META http-equiv="Content-Type" content="text/html; charset=utf-8" > <DIV id="div">[encoding convertto utf-8 $str]</DIV> }] -javascript ${encoding.1.javascript} # Test with Content-Type and conflicting <meta> tag. In this case the # Content-Type should take precedence. Previous versions of Hv3 had # this wrong. # do_browser_test encoding.1.5 -encoding utf-8 -html [subst { <META http-equiv="Content-Type" content="text/html; charset=windows-1252"> <DIV id="div">[encoding convertto utf-8 $str]</DIV> }] -javascript ${encoding.1.javascript} # Test with an incorrect <meta> tag only. In this case firefox does not # do any encoding detection - it just uses the explicitly specified # one in the same way as Hv3. # do_browser_test encoding.1.6 -html [subst { <meta http-equiv="Content-Type" content="text/html; charset=windows-1252"> <DIV id="div">[encoding convertto utf-8 $str]</DIV> }] -javascript ${encoding.1.javascript} # # END encoding.1.* #-------------------------------------------------------------------------- proc enc_slow_css {channel} { enc_slow_part1 $channel { HTTP/1.1 200 OK Content-type: text/css Cache-Control: s-maxage=10 .hello { color: green } } { .tall { height: 500px } } } proc enc_slow_part1 {channel data1 data2} { puts -nonewline $channel [string trimleft $data1] flush $channel after 1000 [list enc_slow_part2 $channel $data2] } proc enc_slow_part2 {channel data} { puts -nonewline $channel $data flush $channel close $channel } do_browser_test encoding.2.1 -html { <style> @import "/tcl?script=enc_slow_css" ; </style> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <DIV id="div" class="tall">... </DIV> } -javascript { return document.getElementById("div").offsetHeight } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������tkHTML-4ee7aaa953d6cb59/tests/engine.tcl������������������������������������������������������������0000644�0000000�0000000�00000010336�11512242631�0017233�0����������������������������������������������������������������������������������������������������ustar�00nobody��������������������������nobody�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������# This file contains the test driver for the html widget. It defines # a special version of the test procedure to use for testing the # html widget. # # $Id: engine.tcl,v 1.2 2003/01/28 05:01:05 hkoba Exp $ # Make sure the html widget is loaded into # our interpreter # if {[info command html]==""} { if {[catch {package require Tkhtml} error]} { foreach f { ./libTkhtml*.so ../libTkhtml*.so /usr/lib/libTkhtml*.so /usr/local/lib/libTkhtml*.so ./tkhtml.dll } { if {[set f [lindex [glob -nocomplain $f] end]] != ""} { if {[catch {load $f Tkhtml}]==0} break } } } } # Initialize variables # namespace eval tcltest { set mode run set current {} set passed 0 set failed 0 set total 0 set status {} } # Arguments: # # tag A symbolic tag for this test. Ex: html-1.0 # # desc A human-readable description of what this test does. # # script Tcl code to implement the test # # result The expected result from this test. If the actual result # is different the test fails. # proc ::tcltest::test {tag desc script result} { ::tcltest::change-desc $tag $desc if {[info exists ::tcltest::idle]} { catch {after cancel $::tcltest::idle} catch {unset ::tcltest::idle} } set rc [catch {uplevel #0 $script} msg] set r [list $rc $msg] if {$r==$result} { incr ::tcltest::passed puts "---- Test $tag passed" } else { incr ::tcltest::failed puts "**** Test $tag failed" puts "Expected: [list $result]" puts "Got: [list $r]" } incr ::tcltest::total ::tcltest::update-status set ::tcltest::idle [after 100 ::tcltest::testing-complete] } # Create the test control window # proc ::tcltest::mainwin {} { set w .testinfo toplevel $w wm title $w {Html Widget Test Information} wm iconname $w {Html-Test} set f $w.f1 frame $f pack $f -side top -fill x label $f.l -text {Status: } label $f.v -textvariable ::tcltest::status pack $f.l $f.v -side left set f $w.f2 frame $f pack $f -side top -fill x label $f.l -text {Current Test: } label $f.v -textvariable ::tcltest::current pack $f.l $f.v -side left set f $w.b frame $f pack $f -side bottom -fill x button $f.pause -text Pause -command ::tcltest::pause button $f.pass -text {Pass} -command {::tcltest::set-result pass} button $f.fail -text {Fail} -command {::tcltest::set-result fail} button $f.exit -text Exit -command exit pack $f.pause $f.pass $f.fail $f.exit -side right -pady 10 -expand 1 scrollbar $w.sb -orient vertical -command "$w.t yview" pack $w.sb -side right -fill y html $w.t -yscrollcommand "$w.sb set" -width 400 -height 150 \ -bd 2 -relief sunken -padx 5 -pady 5 pack $w.t -side right -fill both -expand 1 ::tcltest::update-status } # Change the test description in the control window # proc ::tcltest::change-desc {tag desc} { if {![winfo exists .testinfo]} ::tcltest::mainwin .testinfo.t clear .testinfo.t parse $desc\n set ::tcltest::current $tag } # Update the status line # proc ::tcltest::update-status {} { set v "$::tcltest::passed passed $::tcltest::failed failed " append v "$::tcltest::total total" set ::tcltest::status $v } # Wait for the user to press either the pass or failed buttons. # proc ::tcltest::user-result {} { .testinfo.b.pass config -state normal .testinfo.b.fail config -state normal update raise .testinfo focus .testinfo.b.pass set ::tcltest::result {} vwait ::tcltest::result .testinfo.b.pass config -state disabled .testinfo.b.fail config -state disabled return $::tcltest::result } # Called when the user presses either the failed or passed buttons. # proc ::tcltest::set-result v { set ::tcltest::result $v } # Call this routine at the end of all tests # proc ::tcltest::testing-complete {} { ::tcltest::change-desc {} {Testing is now complete} } # Construct an HTML widget to use for testing. # proc tkhtml_test_widget {} { set w .tkhtml_test if {[winfo exists $w]} { return $w.h } toplevel $w wm title $w {TkHtml Test Widget} wm iconname $w {TkHtml Test} scrollbar $w.sb -orient vertical -command "$w.h yview" pack $w.sb -side right -fill y html $w.h -yscrollcommand "$w.sb set" pack $w.h -side right -fill both -expand 1 return $w.h } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������tkHTML-4ee7aaa953d6cb59/tests/events.bt�������������������������������������������������������������0000644�0000000�0000000�00000003755�11512242631�0017124�0����������������������������������������������������������������������������������������������������ustar�00nobody��������������������������nobody����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������� if 0 {_ #------------------------------------------------------------------------ # This is a "warm-body" test for the events module. # ::browsertest::do_test events.1 -timeout 10000000 -html { <BODY> <SCRIPT> document.testlog = "" function log_node(elem) { if (document.testlog != "") document.testlog += " " document.testlog += elem.id } </SCRIPT> <DIV id="one" onclick="log_node(this)"> <DIV id="two" onclick="log_node(this)"> <DIV id="three" onclick="log_node(this)"> Hello Hello } -javascript { /* Create a synthetic mouse event. */ var e = document.createEvent("MouseEvents") e.initMouseEvent( "click", true, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null ); /* Dispatch the event to the <DIV id="three"> element. It should * bubble up through <DIV id="two"> and <DIV id="one" blocks. */ document.getElementById("three").dispatchEvent(e) return document.testlog } -expected "three two one" } proc slow_html {channel} { puts SLOWHTML slow_part1 $channel { HTTP/1.1 200 OK Content-type: text/html Cache-Control: no-cache <p> Paragraph 1</p> } { <p> Paragraph 2</p> } } proc slow_css {channel} { slow_part1 $channel { HTTP/1.1 200 OK Content-type: text/css Cache-Control: no-cache } { .tall { height: 500px } } } proc slow_part1 {channel data1 data2} { puts -nonewline $channel [string trimleft $data1] flush $channel after 1000 [list slow_part2 $channel $data2] } proc slow_part2 {channel data} { puts -nonewline $channel $data flush $channel close $channel } # This is to test that the browser waits until all stylesheets are # downloaded and applied before firing the "onload" event. # do_browser_test events.1 -timeout 10000000 -html { <STYLE> @import "/tcl?script=slow_css"; div { height: 50px } </STYLE> <BODY> <DIV class="tall" id="me">hello</DIV> } -javascript { var div = document.getElementById("me") return div.offsetHeight } �������������������tkHTML-4ee7aaa953d6cb59/tests/form.bt���������������������������������������������������������������0000644�0000000�0000000�00000002300�11512242631�0016544�0����������������������������������������������������������������������������������������������������ustar�00nobody��������������������������nobody����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������� # # The focus of this module is the HTMLFormElement object - the # thing created by a <FORM> tag in a document. # set ::Doc { <HTML> <BODY> <FORM name=one> <INPUT type=text name="i_one"></INPUT> <INPUT type=text name="i_one"></INPUT> <INPUT type=text name="i_two"></INPUT> <INPUT type=text id="i_three"></INPUT> <INPUT type=text name="i_four"></INPUT> <INPUT type=text id="i_four"></INPUT> </FORM> </BODY> </HTML> } # forms.one.i_one -> NodeList # forms.one.i_two -> HTMLInputElement # forms.one.i_three -> HTMLInputElement # forms.one.i_four -> NodeList # The reference to forms[0].i_one is a collection, because # there is more than one element named i_one. # do_browser_test forms.1 -html $::Doc -javascript { return document.forms.one.i_one.length } -expected 2 # But forms[0].i_two is the HTMLInputElement. # do_browser_test forms.2 -html $::Doc -javascript { return document.forms[0].i_two.type } -expected "text" do_browser_test forms.3 -html $::Doc -javascript { return document.forms[0].i_three.type } -expected "text" do_browser_test forms.4 -html $::Doc -javascript { return document.forms[0].i_four.length } -expected 2 ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������tkHTML-4ee7aaa953d6cb59/tests/html.css��������������������������������������������������������������0000644�0000000�0000000�00000020731�11512242631�0016740�0����������������������������������������������������������������������������������������������������ustar�00nobody��������������������������nobody�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Display types for non-table items. */ ADDRESS, BLOCKQUOTE, BODY, DD, DIV, DL, DT, FIELDSET, FRAME, FRAMESET, H1, H2, H3, H4, H5, H6, NOFRAMES, OL, P, UL, APPLET, CENTER, DIR, HR, MENU, PRE { display: block } HEAD, SCRIPT, TITLE { display: none } BODY { margin: 8px; } /* Rules for unordered-lists */ LI { display: list-item } UL[type="square"]>LI { list-style-type : square } UL[type="disc"]>LI { list-style-type : disc } UL[type="circle"]>LI { list-style-type : circle } LI[type="circle"] { list-style-type : circle } LI[type="square"] { list-style-type : square } LI[type="disc"] { list-style-type : disc } OL, UL, DIR, MENU, DD { padding-left: 40px ; margin-left: 1em } NOBR { white-space: nowrap; } /* Map the 'align' attribute to the 'float' property. Todo: This should * only be done for images, tables etc. "align" can mean different things * for different elements. */ TABLE[align="left"] { float:left } TABLE[align="right"] { float:right } TABLE[align="center"] { margin-left:auto; margin-right:auto; text-align:left; } IMG[align="left"] { float:left } IMG[align="right"] { float:right } /* If the 'align' attribute was not mapped to float by the rules above, map * it to 'text-align'. The rules above take precedence because of their * higher specificity. * * Also the <center> tag means to center align things. */ [align="center"] { text-align:center } [align="right"] { text-align:right } [align="left"] { text-align:left } CENTER { text-align: center } /* Rules for unordered-lists */ /* Todo! */ TD, TH { padding: 1px; border-bottom-color: grey60; border-right-color: grey60; border-top-color: grey25; border-left-color: grey25; } /* For a horizontal line, use a table with no content. We use a table * instead of a block because tables are laid out around floating boxes, * whereas regular blocks are not. */ /* HR { display: table; border-top: 1px solid grey45; background: grey80; height: 1px; width: 100%; text-align: center; margin: 0.5em 0; } */ HR { display: block; border-top: 1px solid grey45; border-bottom: 1px solid grey80; margin: 0.5em auto 0.5em auto; } /* Basic table tag rules. */ TABLE { display: table; border-spacing: 2px; border-bottom-color: grey25; border-right-color: grey25; border-top-color: grey60; border-left-color: grey60; } TR { display: table-row } THEAD { display: table-header-group } TBODY { display: table-row-group } TFOOT { display: table-footer-group } COL { display: table-column } COLGROUP { display: table-column-group } TD, TH { display: table-cell } CAPTION { display: table-caption } TH { font-weight: bolder; text-align: center } CAPTION { text-align: center } H1 { font-size: 2em; margin: .67em 0 } H2 { font-size: 1.5em; margin: .83em 0 } H3 { font-size: 1.17em; margin: 1em 0 } H4, P, BLOCKQUOTE, UL, FIELDSET, OL, DL, DIR, MENU { margin-top: 1.0em; margin-bottom: 1.0em } H5 { font-size: .83em; line-height: 1.17em; margin: 1.67em 0 } H6 { font-size: .67em; margin: 2.33em 0 } H1, H2, H3, H4, H5, H6, B, STRONG { font-weight: bolder } BLOCKQUOTE { margin-left: 40px; margin-right: 40px } I, CITE, EM, VAR, ADDRESS { font-style: italic } PRE, TT, CODE, KBD, SAMP { font-family: courier } BIG { font-size: 1.17em } SMALL, SUB, SUP { font-size: .83em } SUB { vertical-align: sub } SUP { vertical-align: super } S, STRIKE, DEL { text-decoration: line-through } OL { list-style-type: decimal } OL UL, UL OL, UL UL, OL OL { margin-top: 0; margin-bottom: 0 } U, INS { text-decoration: underline } ABBR, ACRONYM { font-variant: small-caps; letter-spacing: 0.1em } /* Formatting for <pre> etc. */ PRE, PLAINTEXT, XMP { display: block; white-space: pre; margin: 1em 0; font-family: courier; } /* Display properties for hyperlinks */ :link { color: darkblue; text-decoration: underline } /* Deal with the "nowrap" HTML attribute on table cells. */ TD[nowrap] , TH[nowrap] { white-space: nowrap; } TD[nowrap="0"] , TH[nowrap="0"] { white-space: normal; } BR { display: block; } /* BR:before { content: "\A" } */ /* * Default decorations for form items. */ INPUT[type="hidden"] { display: none } INPUT[type] { border: none } INPUT, INPUT[type="text"], INPUT[type="password"] { border: 2px solid; border-color: #848280 #faf9f7 #faf9f7 #848280; } FRAMESET { display: none; } /* ************************************************************************* * Below this point are stylesheet rules for mapping presentational * attributes of Html to CSS property values. Strictly speaking, this * shouldn't be specified here (in the UA stylesheet), but it doesn't matter * in practice. See CSS 2.1 spec for more details. */ /* 'color' */ [color] { color: tcl(::tkhtml::attr color -color) } body a[href]:link { color: tcl(::tkhtml::aa body link -color) } body a[href]:visited { color: tcl(::tkhtml::aa body vlink -color) } /* 'width', 'height', 'background-color' and 'font-size' */ [width] { width: tcl(::tkhtml::attr width -len) } [height] { height: tcl(::tkhtml::attr height -len) } basefont[size] { font-size: tcl(::tkhtml::attr size) } font[size] { font-size: tcl(::tkhtml::attr size) } [bgcolor] { background-color: tcl(::tkhtml::attr bgcolor -color) } BR[clear] { clear: tcl(::tkhtml::attr clear) } BR[clear="all"] { clear: both; } /* Standard html <img> tags - replace the node with the image at url $src */ IMG[src] { -tkhtml-replacement-image: tcl(::tkhtml::attr src) } /* * Properties of table cells (th, td): * * 'border-width' * 'border-style' * 'padding' * 'border-spacing' */ TABLE[border], TABLE[border] TD, TABLE[border] TH { border-top-width: tcl(::tkhtml::aa table border -len); border-right-width: tcl(::tkhtml::aa table border -len); border-bottom-width: tcl(::tkhtml::aa table border -len); border-left-width: tcl(::tkhtml::aa table border -len); border-top-style: tcl(::tkhtml::aa table border -if solid); border-right-style: tcl(::tkhtml::aa table border -if solid); border-bottom-style: tcl(::tkhtml::aa table border -if solid); border-left-style: tcl(::tkhtml::aa table border -if solid); } TABLE[border=""], TABLE[border=""] td, TABLE[border=""] th { border-top-width: tcl(::tkhtml::aa table border -if 1px); border-right-width: tcl(::tkhtml::aa table border -if 1px); border-bottom-width: tcl(::tkhtml::aa table border -if 1px); border-left-width: tcl(::tkhtml::aa table border -if 1px); } TABLE[cellpadding] td, TABLE[cellpadding] th { padding-top: tcl(::tkhtml::aa table cellpadding -len); padding-right: tcl(::tkhtml::aa table cellpadding -len); padding-bottom: tcl(::tkhtml::aa table cellpadding -len); padding-left: tcl(::tkhtml::aa table cellpadding -len); } TABLE[cellspacing], table[cellspacing] { border-spacing: tcl(::tkhtml::attr cellspacing -len); } /* Map the valign attribute to the 'vertical-align' property for table * cells. The default value is "middle", or use the actual value of * valign if it is defined. */ TD,TH {vertical-align: middle} TR[valign]>TD, TR[valign]>TH {vertical-align: tcl(::tkhtml::aa tr valign)} TR>TD[valign], TR>TH[valign] {vertical-align: tcl(::tkhtml::attr valign)} /* Support the "text" attribute on the <body> tag */ body[text] {color: tcl(::tkhtml::attr text -color)} /* Allow background images to be specified using the "background" attribute. * According to HTML 4.01 this is only allowed for <body> elements, but * many websites use it arbitrarily. */ [background] { background-image: tcl(format "url(%s)" [::tkhtml::attr background]) } /* The vspace and hspace attributes map to margins for elements of type * <IMG>, <OBJECT> and <APPLET> only. Note that this attribute is * deprecated in HTML 4.01. */ IMG[vspace], OBJECT[vspace], APPLET[vspace] { margin-top: tcl(::tkhtml::attr vspace -len); margin-bottom: tcl(::tkhtml::attr vspace -len); } IMG[hspace], OBJECT[hspace], APPLET[hspace] { margin-left: tcl(::tkhtml::attr hspace -len); margin-right: tcl(::tkhtml::attr hspace -len); } ���������������������������������������tkHTML-4ee7aaa953d6cb59/tests/html1.test������������������������������������������������������������0000644�0000000�0000000�00000012444�11512242631�0017212�0����������������������������������������������������������������������������������������������������ustar�00nobody��������������������������nobody�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������# # Test script for the Tk HTML widget # wm withdraw . if {[lsearch [namespace children] ::tcltest] == -1} { source [file dirname $argv0]/engine.tcl namespace import ::tcltest::* } ::tcltest::test html-1.0 { Verify that all of the entites are displayed correctly. } { set h [tkhtml_test_widget] $h clear $h parse { <html> <h1>Entity and special character test</h1> <p>The following list shows each entity of HTML 3.2 in four formats: (1) the name, (2) as &entity;, (3) as &#123;, and (4) as a raw UTF-8 or Ascii character.</p> <ul> <li> quot " " " </li> <li> amp & & & </li> <li> lt < < < </li> <li> gt > > > </li> <li> nbsp   </li> <li> iexcl ¡ ¡ ¡ </li> <li> cent ¢ ¢ ¢ </li> <li> pound £ £ £ </li> <li> curren ¤ ¤ ¤ </li> <li> yen ¥ ¥ ¥ </li> <li> brvbar ¦ ¦ ¦ </li> <li> sect § § § </li> <li> uml ¨ ¨ ¨ </li> <li> copy © © © </li> <li> ordf ª ª ª </li> <li> laquo « « « </li> <li> not ¬ ¬ ¬ </li> <li> shy ­ ­ ­ </li> <li> reg ® ® ® </li> <li> macr ¯ ¯ ¯ </li> <li> deg ° ° ° </li> <li> plusmn ± ± ± </li> <li> sup2 ² ² ² </li> <li> sup3 ³ ³ ³ </li> <li> acute ´ ´ ´ </li> <li> micro µ µ µ </li> <li> para ¶ ¶ ¶ </li> <li> middot · · · </li> <li> cedil ¸ ¸ ¸ </li> <li> sup1 ¹ ¹ ¹ </li> <li> ordm º º º </li> <li> raquo » » » </li> <li> frac14 ¼ ¼ ¼ </li> <li> frac12 ½ ½ ½ </li> <li> frac34 ¾ ¾ ¾ </li> <li> iquest ¿ ¿ ¿ </li> <li> Agrave À À À </li> <li> Aacute Á Á Á </li> <li> Acirc    </li> <li> Atilde à à à </li> <li> Auml Ä Ä Ä </li> <li> Aring Å Å Å </li> <li> AElig Æ Æ Æ </li> <li> Ccedil Ç Ç Ç </li> <li> Egrave È È È </li> <li> Eacute É É É </li> <li> Ecirc Ê Ê Ê </li> <li> Euml Ë Ë Ë </li> <li> Igrave Ì Ì Ì </li> <li> Iacute Í Í Í </li> <li> Icirc Î Î Î </li> <li> Iuml Ï Ï Ï </li> <li> ETH Ð Ð Ð </li> <li> Ntilde Ñ Ñ Ñ </li> <li> Ograve Ò Ò Ò </li> <li> Oacute Ó Ó Ó </li> <li> Ocirc Ô Ô Ô </li> <li> Otilde Õ Õ Õ </li> <li> Ouml Ö Ö Ö </li> <li> times × × × </li> <li> Oslash Ø Ø Ø </li> <li> Ugrave Ù Ù Ù </li> <li> Uacute Ú Ú Ú </li> <li> Ucirc Û Û Û </li> <li> Uuml Ü Ü Ü </li> <li> Yacute Ý Ý Ý </li> <li> THORN Þ Þ Þ </li> <li> szlig ß ß ß </li> <li> agrave à à à </li> <li> aacute á á á </li> <li> acirc â â â </li> <li> atilde ã ã ã </li> <li> auml ä ä ä </li> <li> aring å å å </li> <li> aelig æ æ æ </li> <li> ccedil ç ç ç </li> <li> egrave è è è </li> <li> eacute é é é </li> <li> ecirc ê ê ê </li> <li> euml ë ë ë </li> <li> igrave ì ì ì </li> <li> iacute í í í </li> <li> icirc î î î </li> <li> iuml ï ï ï </li> <li> eth ð ð ð </li> <li> ntilde ñ ñ ñ </li> <li> ograve ò ò ò </li> <li> oacute ó ó ó </li> <li> ocirc ô ô ô </li> <li> otilde õ õ õ </li> <li> ouml ö ö ö </li> <li> divide ÷ ÷ ÷ </li> <li> oslash ø ø ø </li> <li> ugrave ù ù ù </li> <li> uacute ú ú ú </li> <li> ucirc û û û </li> <li> uuml ü ü ü </li> <li> yacute ý ý ý </li> <li> thorn þ þ þ </li> <li> yuml ÿ ÿ ÿ </li> </ul> </html> } ::tcltest::user-result } {0 pass} ::tcltest::test html-1.1 { Verify that all subscripting and superscripting works. } { set h [tkhtml_test_widget] $h clear $h parse { <html> <body> <h1>A test of subscripting and superscripting</h1> <p>Here is sub<sub>script</sub>. And now super<sup>script</sup>.</p> <p>Here is sub<sub>sub<sub>script</sub></sub>. And now super<sup>super<sup>script</sup></sup>.</p> <p>Here is sub<sub>super<sup>script</sup></sub></p> </body> </html> } ::tcltest::user-result } {0 pass} ::tcltest::test html-1.2 { Verify stylistic markup. } { set h [tkhtml_test_widget] $h clear $h parse { <html> <body> <h1>A test of font changing markup</h1> <p>This is normal text</p> <p><b>: <b>bold text</b></p> <p><big>: <big>big text</big></p> <p><cite>: <cite>cite text</cite></p> <p><code>: <code>code text</code></p> <p><em>: <em>emphasized text</em></p> <p><i>: <i>italic text</i></p> <p><kbd>: <kbd>keyboard text</kbd></p> <p><s>: <s>strike-thru text</s></p> <p><samp>: <samp>sample text</samp></p> <p><small>: <small>small text</small></p> <p><strike>: <strike>strike-thru text</strike></p> <p><strong>: <strong>strong text</strong></p> <p><tt>: <tt>teletype text</tt></p> <p><u>: <u>underlined text</u></p> <p><var>: <var>variable text</var></p> <p>This is normal text</p> </body> </html> } ::tcltest::user-result } {0 pass} ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������tkHTML-4ee7aaa953d6cb59/tests/html2.test������������������������������������������������������������0000644�0000000�0000000�00000003702�11512242631�0017210�0����������������������������������������������������������������������������������������������������ustar�00nobody��������������������������nobody�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������# # Test script for the Tk HTML widget # wm withdraw . if {[lsearch [namespace children] ::tcltest] == -1} { source [file dirname $argv0]/engine.tcl namespace import ::tcltest::* cd [file dirname $argv0] } # in image to use for all GIFs. # image create photo nogifsm -data { R0lGODdhEAAQAPEAAACQkADQ0PgAAAAAACwAAAAAEAAQAAACNISPacHtD4IQz80QJ60as25d 3idKZdR0IIOm2ta0Lhw/Lz2S1JqvK8ozbTKlEIVYceWSjwIAO/// } # A callback to handle image requests # proc ImageCmd {args} { set fn [lindex $args 0] if {[catch {image create photo -file $fn} img]} { set img nogifsm } return $img } # Free all images # proc FreeImages {} { foreach img [image names] { image delete $img } } # Create the HTML widget to use for all testing. # set h [tkhtml_test_widget] $h config -imagecommand ImageCmd ::tcltest::test html-2.1 { A snapshot of Slashdot on Jan 29, 2000. } { set file page1/index.html $h clear set f [open $file r] $h config -base $file $h parse [read $f [file size $file]] close $f set r [::tcltest::user-result] $h clear FreeImages return $r } {2 pass} ::tcltest::test html-2.2 { A snapshot of a page from the Scriptics website on Jan 29, 2000. } { set file page2/index.html $h clear set f [open $file r] $h config -base $file $h parse [read $f [file size $file]] close $f set r [::tcltest::user-result] $h clear FreeImages return $r } {2 pass} ::tcltest::test html-2.3 { A snapshot of freshmeat on Jan 29, 2000 } { set file page4/index.html $h clear set f [open $file r] $h config -base $file $h parse [read $f [file size $file]] close $f set r [::tcltest::user-result] $h clear FreeImages return $r } {2 pass} ::tcltest::test html-2.4 { A slide show about mktclapp } { set file page3/index.html $h clear set f [open $file r] $h config -base $file $h parse [read $f [file size $file]] close $f set r [::tcltest::user-result] $h clear FreeImages return $r } {2 pass} ��������������������������������������������������������������tkHTML-4ee7aaa953d6cb59/tests/html3.test������������������������������������������������������������0000644�0000000�0000000�00000016067�11512242631�0017221�0����������������������������������������������������������������������������������������������������ustar�00nobody��������������������������nobody�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������# # Test script for the Tk HTML widget # wm withdraw . if {[lsearch [namespace children] ::tcltest] == -1} { source [file dirname $argv0]/engine.tcl namespace import ::tcltest::* } ::tcltest::test html-3.1 {Check the HTML parser for sanity} { set h [tkhtml_test_widget] $h clear $h parse "<p align=center>Test1 \nEnd\n" $h token list 1.0 end } {0 {{Markup p align center} {Text Test1} {Space 1 1} {Text End} {Space 1 1}}} ::tcltest::test html-3.2 {Check that markup arguments are parsed correctly} { set h [tkhtml_test_widget] $h clear $h parse {<p align="center" id='"5"' id2 = "'4'">} $h token list 1.0 end } {0 {{Markup p align center id {"5"} id2 '4'}}} ::tcltest::test html-3.3 {Check that comments are ignored} { set h [tkhtml_test_widget] $h clear $h parse {<p><!-- This is comment --></p>} $h token list 1.0 end } {0 {{Markup p} {Markup /p}}} ::tcltest::test html-3.4 {Check that entities are resolved} { set h [tkhtml_test_widget] $h clear $h parse {& <>H<p>} $h token list 1.0 end } {0 {{Text {& <>H}} {Markup p}}} ::tcltest::test html-3.5 {Check that spacing is recorded properly} { set h [tkhtml_test_widget] $h clear $h parse "<pre>\n\tHi\tThere\n</pre>" $h token list 1.0 end } {0 {{Markup pre} {Space 1 1} {Space 8 0} {Text Hi} {Space 6 0} {Text There} {Space 1 1} {Markup /pre}}} ::tcltest::test html-3.6 {Script markup should become a single token} { set h [tkhtml_test_widget] $h clear $h parse "<script>Contents of script are not tokenized</script>\n" $h token list 1.0 end } {0 {{Markup script} {Space 1 1}}} ::tcltest::test html-3.6b {Style markup should become a single token} { set h [tkhtml_test_widget] $h clear $h parse "<style>Contents of style are not tokenized</style>\n" $h token list 1.0 end } {0 {{Markup style} {Space 1 1}}} ::tcltest::test html-3.7 {All markup within listing is normal text} { set h [tkhtml_test_widget] $h clear $h parse "<listing><p>Hello</p></listing>\n" $h token list 1.0 end } {0 {{Markup listing} {Text <p>Hello} {Text </p>} {Markup /listing} {Space 1 1}}} ::tcltest::test html-3.8 {All markup within xmp is normal text} { set h [tkhtml_test_widget] $h clear $h parse "<xmp><p>Hello</p></xmp>\n" $h token list 1.0 end } {0 {{Markup xmp} {Text <p>Hello} {Text </p>} {Markup /xmp} {Space 1 1}}} ::tcltest::test html-3.9 {All markup within textarea is treated as normal text. This is not valid HTML, but it is what Netscape does.} { set h [tkhtml_test_widget] $h clear $h parse "<textarea><p>Hello</p></textarea>\n" $h token list 1.0 end } {0 {{Markup textarea} {Text <p>Hello} {Text </p>} {Markup /textarea} {Space 1 1}}} ::tcltest::test html-3.10 {All markup after plaintext become normal text} { set h [tkhtml_test_widget] $h clear $h parse "<plaintext><p>Hello</p></plaintext>\n" $h token list 1.0 end } {0 {{Markup plaintext} {Text <p>Hello} {Text </p>} {Text </plaintext>} {Space 1 1}}} ::tcltest::test html-3.11 {Unrecognized markup is ignored} { set h [tkhtml_test_widget] $h clear $h parse "<unknown>Text\n" $h token list 1.0 end } {0 {{Text Text} {Space 1 1}}} ::tcltest::test html-3.12 {Entities are resolved within markup arguments} { set h [tkhtml_test_widget] $h clear $h parse {<p id="<hi>">} $h token list 1.0 end } {0 {{Markup p id <hi>}}} ::tcltest::test html-3.13 {Entites are resolved within markup arguments} { set h [tkhtml_test_widget] $h clear $h parse {<p id=<hi>>} $h token list 1.0 end } {0 {{Markup p id <hi>}}} ::tcltest::test html-3.14 {White space within markup is ignored} { set h [tkhtml_test_widget] $h clear $h parse {<br >} $h token list 1.0 end } {0 {{Markup br}}} ::tcltest::test html-3.15 {Whitespace within markup is ignored} { set h [tkhtml_test_widget] $h clear $h parse {<br id = 5>} $h token list 1.0 end } {0 {{Markup br id 5}}} ::tcltest::test html-3.16 {Whitespace in markup is ignored} { set h [tkhtml_test_widget] $h clear $h parse {<br id = 5 >} $h token list 1.0 end } {0 {{Markup br id 5}}} ::tcltest::test html-3.17 {Whitespace in markup is ignored} { set h [tkhtml_test_widget] $h clear $h parse {<br id =5>} $h token list 1.0 end } {0 {{Markup br id 5}}} ::tcltest::test html-3.18 {Whitespace in markup is ignored} { set h [tkhtml_test_widget] $h clear $h parse {<br id= 5 >} $h token list 1.0 end } {0 {{Markup br id 5}}} ::tcltest::test html-3.19 {Whitespace in markup is ignored, except when quoted} { set h [tkhtml_test_widget] $h clear $h parse {<br id= " 5 " >} $h token list 1.0 end } {0 {{Markup br id { 5 }}}} ::tcltest::test html-3.20 {Tabs in markup are treated like whitespace} { set h [tkhtml_test_widget] $h clear $h parse "<br id\t=\t' 5 '\t>" $h token list 1.0 end } {0 {{Markup br id { 5 }}}} ::tcltest::test html-3.21 {Newlines in markup are treated like whitespace} { set h [tkhtml_test_widget] $h clear $h parse "<br id\n=\n\" 5 \"\n>" $h token list 1.0 end } {0 {{Markup br id { 5 }}}} ::tcltest::test html-3.22 {Markup arguments without values} { set h [tkhtml_test_widget] $h clear $h parse "<br clear >" $h token list 1.0 end } {0 {{Markup br clear {}}}} ::tcltest::test html-3.23 {Markup arguments without values} { set h [tkhtml_test_widget] $h clear $h parse "<br clear id=9>" $h token list 1.0 end } {0 {{Markup br clear {} id 9}}} ::tcltest::test html-3.24 {XHTML style / at the end of markup} { set h [tkhtml_test_widget] $h clear $h parse {<br clear="both"/>} $h token list 1.0 end } {0 {{Markup br clear both}}} ::tcltest::test html-3.25 {XHTML style / at the end of markup} { set h [tkhtml_test_widget] $h clear $h parse {<br />} $h token list 1.0 end } {0 {{Markup br}}} ::tcltest::test html-3.26 {XHTML style / at the end of markup} { set h [tkhtml_test_widget] $h clear $h parse {<br/>} $h token list 1.0 end } {0 {{Markup br}}} ::tcltest::test html-3.27 {/ At the end of markup adds a second token} { set h [tkhtml_test_widget] $h clear $h parse {<p />} $h token list 1.0 end } {0 {{Markup p} {Markup /p}}} ::tcltest::test html-3.28 {/ at the end of markup adds a second token} { set h [tkhtml_test_widget] $h clear $h parse {<p/>} $h token list 1.0 end } {0 {{Markup p} {Markup /p}}} ::tcltest::test html-3.29 {/ not at the end of markup still work} { set h [tkhtml_test_widget] $h clear $h parse "<A href=\"\" /privacy.html=\"/privacy.html\">\n" $h token list 1.0 end } {0 {{Markup a href {} /privacy.html /privacy.html} {Space 1 1}}} ::tcltest::test html-3.30 {Incremental parsing} { set h [tkhtml_test_widget] $h clear set txt {<a href="" /privacy.html="none"/>Hello&<p>} set len [string length $txt] for {set i 0} {$i<$len} {incr i} { $h parse [string index $txt $i] } $h token list 1.0 end } {0 {{Markup a href {} /privacy.html none} {Markup /a} {Text Hello&} {Markup p}}} ::tcltest::test html-3.31 {Searching for anchors} { set h [tkhtml_test_widget] $h clear $h parse { <a name="one">One</a> <a id="two">Two</a> <a href="three">Three</a> <a name="four" id="vier">Four</a> } update $h names } {0 {one two four}} �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������tkHTML-4ee7aaa953d6cb59/tests/html4.test������������������������������������������������������������0000755�0000000�0000000�00000003257�11512242631�0017222�0����������������������������������������������������������������������������������������������������ustar�00nobody��������������������������nobody�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#!/usr/bin/wish if {[info commands html] == ""} { if {[file exists libTkhtml2.0.so]} { load ./libTkhtml2.0.so } else { package require Tkhtml } } package require tcltest ::tcltest::test html-4.1 {textarea space after dot} { set ::RESULT {} proc FormCmd {n cmd args} { if {$cmd != "textarea"} return set ::RESULT [lindex $args end] } html .html -formcommand FormCmd pack .html .html parse { <html><body><form action="submit" method="get"> <textarea name="test" cols="20" rows="2">A.B. C. D.</textarea> </form></body></html> } # To force all FormCmd is executed... update set ::RESULT } {A.B. C. D.} ::tcltest::test html-4.2 {pre space after dot} { catch {destroy .html} pack [html .html] .html parse {<body>BEGIN<pre>A.B. C. D.</pre>END</body>} .html text ascii 1 end } {BEGINA.B. C. D.END} ::tcltest::test html-4.3 {SentencePadding A. B. C.} { catch {destroy .html} pack [html .html -sentencepadding 1] .html parse {<h1>A. B. C.</h1>} set result [.html text ascii 1 end] destroy .html set result } {A. B. C.} ::tcltest::test html-4.4 {SentencePadding for D.C...} { catch {destroy .html} pack [html .html] catch {.html configure -sentencepadding 1} .html parse {<h1>Today Washington D.C. is ...</h1>} set result [.html text ascii 1 end] destroy .html set result } {Today Washington D.C. is ...} ::tcltest::test html-4.5 {No SentencePadding for "A. B."} { catch {destroy .html} pack [html .html] catch {.html configure -sentencepadding 1} .html parse {<h1>A. B.</h1>} set result [.html text ascii 1 end] destroy .html set result } {A. B.} �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������tkHTML-4ee7aaa953d6cb59/tests/html5.test������������������������������������������������������������0000755�0000000�0000000�00000000437�11512242631�0017220�0����������������������������������������������������������������������������������������������������ustar�00nobody��������������������������nobody�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#!/usr/bin/wish if {[info commands html] == ""} { if {[file exists libTkhtml2.0.so]} { load ./libTkhtml2.0.so } else { package require Tkhtml } } package require tcltest tcltest::test html-5.1 {gzip -> gunzip roundtrip} { html gunzip data [html gzip data abc] } {abc} ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������tkHTML-4ee7aaa953d6cb59/tests/hv.tcl����������������������������������������������������������������0000644�0000000�0000000�00000034635�11512242631�0016413�0����������������������������������������������������������������������������������������������������ustar�00nobody��������������������������nobody����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������� package provide app-hv3 1.0 catch { memory init on for {set i 0} {$i < 50} {incr i} { memory info } } set auto_path [concat . $auto_path] package require Tkhtml 3.0 # source [file join [file dirname [info script]] tkhtml.tcl] # Global symbols: set ::HTML {} ;# The HTML widget command set ::DOCUMENT {} ;# Name of html file to load on startup. set ::EXIT 0 ;# True if -exit switch specified set ::NODE {} ;# Name of node under the cursor set ::WIDGET 1 ;# Counter used to generate unique widget names set ::MEMARRAY {} ;# Used by proc layout_engine_report. set ::TIMEARRAY {} ;# Used by proc layout_engine_report. array set ::ANCHORTONODE {} ;# Map from anchor name to node command # If possible, load package "Img". Without it the script can still run, # but won't be able to load many image formats. catch { package require Img } # Background error proc. We don't want to pull up a dialog box for every # image that can't be found, so just output the error on stdout. # proc bgerror {msg} { puts "ERROR: $msg" } proc nodePrint {indent node} { set type [$node tag] set istr [string repeat " " $indent] set ret {} if {$type == "text"} { append ret $istr append ret [$node text] append ret "\n" } else { append ret $istr append ret "<[$node tag]>\n" for {set i 0} {$i < [$node nChildren]} {incr i} { append ret [nodePrint [expr $indent + 2] [$node child $i]] } append ret $istr append ret "</[$node tag]>\n" } return $ret } proc report_dialog {report} { if {![winfo exists .report]} { toplevel .report text .report.text scrollbar .report.scroll .report.text configure -width 100 .report.text configure -yscrollcommand {.report.scroll set} .report.scroll configure -command {.report.text yview} pack .report.text -fill both -expand true -side left pack .report.scroll -fill y -expand true } .report.text delete 0.0 end .report.text insert 0.0 $report } proc layout_primitives_report {} { report_dialog [join [$::HTML layout primitives] "\n"] } proc document_tree_report {} { report_dialog [nodePrint 0 [$::HTML node]] } proc document_summary_report {} { set report {} set node [$::HTML node] set count [count_nodes $node] set primitives [llength [$::HTML layout primitives]] set layout_time [lindex [$::HTML var layout_time] 0] set report "Layout time: $layout_time us\n" append report "Document nodes: [lindex $count 0]" append report " ([lindex $count 1] text)\n" append report "Layout primitives: $primitives\n" report_dialog $report } proc bytes {memreport} { set line [lindex [split $memreport "\n"] 3] return [lindex $line end] } proc layout_engine_report {} { if {[info commands memory] != ""} { lappend ::MEMARRAY [string trim [memory info]] } lappend ::TIMEARRAY [$::HTML var layout_time] $::HTML reset if {[info commands memory] != ""} { lappend ::MEMARRAY [string trim [memory info]] } else { lappend ::MEMARRAY N/A lappend ::MEMARRAY N/A } load_document $::DOCUMENT {} if {[llength $::MEMARRAY] < 8} { after idle layout_engine_report } else { set report_lines {} if {[info commands memory] != ""} { set report_lines [split [lindex $::MEMARRAY 0] "\n"] foreach mem [lrange $::MEMARRAY 1 end] { set l 0 foreach line [split $mem "\n"] { set number [format {% 8s} [lindex $line end]] lset report_lines $l "[lindex $report_lines $l] $number" incr l } } set leaks {} lappend leaks [expr \ [bytes [lindex $::MEMARRAY 2]] - [bytes [lindex $::MEMARRAY 0]]] lappend leaks [expr \ [bytes [lindex $::MEMARRAY 4]] - [bytes [lindex $::MEMARRAY 2]]] lappend leaks [expr \ [bytes [lindex $::MEMARRAY 6]] - [bytes [lindex $::MEMARRAY 4]]] } else { set leaks N/A } lappend report_lines {} lappend report_lines "Layout times (us): $::TIMEARRAY" lappend report_lines "Growth (bytes): $leaks" set report [join $report_lines "\n"] report_dialog $report set ::MEMARRAY {} set ::TIMEARRAY {} } } proc scroll_test {{dir 1} {step 0}} { set num_steps 500 set yview [$::HTML yview] set range [expr 1.0 - ([lindex $yview 1] - [lindex $yview 0])] set fraction [expr ($range / $num_steps.0) * $step] $::HTML yview moveto $fraction incr step $dir if {$step >= 0} { if {$step == $num_steps} {set dir -1} after 1 "scroll_test $dir $step" } } proc resize_test {{x 800} {increment -20}} { wm geometry . "[set x]x600" incr x $increment if {$x == 800} return if {$x == 100} { set increment 20 } after 1 "resize_test $x $increment" } # Update the status bar. The mouse is at screen coordinates (x, y). # This proc is tied to a <Motion> event on the main Html widget. # proc update_status {x y} { # Global variable ::NODE stores the node that the cursor was over last # time this proc was called. If we are still hovering over the same # node, then return early as the status bar is already correct. # set n [$::HTML node $x $y] if {$n == $::NODE} { return } set ::NODE $n set status "" set linkto "" for {} {$n != ""} {set n [$n parent]} { if {[$n tag] == "text"} { set status "[$n text]" } else { set status "<[$n tag]>$status" } if {$linkto == "" && [$n tag] == "a" && [$n attr href] != ""} { set linkto [$n attr href] } } # If the cursor is hovering over a hyperlink, then set the status bar # to display "link: <url>" and set the cursor to "hand2". Otherwise, # set the status bar to display the node chain and set the cursor to # the default. # if {$linkto != ""} { . configure -cursor hand2 set status "link: $linkto" } else { . configure -cursor {} } # Trim the status bar string so that it does not cause the GUI window # to grow. # set pixels [expr [winfo width .status] - 30] set letters 10 set font [.status cget -font] while {$letters < [string length $status] && [font measure $font [string range $status 0 [expr $letters+10]]] < $pixels} { incr letters 10 } .status configure -text [string range $status 0 $letters] } # This procedure is called when the user clicks on the html widget. If the # mouse is over a hyper-link we load the new document. # proc click {x y} { set link "" for {set node [$::HTML node $x $y]} {$node!=""} {set node [$node parent]} { if {[$node tag] == "a" && [$node attr href] != ""} { set link [$node attr href] break } } if {$link != ""} { set parts [split $link #] set doc [lindex $parts 0] set anchor [lindex $parts 1] if {$doc == "" || [file join $::BASE $doc] == $::DOCUMENT} { if {[info exists ::ANCHORTONODE($anchor)]} { set node $::ANCHORTONODE($anchor) $::HTML yview moveto $node } } else { set ::DOCUMENT [file join $::BASE $doc] load_document $::DOCUMENT $anchor } } } # This procedure is called when a <style> tag is encountered during # parsing. The $script parameter holds the entire contents of the node. # proc handle_style_node {script} { $::HTML style parse author.0 $script } # This procedure is called when a <link> node is encountered while building # the document tree. It loads a stylesheet from a file on disk if required. # proc handle_link_node {node} { if {[$node attr rel] == "stylesheet"} { set fd [open [file join $::BASE [$node attr href]]] set script [read $fd] close $fd } $::HTML style parse author.1 $script } # This procedure is called when a <a> node is encountered while building # the document tree. If the <a> has a name attribute, put an entry in the # ::ANCHORTONODE map. # proc handle_a_node {node} { set name [$node attr name] if {$name != ""} { set ::ANCHORTONODE($name) $node } } # Analyse the tree with node $node at it's head and return a two element # list. The first element of the list is the total number of nodes in the # tree. The second element is the number of "text" nodes in the tree. # proc count_nodes {node} { if {[$node tag] == "text"} { set ret {1 1} } else { set ret {1 0} } for {set i 0} {$i < [$node nChildren]} {incr i} { set c [count_nodes [$node child $i]] lset ret 0 [expr [lindex $ret 0] + [lindex $c 0]] lset ret 1 [expr [lindex $ret 1] + [lindex $c 1]] } return $ret } # This procedure is called once at the start of the script to build # the GUI used by the application. It also sets up the callbacks # supplied by this script to help the widget render html. # proc build_gui {} { set ::HTML [html .h] scrollbar .vscroll -orient vertical scrollbar .hscroll -orient horizontal label .status -height 1 -anchor w -background white . config -menu [menu .m] foreach cascade [list File Tests Reports] { set newmenu [string tolower .m.$cascade] .m add cascade -label $cascade -menu [menu $newmenu] $newmenu configure -tearoff 0 } .m.reports add command -label {Document Summary} \ -command document_summary_report .m.reports add command -label {Document Tree} -command document_tree_report .m.reports add command -label {Layout Primitives} \ -command layout_primitives_report .m.reports add command -label {Layout Engine} -command layout_engine_report .m.tests add command -label {Scroll test} -command scroll_test .m.tests add command -label {Resize test} -command resize_test .m.file add command -label {Open...} -command open_document .m.file add command -label {Back} -command go_back .m.file add command -label {Exit} -command exit pack .vscroll -fill y -side right pack .status -fill x -side bottom pack .hscroll -fill x -side bottom pack $::HTML -fill both -expand true $::HTML configure -yscrollcommand {.vscroll set} $::HTML configure -xscrollcommand {.hscroll set} .vscroll configure -command "$::HTML yview" .hscroll configure -command "$::HTML xview" bind $::HTML <Motion> "update_status %x %y" bind $::HTML <KeyPress-q> exit bind $::HTML <KeyPress-Q> exit bind $::HTML <ButtonPress> "click %x %y" $::HTML handler script style "handle_style_node" $::HTML handler node link "handle_link_node" $::HTML handler node a "handle_a_node" focus $::HTML } # This procedure parses the command line arguments # proc parse_args {argv} { for {set i 0} {$i < [llength $argv]} {incr i} { if {[lindex $argv $i] == "-exit"} { set ::EXIT 1 } else { set ::DOCUMENT [lindex $argv $i] } } } # This proc is called to get the replacement image for a node of type <IMG> # with a "src" attribute defined. # proc replace_img_node {base node} { set imgfile [file join $base [$node attr src]] image create photo -file $imgfile } # This proc is called to get the replacement window for a node of type # <INPUT>. # proc replace_input_node {base node} { set type [string tolower [$node attr type]] if {$type == ""} { set type text } set win "" set winname "$::HTML.formcontrol[incr ::WIDGET]" switch -- $type { text { set win [entry $winname] } password { set win [entry $winname -show true] } submit { set win [button $winname -text [$node attr value]] } button { set win [button $winname -text [$node attr value]] } } return $win } # This proc is called to get the replacement window for a node of type # <SELECT>. # proc replace_select_node {base node} { set options [list] set maxlen 0 set win "" set winname "$::HTML.formcontrol[incr ::WIDGET]" set menuname "$winname.menu" set radiogroupname "::radio$::WIDGET" set menubutton [menubutton $winname] set menu [menu $menuname] for {set i 0} {$i < [$node nChildren]} {incr i} { set child [$node child $i] if {[$child tag] == "option"} { set label [$child attr label] if {$label == "" && [$child nChildren] == 1} { set label [[$child child 0] text] } $menu add radiobutton -label $label -variable $radiogroupname if {[string length $label]>$maxlen} { set maxlen [string length $label] set $radiogroupname $label } } } $menubutton configure -menu $menu $menubutton configure -textvariable $radiogroupname $menubutton configure -width $maxlen $menubutton configure -relief raised return $menubutton } proc go_back {} { set len [llength $::HISTORY] if {$len == 1} return foreach {doc anchor} [lindex $::HISTORY [expr $len-2]] {} set ::HISTORY [lrange $::HISTORY 0 [expr $len-2]] load_document $doc $anchor } proc open_document {} { set doc [tk_getOpenFile] if {$doc != ""} { set ::DOCUMENT $doc load_document $doc {} } } proc load_document {document anchor} { set fd [open $document] set doc [read $fd] close $fd lappend ::HISTORY [list $document anchor] set base [file dirname $document] set ::BASE $base array set ::ANCHORTONODE {} $::HTML reset $::HTML style parse agent.1 [subst -nocommands { IMG[src] {-tkhtml-replace:tcl(replace_img_node $base)} INPUT {-tkhtml-replace:tcl(replace_input_node $base)} SELECT {-tkhtml-replace:tcl(replace_select_node $base)} }] $::HTML parse $doc if {$anchor != "" && [info exists ::ANCHORTONODE($anchor)]} { update $::HTML yview moveto $::ANCHORTONODE($anchor) } } if {[info exists argv]} { parse_args $argv build_gui load_document $::DOCUMENT {} } if {$::EXIT} { update catch { memory active mem.out puts [memory info] } exit } ���������������������������������������������������������������������������������������������������tkHTML-4ee7aaa953d6cb59/tests/image.tcl�������������������������������������������������������������0000644�0000000�0000000�00000021104�11512242631�0017043�0����������������������������������������������������������������������������������������������������ustar�00nobody��������������������������nobody����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������� catch {memory init on} proc usage {} { set prog $::argv0 puts stderr [subst { $prog <html-document1> ?<html-document2>....? $prog -file <filename> This program renders html documents to jpeg images. If the second syntax above is used, then <filename> must be the name of a text file containing the names of one or more html document files, each seperated by a newline character. Otherwise the documents rendered are those specified directly on the command line. When invoked, the TKHTML_TESTDIR environment variable must be set to the name of a directory. This directory is used by the program to store images previously rendered. The idea is that if the user has previously inspected and approved of the rendering of a document, then the image is saved and may be used to verify rendering of the same document at a later stage. Thus, automated test suites for the layout engine may be accomplished. It's unfortunate that moving caches between machines etc. will probably generate false-negatives, due to differences in font configuration. }] exit -1 } set IMGFMT bmp # Load Tkhtml and if possible the Img package. The Img package is required # for most image files formats used by web documents. Also to write jpeg # files. # set auto_path [concat . $auto_path] package require Tkhtml catch { package require Img } # Set the global variable ::TESTDIR to the value of the cache directory. If # the environment variable is not set, invoke the usage message proc. # if {![info exists env(TKHTML_TESTDIR)]} usage if {![file isdirectory $env(TKHTML_TESTDIR)]} usage set TESTDIR $env(TKHTML_TESTDIR) proc shift {listvar} { upvar $listvar l set ret [lindex $l 0] set l [lrange $l 1 end] return $ret } # Procedure to return the contents of a file-system entry proc readFile {fname} { set ret {} catch { set fd [open $fname] set ret [read $fd] close $fd } return $ret } # Procedure to handle text inside a <style> tag. proc stylecmd {style} { append ::STYLE_TEXT $style append ::STYLE_TEXT "\n" return "" } # Procedure to handle a <link> tag that imports a stylesheet. proc linkcmd {node} { set rel [string tolower [$node attr rel]] set media [string tolower [$node attr media]] set media_list [list all visual screen ""] if {[string compare $rel stylesheet]==0 && [lsearch $media_list $media]!=-1} { set href [$node attr href] set filename [file join $::BASE $href] lappend ::STYLESHEET_FILES $filename } } # Procedure to handle the <title> tag. proc titlecmd {title} { wm title . [string trim $title] } proc load_document {css document} { set ::STYLESHEET_FILES {} set ::STYLE_TEXT {} set parsetime [time { $::HTML internal parse $document $::HTML internal parsefinal $::HTML style parse agent $css while {[llength $::STYLESHEET_FILES]>0} { set ss [lindex $::STYLESHEET_FILES 0] set ::STYLESHEET_FILES [lrange $::STYLESHEET_FILES 1 end] $::HTML style parse author [readFile $ss] } $::HTML style parse author $::STYLE_TEXT }] $::HTML style parse author.1 { img { -tkhtml-replace: tcl(replace_img) } object { -tkhtml-replace: tcl(replace_img) } input { -tkhtml-replace: tcl(replace_input) } select { -tkhtml-replace: tcl(replace_select) } } set styletime [time { $::HTML style apply }] puts -nonewline "Parse [lrange $parsetime 0 1] Style [lrange $styletime 0 1]" } # Procedure to handle <input> and <object> tags. proc replace_img {node} { if {[$node tag]=="object"} { set filename [file join $::BASE [$node attr data]] } else { set filename [file join $::BASE [$node attr src]] } if [catch { set img [image create photo -file $filename] } msg] { # puts "Error: $msg" error $msg } return $img } # Procedure to handle <input> tags. set CONTROL 0 proc replace_input {node} { set tkname ".control[incr ::CONTROL]" set width [$node attr width] if {$width==""} { set width 20 } switch -exact [$node attr type] { image { return [replace_img $node] } hidden { return "" } checkbox { return [checkbutton $tkname] } radio { return [checkbutton $tkname] } submit { return [button $tkname -text Submit] } default { entry $tkname -width $width return $tkname } } return "" } # Procedure to handle <select> tags proc replace_select {node} { set tkname ".control[incr ::CONTROL]" button $tkname -text Select return $tkname } proc docname_to_imgname {docname} { file join $::TESTDIR [string map {{ } _ / _} [file tail $docname]].$::IMGFMT } proc docname_to_primname {docname} { return [file join $::TESTDIR [string map {{ } _ / _} $docname].primitives] } proc compare_document_image {docname} { $::HTML layout force -width 800 set layouttime [time {set img [$::HTML layout image]}] puts " Layout [lrange $layouttime 0 1]" set filename [docname_to_imgname $docname] $img write tmp.$::IMGFMT -format $::IMGFMT image delete $img set data [readFile tmp.$::IMGFMT] set data2 [readFile $filename] if {$data2==""} { return NOIMAGE } if {$data2==$data} { return MATCH } return NOMATCH } proc correct {docname img} { set filename [docname_to_imgname $docname] catch { file delete -force $filename } $img write $filename -format $::IMGFMT set ::CONTINUEFLAG 1 } proc incorrect {docname img} { set filename [docname_to_primname $docname] set fd [open $filename w] puts $fd [join [$::HTML layout primitives] "\n"] close $fd set ::CONTINUEFLAG 1 } wm geometry . 800x600 set ::HTML [html .h] $::HTML handler script script dummycmd $::HTML handler script style stylecmd $::HTML handler script title titlecmd $::HTML handler node link linkcmd if {[lindex $argv 0]=="-file"} { set fname [lindex $argv 1] set fdir [file dirname $fname] set fd [open $fname] set ::DOCUMENT_LIST {} while {![eof $fd]} { set doc [gets $fd] if {$doc!="" && ![regexp {^ *#} $doc]} { lappend ::DOCUMENT_LIST [file join $fdir $doc] } } close $fd } else { set ::DOCUMENT_LIST $argv } set ::DEFAULT_CSS [readFile [file join [file dirname [info script]] html.css]] frame .buttons button .buttons.correct -text Correct button .buttons.incorrect -text Incorrect button .buttons.oldimage -text {Old Image} button .buttons.newimage -text {New Image} pack .buttons.correct .buttons.incorrect -side left pack .buttons.oldimage .buttons.newimage -side right pack .buttons -side bottom -fill x scrollbar .s -orient vertical scrollbar .s2 -orient horizontal canvas .c -background white pack .s -side right -fill y pack .s2 -side bottom -fill x pack .c -fill both -expand true .c configure -yscrollcommand {.s set} .c configure -xscrollcommand {.s2 set} .s configure -command {.c yview} .s2 configure -command {.c xview} bind .c <KeyPress-Down> {.c yview scroll 1 units} bind .c <KeyPress-Up> {.c yview scroll -1 units} focus .c foreach document $::DOCUMENT_LIST { set ::BASE [file dirname $document] load_document $::DEFAULT_CSS [readFile $document] set res [compare_document_image $document] if {$res=="MATCH"} { puts "$document - MATCH" } if {$res=="NOIMAGE"} { .c delete all set img [$::HTML layout image] .c create image 0 0 -anchor nw -image $img catch { .c configure -scrollregion [.c bbox all] } .buttons.correct configure -command "correct $document $img" .buttons.incorrect configure -command "incorrect $document $img" .buttons.oldimage configure -state disabled .buttons.newimage configure -state disabled vwait ::CONTINUEFLAG .c delete all image delete $img } if {$res=="NOMATCH"} { set img [$::HTML layout image] set imgold [image create photo -file [docname_to_imgname $document]] .c delete all .c create image 0 0 -anchor nw -image $img catch { .c configure -scrollregion [.c bbox all] } .buttons.correct configure -command "correct $document $img" .buttons.incorrect configure -command "incorrect $document $img" .buttons.oldimage configure -state normal -command [subst -nocommands { .c delete all .c create image 0 0 -anchor nw -image $imgold catch { .c configure -scrollregion [.c bbox all] } }] .buttons.newimage configure -state normal -command [subst -nocommands { .c delete all .c create image 0 0 -anchor nw -image $img catch { .c configure -scrollregion [.c bbox all] } }] vwait ::CONTINUEFLAG .c delete all image delete $img image delete $imgold } $::HTML internal reset } rename $::HTML {} exit ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������tkHTML-4ee7aaa953d6cb59/tests/main.tcl��������������������������������������������������������������0000644�0000000�0000000�00000000533�11512242631�0016710�0����������������������������������������������������������������������������������������������������ustar�00nobody��������������������������nobody����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������� # # This is the main.tcl file used to create a starkit from the hv.tcl # application. # package require starkit if {[starkit::startup] eq "sourced"} return if {[llength $argv] == 0} { set argv [file join [file dirname [info script]] index.html] } rename exit exit_original proc exit {args} { ::tk::htmlexit } package require app-hv3 ���������������������������������������������������������������������������������������������������������������������������������������������������������������������tkHTML-4ee7aaa953d6cb59/tests/node.bt���������������������������������������������������������������0000644�0000000�0000000�00000001206�11512242631�0016532�0����������������������������������������������������������������������������������������������������ustar�00nobody��������������������������nobody����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������� do_browser_test node.1 -javascript { return Node.ELEMENT_NODE } do_browser_test node.2 -javascript { Node.prop = "hello" return Node.prop } # This test does not work. Firefox allows the Node.ELEMENT_NODE # constant to be overwritten, whereas Hv3 throws an exception. # # ::browsertest::do_test node.3 -timeout 10000000 -javascript { # Node.ELEMENT_NODE = "hello" # return Node.ELEMENT_NODE # } -expected hello do_browser_test node.3 -javascript { try { document.body.nodeType = 10 } catch (e) { return e } return "" } do_browser_test node.4 -html {<body>} -javascript { return "" + document.body.ELEMENT_NODE } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������tkHTML-4ee7aaa953d6cb59/tests/options.test����������������������������������������������������������0000644�0000000�0000000�00000001457�11512242631�0017662�0����������������������������������������������������������������������������������������������������ustar�00nobody��������������������������nobody�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������# Test script for Tkhtml proc sourcefile {file} { set fname [file join [file dirname [info script]] $file] uplevel #0 [list source $fname] } sourcefile common.tcl html .h #-------------------------------------------------------------------------- # Test cases option-1.* test the parsing of the '-fonttable' option. # tcltest::test option-1.0 {} -body { .h cget -fonttable } -result {8 9 10 11 13 15 17} tcltest::test option-1.1 {} -body { set rc [catch { .h configure -fonttable hello } msg] list $rc $msg } -result {1 {expected list of 7 integers but got "hello"}} tcltest::test option-1.2 {} -body { .h cget -fonttable } -result {8 9 10 11 13 15 17} tcltest::test option-1.3 {} -body { .h configure -fonttable {1 2 3 4 5 6 7} .h cget -fonttable } -result {1 2 3 4 5 6 7} finish_test �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������tkHTML-4ee7aaa953d6cb59/tests/page1�����������������������������������������������������������������0000755�0000000�0000000�00000000000�11512242631�0016175�5����������������������������������������������������������������������������������������������������ustar�00nobody��������������������������nobody�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������tkHTML-4ee7aaa953d6cb59/tests/page1/image1����������������������������������������������������������0000644�0000000�0000000�00000021443�11512242631�0017346�0����������������������������������������������������������������������������������������������������ustar�00nobody��������������������������nobody�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������GIF89aÔ<�æ!�ÿÿÿÿÿÌÿÌÿÌÿÿÌÌÿÌÌÌÌ̙̙fÌ™3™Ì̙̙™Ìf™™Ì™™™™™f™™3™ff™f3fÌÌfÌ3f™Ìf™ff™3fff3™Ì3™™3™f3f™33333��™Ì�™™���ÿÿÿÿÿ™ÿÿfÿÿ3ÿÿ�ÿÌÌÿÌ™ÿÌfÿÌ3ÿÌ�ÿ™ÿÿ™Ìÿ™™ÿ™fÿ™3ÿ™�ÿfÿÿfÌÿf™ÿffÿf3ÿf�ÿ3ÿÿ3Ìÿ3™ÿ3fÿ33ÿ3�ÿ�ÿÿ�Ìÿ�™ÿ�fÿ�3ÿ��ÌÿÌÌÿ™ÌÿfÌÿ3Ìÿ�ÌÌfÌÌ3ÌÌ�Ì™ÿÌ™ÌÌ™™Ì™�ÌfÿÌfÌÌf™ÌffÌf3Ìf�Ì3ÿÌ3ÌÌ3™Ì3fÌ33Ì3�Ì�ÿÌ�ÌÌ�™Ì�fÌ�3Ì��™ÿÿ™ÿÌ™ÿ™™ÿf™ÿ3™ÿ�™Ìÿ™Ì3™Ì�™™ÿ™™�™fÿ™fÌ™f™™f�™3ÿ™3Ì™3™™3f™33™3�™�ÿ™�Ì™�™™�f™�3™��fÿÿfÿÌfÿ™fÿf!ÿ NETSCAPE2.0���!ùd�!�,����Ô<��ÿ€�‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´¢·¸ˆ » µ¿ÀŒ¼ ¬Ä¾ÁÊ˯Ãĺ¼ÉÌÔ’× žÎ»Æ«ÈÕáâ¡Ä݇àãê‰éœÜÅÇÒëóô’æ»Ó„íõóûšïÞTùãG°`ƒ{  ˆ ×-w¹R9„±CBåèÈaÀH/fÔø° ÉVx¥äõQ¸Øº€MÛ ˜×’ÑD˜mP˜-q^óY· -}%$4ßOlÆ`òÌ@(4©¼lØ©[>¬*µ}Vôœ"®æ>*‹ÏØ]Gÿ`{téÉ»¡Þ¥ �ÇAûVö$á4‚Dˆ/‘à|l •UÈöžÌ­ÈÚ,ltç}ï'µÈx—XÇ¥Ï,ÍáãâÔ£ñʾôf^ åx|Óœ¾¬„á^»gs2FbÚBcÓ}È8`äžuOÞ®2ÏàŒ¦;ìE]?Ç^z° ÊÜú,ov¶{L¼õ’Víüv÷w3¸N'ÿ¼Jÿp_ëá&HmæõÅÒjh } 釠1· 3Ñk­E „VEÌxçÆÖi…¼Ó�ï$“boÒYxà‡ïÅXI¼ý¦~.¥`‚ˆ$¦a‚5&–ˆ0B¨ŠÄ,Ùÿ޶‘×bݽh ÂcsÍ™#}IJöŸ‚ ò—Œd®Õ¥‡ >§Ún ¾V–w§ÍEg2Õ&f‘è]Р’ºI³`YTÐÀœ÷8Ùäi‚É£¢1¥W!–c*2hzkB¥šæÕÈb7ý!Ú^™ *ÒN§ŠNèmH-x&ŠŸ=c#Úœê©f‹`ˆ¦mò&V«g.9k@ ±Ç©–H&Š‚÷ˆ)UéøP¤‘†*-SÂ^ÖŽ­À­”j˜ÊÕõåŽÐ‹,t¢âV”/E…û ›dfèq‰^£×<úi´¥çE[.Ú,–Åk,¾ÓJkh˾ú€GE9Y@— ë·>½Eqÿ–¦÷š››Âú.“ð> )¹ˆJ0¦Ö<Ÿ¿}\›½W bÁ1†–ÚaXN¦†ñb1»æˆÕ’ îJªÒƒG›öãe¾ú*1°�‹Ô¯SÄ–H,¿@_V*¸…,éjÇ3Óì^múyTôÖ+Ýo˜h{§õ¸…ÔÛõªr%kè.„DÜôªc~mhœåxg%„ãuºb"#vœ ÙUêDÖ¾U‹]æÏRªíO¡wçS˜žèY­cÞpqΖ² “Œ Ósöñ¯?&ĹĮë)XåÂÝC$2«²pœM³yîfÙŒPØ’ßuxnªùCµâ²§µ‘-ñÊv"îó¬ÏôÊ·–ã*$¼o‚'ý©ÿ!oΧe£J=«ÉF^ü{lÅæµË$÷ûüé?]|ë‘LñJºç•Úà°×š½­+RÖAÝT¼d!÷1PXcÒ`”Ç“ÑLê(0#Þû6ø A]@?`œ\äôA jbP{Ú„õ¡°„ra!%<H¢GÐPƒ$la#œÆÁãl>ì! ½1¿ñˆ±8ß§¾õ-ñ‰ªˆ™˜šNñŠy1"§u°^˜p‹` £G8’1šñŒhL£×ÈÆ6ºñpŒ£çHÇ:ÚñŽxÌ£÷ÈÇ>úñ€ ¤ IÈBòˆL¤"ÉÈF:ò‘Œ¤$'IÉJZò’˜Ì¤&7ÉÉNzò6“  ¥(GIÊRšò”¨L¥*WÉÊVºò•°Œ¥,gIËZÚò–¸Ì¥.wÉË^úò—À ¦0‡)‹@��!ù´�!�,°��ã�'��ÿ€ ‚ !†‡ˆ‰Š‹ŒŽ‘’‹ƒ “˜™š›œ•—œ ¡¢£!ž¤§¨¨¦©!®Ÿ¬š¯° ·Š«±»¼Žº§•½“Áƒ’‰¿Ã̼ˣłÍÑ ÇɈÏÓÛ£Ú¡ÕÜà‘ÈÆÊƒ´áêè¬ãëˆï•Öç‚éðù‘Þ òùþâ°⧯ =KîþSÐ\¶v#6Òå ÃLøUd#Ã_m2d¢‘PrL·Šá,Z/ ¹òôÊQÌV5>›‰®æJš[:Ô™3å,™E£™¬¶”žÊVÕ–jG¯ÞÀ¤í¢Ò³IÕ)¥ªRq‚•Ft¬!SU™¥&,ê'·_ÿÓŠ s¬5O`iÌj×jYž[Ê»v®Ý³èòæ¢Ë6±W­~‘–<¹/äÁSïÅã{¸aß“–)ƒõعïPйš¾\×®ÞÏ¢«^öŠXó!¥¨1}öìÈ·a›¶]›±êá©‹þ]9sâ{5ÿ>î:øêÜwÎÌõ«ì¤‘Ë~Ø3»ìÀn™ÊÖÚ;,á·L}†wœ“il™ñŸÞÎÿ 9,Šmæ]´¡fmà#š€Q‘Gw­…ÕQYR5¨œ€N¨ÝbÙWÜA&åÖÞƒæeЇÁ‡%Ñ!ˆq‚6T‰Äy·`$�ý²Š?Éîá†âm*ªõ¢‹5âvcÿcA&3$„K¦ô‘‰õuúõŽBàX׃ fÙß‘°Äˆa„Í-³c€†ÙÞ[@æ^›QŽÃŸœØe´ž›oy`™lÊØ¤9�)iæÀµçp!Ê㨓â)×bjB¤(¢’(yc¡UžæY¢dÆfÜ|Y–ŠÝZÝÍ6fP¶J ž†‡f”¯Òú)‡ƒVè–˜öúY¿-ÊX¥Hæ +˜ÇÍj  ÂG*ŸWž:Þ­½n©¤º˜æªŸ—Ú*«©œÚv¨­ÝþÚ¨@z­´`ZF¬TÝ.ˤ²áê+…¸F(lˆ¼Ö é½Ú¨ê¤«[­”Iþ‹l«ãÊÛçŸÞâˆîÄêL¡ÿ• éa¼ kºì“kZlªƒúF̤–KÐÅ%áu¤U Öè™#l²  &,®7ç•.‰V©ß‰_ ¤U(vüòˆ#+íi¼Ú̉óÈò‚·N+R…R�æ´žÀ+×Z-ŠÙ=9K¡*×ZÏ`þŒ´ÕÒ鬫.÷—¨Óæ6S²M;u·ÞÁPgIàÛjªÕw¬N}ð;‡vI~5àpYŽzß3Šh —.óuÔú;ãuÏa»•æ›'ÇçK§÷vm/»‰Sívåã9gzW°9XžÜ¬/Xx#yÚ#æïâ ‘®íîdŽ{´É; ñÁÒê©Û—æÌN»ñ(û<¥Cq½³ ß,<;yÔô⬟|©·lõÅ͹üñScÿMïëw8Ή˘Mø…¿êIWr@Y,pö;Éû—ˆ@��!ù´�!�,��’9��ÿ€�‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûô þ qøÇaÑ@ø¢@;†ùƒ( A‹ :dGQ⯎�‚H˜H$É^ ÿm\Ò#/&/" V æJ–ÿ"ºŒeóæ ˜Kµ¹¨'&£›†"*K© 5‹2u45‘SCW“5àÀõ$€ ]ÚÊU'€Ž4 �èLE1ÿÓô)¬Ú 7 tåà-³v!Òź7¯\†­.D–ëX‘Ù6>©·ëʽbýz=Ôàp΂={ݪ62ã½�Hÿ‹Õ³¿ ¬¡U›xYJ7[ŠÔé1!·#eŽ„¬’ÐíÒ bïŒñxéØˆŽ¯ì­1QËA©#œÎÐxõ§9= /1ò“ÚßÖ…ˆúWäÿ¥ßll÷ j¯^O+HàôBr:9çßwÎùf qƒ "ý‰Ôà{êÅk®¨žx~×| ÀbpŽ˜œ|Þ…¢‰è™áp±eÌa$¹ÆÚq²yèh9UTá!160[v=æXd‚Vàÿu…<ˆÝkÆ¥5ár+’xœNøÉ¡‘¸ýb"Y"tcZå 6$”‚t–W~/r d˜]Zx¡l¤É'…wƒ#x) ¡YT–$ U!d\6D‰ºi“â`¢<¢ ‰}‚`º%„ mꤠ=jh¡²Ö’oŠl¹éŽ/Ò%–Ÿî§Œ„©åß“'⺗†ƒ ªSL"VÈ!œ»"j§¢c!¶kwV}GÜ_B6'¥™y_užzÈ$"Ûzi©®MvÆ«?U†kœÀaWÝã§\xǬ #F p-Þš›Ÿ¾8¢"NÎ7¡·'Âêk“ØÎ{ìJízWœuÖ‚K(|å:gÿ»&F|L˜íwP¼ê)[,W¦Z›."'s(ÚÈŽ-\ÈÊ,¬ãˆK*(Ã?˜íÃ3Ò¯!ºõl`ä¾h1²¯[¬{Ç\¨od²ö¬È½Á’:¬ÂÑEZë­’ôëE9]áup:´ó Ÿ›+· glª*ìdÒßJC#šóÌè!8[z²ºÂ2(VÔÍ´l2?ìSÄ22àÚ6/Ê,«…K½ªMòÙkµo¥<ïÙÈnê`ä„3§?±‘—¬ÆµVºù߆xÎ5d‹·ü3®È:ØrÖ䦊œ^ôµQ_™fGgæžv¹€¶tçAái®ôGoDìJ³m]wëÍ”&ùuÄ] þÿa®ÿ=àVÏ{ú_â”Ðíëï~âGÖþœa«XHŒâ«µ’¥éÛæAž•é[ÀÍý>'7=KCœ Oÿò” ѬŽgCNù5©ækxÚƒÏû´v¼upnõr„k袗Açq´#˜Œš¢X�4õÔv“ÇÍÎD5ÆÛ ¹—ù/š3ßb=Ñ%17"¡l´ã&ú…N„‡CDãA¾0Q0ÚbÀ´S2…6É«6ù1ˆÛ`Üø¢Õ”ñáŽÑ±cT*!GñÑñC£§äÇQôñ”è ?ÑÇEbE‘°ÁãNΡÃIZò’j›!&7ÉÊqò;“ü8NAIÊRšò”¨L¥*WÉÊVºò•°Œ¥,gIËZÚò–¸Ì¥.wÉË^úò—À ¦0‡IÌbó˜×�!ùP�!�, ��½:��ÿ€�‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œ�M ¤¥¦§¨©ª«¬­®˜¢¡ ¯·¸¹º»¼½¾¤±¢Ÿµ ¿ÉÊËÌÍÎÏ„µ Å×ÐÝÞßàáâƒ×ÚŵÅãïðñòó˜åØ çííÈôþÿ�~+ÐŽC- @ì+7J Ã‡#ª*wŽ`BçÎÙëîS5 8JI²$%‚Å:ˆB¢C±|ölRÀÀ‚›rŠ4ɳ§OA ^¸XÐ`vv6£©�gN ,,øIµêÈ¢ùê3Ç¡ÂÂnŸšæUj�«hÓÒC™¯mÂ}æÿÚes÷ìÓ²d-HUË·o¸ ù:(„«iÒºw£â-ËͯãÇË^vp»µ(Ü†Ì ˆ µ¬C‹ÖÅv2B—p¹V8ê�g6{ž:º¶í‰æLçKýò\¶l¯IøD ñã X`óS½zA+^�¹òÛØ³'BšŽ÷>ßè¼v`\‚ èÓ«— ”½žõVhŒ¨zóêÑKH ½ö`¢$ Šw\¡sW˜eRÜy4èàƒbÀr‡hß´'yøA!ø'¢h�Šbo»±ã•†“pèá6øÁ(’@TÀ¢ Õ1#„ð7â}™ Š6¢x•ÿº…wÁYš „3þ(ã,j¦t‰,heŒIä˜VY£Î€ µÕÖKÅì Ì(§œVÎHÁ!h–Á–ÓÝ÷%˜„Hæ ?Õb"š €š¡#‹›Ž$çúùøãŒC’g d°§bââ‹t‚y'¡¨šT⑉Àèš Xƒ}–Ф…`Pg˜ƒ|"§žÎXc…’R)gU‚jªÌ>Ä‘‰�\ó*:ÃÀ%Ó&pÆ”—òêÉ}èU9㲃øI¥„Ê™ûâ°Í¶+Ñ0öìF-�CŒ:˜W¸_z+¥®Έ"ä0;Yð©î6ìAGZ{ AsÉeLÿ%C,xzzÀ+æ«á¿T’ €ÂìðÊÿ d¢aÚdˆÍM`�x >¡ÁÃx)êÌ®! óì±ÉA{œËLϱ¡0Çz6äé�“®cB$ü>HizV&�2·SX!Ê Mv„M·ýÎÓ;zè1yBÒ>@:HqFS:!�LjAÈJ0ÀáÙ0Ù¢LãÙªìöäÉ ÓD!«šèh̘`€aàÝ£wÒ”îÔu„GnÞê¬ï‡vÚfÀ7•CSn{.'Çc¬“ïtÇÒZk3_–á"¤3¼w±£žÀ©Ç¸Ÿâå½hòíØ«ÀBÔªƒ”WÜSµÿ𿯓š6ìC0óî4{óð9x‡T.ýý¯S±oÓXŒN65a’Ìw™æ0‡`߃$ĸô(~/‚àŸÆ…¿ ºÂDJÂkÒç»ò.±Kù24 �$ÀJó£Ÿ=öµ^ªvŒ¡)Ò;¤ÄdnI’›ïRs ¼QŸ�œÑ>4ÄøùÍW`2â( (:q†…yÙoVó›#¡ï7„1ˆ�å’¨ú‘J[a¨Ø /zÍoM|¢;ÑÎ̓¿©Øw8`V9�J‡�ƒ`4§*e�l—ŠQ¨¤ä5 ‡2b! )Åž5:mtãˤˆÅ9V¦v›FÎ Ñ# P�ÿžÜOr>‘4©°A0Û¶¼&$‚Ë“ 4ŽÞIËIèïP³¢2ÈyacxìÐÛp 8C”’RE‹œØNçÉ‚:Hc-§É‰©Íe@9Œ#/—dŒ8^c“‘\ÉN6Dô|²o†£¦:WcðFŽrD‘£tÈL¬BP}&¿ë­óŸõЈw*vÀó P‡×¢Äû¶dˆSF ÔÃ(H€Zt(16ú?)Êå¸g7°S=´A%ýÄ'é¡|Îò¢0MÄ7OtšÃn:ÞK»Ä ’úD*K*ªOR‰¨1Mª$Õ›ïH7à;Ôoðh Iùô$ÿeâ éŸn€\ø¤WI T¥š•±°E0R¹½ó´²DHŠÕ’Š\õ*¹øVW¯J󬀯Ä(ÒÉDÒ­êTwºˆê8ö¯‡«òA�``¬%ýk`kš¤—gÂ!hßÈXKDv¬ àHq(@V¯Nv³›%a¼>+I †öP­8­d`°³`�l›'ˆ/&k²WmՊü±b�¾nI=ù[àÆn¸I…—L³o2·¶Òˆ¡¥RT0@ºèÕ+va«¹¸¨ã»à•Kè(ÉÒBb®é•.ì»^Z~ó€ñ­-“˜ÔôÍ¿+uL]×RÀŸý…)LA*£\6A¥ @¬Ä›!ªªâº[%€ˆ5a³Nø°n¬Z… ȦŠu±Ä0öʼn•{áHœèŠàŒ±Ž] òN‚MØ8ÞŽ‡ì´šLÌ��!ùP�!�,b���$��ÿ€!‚ƒ„ƒ Š …Ž‘’“”•–—˜‰ Š ™¤¥¦§¨”ž … š©´µ¶§° ®¼ƒ À·ÄÅÆ«¢”Š…¾ ²ÆÐѨ«»¦Í£ÒÙÚ“«Ï§ºÛáâ„°ãçèÖàéì퓵 ؇ÜÞÌ Œ•ˆ‹Ø!›ÃhmêG¨@À^‚`Ù;ÕŒW'I¾þ£¦h&dº@9¤ÐÑÆGqÊÊœ _“r…€‡éP"(W‚´Ê_ˆrÀÊ=Bva(B5ƒÔíU,«x•ªUÐH.5†2yr¦ UPŸ†$T³ (‰!°z"f¡¤\ôÅ«aÖ™[ÿ5Iz!Õ²Vo&Û b˜NG[©¼šW¦Ñ…~&lÚ«ï ¥ 7v}«‹0Äx aÖ¼Ðì!©ÞFKØg¾» OÖäxlkGŒYBÌhaʼn_‡U‹(ÔÑ‚ƒF›Z^aA²ÿAÔMµÕä˜MØfÜfsóÙìÅÏwAÄË|ù‹ r¤ÙªÛCB¿´×õ÷…¸S/êy©@IË› Gú1¡õBñÔJ~ý•–RíE‡Zfÿ‹MÄÕW„Ç­Cštüµ[‚ÿ膇‘W‰x·YÔ!DN'Ûí–ÛIÞÔf˜#öm–ÚA*q„™Ê€•¢^ϬÆß‚iaƒ“s/Â2Lÿ2û1s^ƒƒ}%Ü0¤Y²Ì#?2H–/DÓšNþ˜Ô•ÉßÁiDuO5IIÁeYS„šu©W[<ê•Ïq q¨¤d2ó•‡^Ê"⃔äƒ+6‡åq:zƒ¡ ’× ¤eA§$‚ÉHã/têØ¢P%-ʨm„~¸deÙTc5.NÇcI"-”£x*’3déˆ+0Å’Ò“»ÙyPø€˜+'¸¦Uâ`¬"÷Ìg•}·è¥£>6W(ô ëwÙþ³m·iùF®—eY`¾9³*‡g« "u™j ½­DB¯©ke«á&ú@å­;,\¸'lK”©*ì0-¡rùðÄÄlZ$Åׂ˜wLJ7.õêñÈ•`”'É(Ob%��!ù´�!�,��:���ý€!‚ƒ!† „‰Š‹ŒŽ„†‚”•–’ “—›œŠ ¡¡¢¦– ˆ§¬  ­±žµ ‘!¥”šƒ¾¡ †µ«ª!Ä¥ «’µ! ăŸ¼Ò¡™Š¤·¤¾¶Ÿˆ©“ÝØÍ¯©‹Ü‹ÎÊÈ·å´ãØœ¹‰ÄÀ‚Ý„¤‚Tñ2díÞ&ð08W"m©x)ÓVHâ%Š„R% 1Ú½W¾BÈIÚ»Žº`I2˜¤BM¶VíÒÔ@Ó……b‚iQeÎ_°jrLV-X´Úá<w ^3HÎ4 ˆ¨è+l»ñ˸µ?p¿Êu•u*+Ù³þÎ’«VT �!ùú�!�, ��½:��ÿ€�‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­ª ° �°³ ®½¾¿ÀÁÂú ÇʲÍËǼÄÓÔÕÖר–ÊÐɵ´ ¼¹ÈÉÊÙçèéêë§Û´¼º�ÊîÈáãÎÒìþÿ�þ»p �‚‚€¨%k–1eÌ œH±¢EVÊlíbx ÄAÈäÁ ·±Á­zSª\ÉÒÁ’éò˜ÑHƒöqpçŒ[¿–@ƒ ø’IýLê‹Yë–G] 7Þü9´ªÕ«Á¢Ö<À]³†´º*”õ±ëFf=b]˶í©e°ÿ@"5F0cÁ\ÉîÙª,¼“8Ý LXƒ|¹Ü)äҦ؆(ŤåL2I§e kÞ\xæSg²âmzpgWÅ]AÇËgò›,ªœc˪0<Ž<M“=H‹à<§ÛôBh{ÒÙÈ“¯ô¶4î=Ÿ1qÆ¥‰Ó¸¬„°D;MöZ¹÷ïDqœ¬ 5=ñH—“†O9î~>O¿>¶Ï3yÞeΓý˜Ó•e»'VDö%¨ 0·xuÐB’9eÚKÚÉN>ô<·Œd·Qµ l †(b(­Ý†Ï1½U¶TW¦±XOLm³ŒZQ)V`X#æ¨c'ÇÝŸ7ÆI£PXðÜãchz‰SPÿ-xqÇ ˆ;F)å#³sa<ƒLxË_Õ9£O<Ä©u‹j!ƒã”h¦iÏš^y$ãd^ÁK9`Åi£|;ÕxRv¸ø¸›€*è „j(›i&ú‹|Œ6êè£F*餔Vj饒*ªi+nêé§ ~ŠL¤–jꩨ¦ªêª¬žú@n*ë)b „ ¸æªë®¼öêë¯Àò ë¬Ä–Rk@·«ì²Ì;l±Ð‚r,Q 4kíµË>í¶›L;PµØ†+n®Úrk®%Þú“ì¸ìZ[î¹ðF"¦=‡Ð+ ”¡à;Ⱥ»"aÀ¿HàzÀíòJðÀÁ¾ïŒЈ'7xšää#ú*R[ÿƒ‹ð‹«‡ÀqÁºr<Á¿*Ìðɇ”éLZ+;KZ™-²¤$÷X™1¸¹ V©ôó�ȸ>à€‚ì«É('-ˆÊ8n¹ïq©Å¬Èn•˜y³®&tÁ?¿8?ÀÖM�`t¯H+²ÊýXÔ0:’Ë%C^-° ¤îш²ÙÎÆªöàl?cÝQ›UÙ…3Hãî-~HÝP½,ÕºY7A¯�¯Hè,ˆ goLé»rLpÖ&´@�§=øÂ…Ëuø,’yä€9m—™ï»lHÝ,¯'W®‚8àkç�„m:�M4P6�`-–ã€çª:ÿJf@± >{ÿÒ4¶ø ŽÛÜ;šYÞääcÌMâþ¶ùo‡õf!Éü¯Cëª?�[{Ã" 3’q¬�|Ñ�ð7‚½Z ®d7¾s¥Ëm†ˆ‰ü²µœLKƒg¢Gëç"Øä�pžÀ €„9Àcã…6‡«7ТzÀ ÇÆ £mOÜáØÄWA†]pƒ…ˆŽ!0˜;©iqHd-0¶Dpéϼ]s�åéŠhX¢ ¹G=íuˆ#‹¸­#†ÐƒR;_?Ø>B îq4©#þ¬X´] aið€CˆÎø_!D‡C2ŠìsÂ""áåFDÄ­wlâcÇ(ŽeÿFq|PÐú¨«�~ €,$õþÅÊèͰlh+ÿåJ3RŒ‘œäÚBÉDB\²“!üeî8‰ÇÖF?QåØÑÈ,6o”&PÕÏôg€žÊ‹¦3ÀÖxÑÌ!êòd•¬—·z)ÌÔ“„ÀÌÝ•ù�Z@Ò`‚óz�,²o»¢¦½HÀìMP’ßlc(g–Aoe2q¾Ô#:‹‰Çs®ë”ÝÄUÖž‰€p¬›å¡?q%C3’,|§7¯c))/“ç´j³ÉáM 1ƒépp¶·Ñ-t2Z²ÖHŽEW X6wÈ‹&äÊ¢eü'IKš™÷4J_1^Tí²ª2J?UÖ]ÆT/Üñ ¤ š?÷& Ñ!\ D¡d6'2B@‘#[ãR5U«šäÑ� Šðʘ½F¯–£ ]ú À–?~= Î&¸7}`†$d)÷ö½Çæ\ÐGfص?’Bs�>û*€ÎuVéb‡Æ{ª òÊk¥B[k1kªŸ¡j¤§(EVë7±É5·hJí:xÛ[ý¸R®:ˆ[Üv¹;êT¨¦KÝ鎪UØÍ®vWUZèB Sà ¯xÇKÞòšÖ»èM¯z×ËÞöº÷½ð/!�;�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������tkHTML-4ee7aaa953d6cb59/tests/page1/image10���������������������������������������������������������0000644�0000000�0000000�00000006027�11512242631�0017427�0����������������������������������������������������������������������������������������������������ustar�00nobody��������������������������nobody�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������GIF87a2�2�÷��Œ’Œ¼ÊÄLZTœ²¬lvtÔæä4><Œ¢œ„~|ÜÖÔlfdLBD¼¶´ìæìTjdÄÚÔ¤¢œt‚|,.,<NLœ’”ìöô\Z\¤º´ÌÊĄЄ4.4|vt4FD¼Â¼ÜÞÜLNL¤ª¤üöôÜò쌚”¬®¬lnlÌÒÌl~tœ¢œ¬¢¤œšœ\b\”ŠŒ464\VTTb\djlìþüDFDÌÆÄìâ䬶´tvtäæäìîìÔÚÔ|ЄļäÞÜLVT|rt<64TZTD>D„†„¼¾¼$64DVTôöô´º´ŒŠŒ´®¬tnl¤šœdbd$&$”’”ÄÖÔ”ª¤äÚÜ\jd¤¦¬|‚|DNLÔÎÌ|~|TRT”š”ÔÒÌÄÊÄ<><”¢œÜÚÔLJL¼º´Ìâܤ¦œÌÎÄ<FDLRL¬ª¤üþüäúôœª¤¬¦¤4:4DJDtztäîìôòôÄÆ¼äâÜ,64´²¬,*,\ndŒ–”L^\lztÜæä„‚„ljlLFDìêäÌÚÜœ–”ÔâÜdrl¬º´äò줮¬t~|Œ†„ôþü´¶´TVTľ¼t†„,24ìúô\^\„ŽŒ|z|¼ÆÄÜâÜüúüŒžœ¬²´lrlœ¦¤œžœ\fd”ŽŒäêäìòìÔÞÜ<:<T^\ôúô´¾¼ŒŽŒtrt¤žœdfd$*+|†„DRO”žœÔÖÔÄÎÌ<B?”¦¤<JH¬¾¼äöôÔêäÄÞÔ<RL424dnlDBD$:4”–”,:4Œ’”LZ\„~„ÜÖÜlfl¼¶¼¤¢¤ÌÊÌ„ŠŒ|v|¼ÂÄLNT¤ª¬üöüÌÒÔœ¢¤¬¢¬\bd46<\V\TbdDFLtv||ŠŒÄÂÄäÞä<6<TZ\´º¼´®´tnt\jl|‚„|~„”šœÔÒÔÄÊÌ”¢¤ÜÚܼº¼¤¦¤ÌÎÌLRT¬ª¬¬¦¬4:<DJLtz|ÄÆÄäâä´²´\nllz|LFLìê윖œŒ†Œìúü\^dÜâälrtœž¤”Ž”äêììòôôúüŒŽ”¤ž¤dfl,����2�2��þ� ´wíÆ¨c6ˆA(– 4! H/âDD!òs4GJ"<¢‘Aš >Y.ü³%HÛƒ¶ ¡W¨˜˜7!J”a‘ßEˆø‰¤„†hš¨ŒaJÓ3< ð<c¦É–-mš˜i+`HÕ1QžôYèèQ #B:ù-êQ…Fs>A»%”¦(¶ºqOÑ3[&¬ÚâjÈP®¨†Cò-ПhyTK”ÑEæ¨Õš¢[eÒ½‚–D–{܆©Þ6dˆnÑ Ü›íÆÓ1bB*¤c²edeázU¯¼[·˜=*W†M3!·>µºUºêaO”‡ï ¤!Xîþ]²ÅÂZr˜ö‰d‹B‡ÝJåªÐ‚Ï¿zYà ²¡Z—V3€†i¦ðqI${ì’%XRBÇ`bˆ§Ü¡žeCÍB&ªS?+P >™tÓB/?\Å-.ÔòÉ <Ò7ì1 ™¬0N0+XBD�mt‘‚GG�'´ÐÍ +#O0PF¹Œ %”€9™$ )¼…"Mp„<¹“Ë8)¬ sÝ ¡ÀE*JÊ#ˆþDé?*œ£‚9íˆ3Í:4L³Š7ÂLÓN–‘„I Á3Ê 3@²ž‘h Š!ÝÈóá þ(£L0£ª°Œ9%ЃҰ9þ °ãG<ìôàÀ v³Î0 ”qÃdC¡Q /¨<ñDL¬@¢¨øìÌg”ÐN‹¬³Ž«dûAlë O¬ L�åÌÀ‚Pk‰D¨ôó„<L*›‚2)àå8æ(‘„ ³N[„#8ÔÀN k4)Œ`´QŽPìÅ(C$ñ.¼$‚£Š™ŒzF´í4 ‹s…7_ôÀŽ=„#Å <±Î¦¤SÎzëiãÃ0ýäS<ø¬à…ƒÓq&㜡jd³9MŸðÅ$×àO¥HzA:Џù‘H©X1Ê.ùäóˆªà£ÊÚ)3ÎÛgX²/ßd ÌS¯,þ5$ î(€` G|í‘f 3J.ùŒ²B.Zt£Šä™ÌAæÐ‘Hµ4|C9Þ¬;ìà°Ç +d0Ê#Y˜óZŠSñ(´ƒ› SÞö9¨6PÌ4\# è¢w;I/7à³Î(Md‘…á°'^q£˜mì¹ä²ö½æÈͪð߬ÃÔ|€Å ™“)f€,[Ö€ÐZÅ›$Aý(Oìr‡ªTŽo ‰Ô:†÷¹Ð‰n‘à@úFaŠ,€ 2†ÓD:*6„Qôãö»_�r±‚Qsâø ˜­UD#yèÇŒ²Ç VÀÂ(†‘„M´&ƒIØEä* *dndþƒòÜðBç o"y4``Z1ÜÁ†˜!õæ1„Ch ‚‹ËD&ò„/ïMc4 `½ARp M*1Ä–A£¸á<¨HÅrP‹n‹0Ff-áŒGôGÿ‚6¸p-j`†L0Š$h ‡˜žµ˜‰{I+ _\Ç7†HFrðÁ™ ÂXÂá j€*0Œ=TlT<þîXÉÿµ Óø] HaðøX1°‡=¬ÐDI»=@rzOà`“܆ª�²*ˆìe ø°‚kDâB0æ)Ñð†»@{¹¨-vǶÙrd<Ô�Á' S, ‰þ¸"ºÐ…µ` ˜‚!´°‹Ååƒz-°“¶8Ž5�*‰øb«æ™uüÃOÀ)²ð‰[À8G¨ % 0…<@B wX±¬w»”`´8¨ Ò x›\€)6Q€àEè„eDê c»Ñ�—â£n³Ò-ù(ÏÎ ÃUõüÇ(Ìa‚,tADF8>€ƒ #ˆØA ` S`!òh*“ JM�ZSž}à&¿ÁSl• è‚ ˜4q¬#9Ȇ`E,ñÎÄžòŒ°ëÀ,¿’‘ ­#xäÐéVcЇO|‚nØÃžP"°ã¶�þ)bÀ‚Va Æ&˜P ‡¢ªF1ŠAÎ~C“äXņg>lu ŸaÃ'IqÄQ”€hPGÐ1ÖÖ´`0ÅVqì ³Ö:02ÜUãD8ˆ�sÜã`ø„) dŠ_DbÂ@„-&à6¸  ˜N+6P 8㹸Æ4pI÷sÉ]8ÂQÜlã æÐg`ûúËKÌ#«8B bÀ'ÌÁ§hE+ø)ØZœ¢`XÀÆÖ^‚ŽŒœ$V[,4·hî'#‘‰uàÀ#:PÇÐÁ�¸`§p;ƒ%Þ xa`c¾ðÆþ’ÁoìA¬Jf`‚&Ä hG8à€GX`HÐ:\à„F°¡§`Ã#ª \`}€‡"²Ñ„"‡È6%ŽHX¬Ip4p‰=D*@ÁHJ�ŠVÌá@‡ŒÑ‚ll4 MhÂ~i‚lÜ€7¸A$†À‚Õš# ÷hš›€LL#… F¦½â9hfl(Ã-$ ”hºˆF$ðf*Ž¢O¸À@ u aì€Ã8§ Hâ­8�²ü"ç)âh‚)– Ž`ÁÃ{ä‚17ü¢ 1G8â‘.œa BE'4�+Á¶Ólþ/` €I‡påýÌQ¿G€!%ðF'¢]ñõD›êyC" ` E´ V�fГ?a6…¯‡}Œ'`AX9(^q~„“öJ€ ˜‚*PDÇË¡ˆ (‡1XÀ Ö0S4áÝìP[†*RœñÃY¿ø$‘‹¨CMa(Ž.ð&Ô”rN‚8âC颹Hèz h=(T‰*H�0×Þ$äÂÉ!=&ä×buÂåÝ"©·$‰;dbÃÐ@$roÀò.JÕ wÌqg€,\ŽA|�#ébýûŠüêCDØ—= 3}‘�;���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������tkHTML-4ee7aaa953d6cb59/tests/page1/image11���������������������������������������������������������0000644�0000000�0000000�00000002621�11512242631�0017424�0����������������������������������������������������������������������������������������������������ustar�00nobody��������������������������nobody�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������GIF89aK�7�„�� š‡’?6WHBÌÊÈL*'vha̤ pH8†k`¶§œ1)&ýýûn8)nYO«™çdoȯ£¼@Dót“QE%êØØÂRQü•˜‹xnû°´º¸¶_TOÙ×ÕH94���!þMade with GIMP�!ù ��,����K�7�@þà'Ždiž¦Õ)ÏdÏFXhm߸h=…PŽ cà‰žäb¹¨8ŸÎA'G­Y"Ac»E8HDAÉ®W&ãð,¡σV=u8¡Ó±h4>  CD -n–npSu" 7ML 0hN«BMµztU3ž"nÀ`d,/Œ–H¹O2½Ã: 3t L¨ªoqIJªpä èLÀ 2}Õ7³˜Pëýrö� àÒ—‚‰ÕÊA3#nÊÁq0 `‰YHØH¡£A`®ÉÐ Q«EGþðp ’iAaÕÈyÑ‚…ZÄéd·$‰«W,2©äà´ Ò*æ°°’æbïzÂháÍa3tð°ÔÄ+ N=mpÕ¡H’ŒpeªõõÁ<{¨áP�€Ý»xóêÝ»7ÓÝ |÷2‰`'‹(:ð@r®ñ9V ä"¶È#‚#Iˆ ^ îÉ“«àÀ²A§‹R:kÌûàx Ç‚\À0#†ªBfC”¬Ý$9´…Œhi€À¬Â‘k’Q]ÓpÖQ'r”Ú³ A€ @˜p¡d±%°Ô*�ÂXÆŠ¶»®iÀ;èõòˆ|ò-:‰ó2¯ÄBQA¬þ”J‡UcÀ&õØ@@ŽÃÄ�k¼×Â2,±šj´x–Ô0Tð@„6(�M.=9§€Ë(¢OV+…Xz èËW´Õ¡‚IpàÊB0¶†kH@”Š4=ÚJX>N"$z/²à‚"t˜‰ßA)Ú`7 o ÃhM|µHZçHÄ8•¨G qQA@š5Òw *pöf- ¸ãÄ]© ÏÐYÑ�˜ŸžýYKgM<Ê8•Úƒvµ)ö c™´Am¤ê �(ê&¥Ä]#Ϭ¸ ?o,@«žDHQDê 7*®(pA�†œÖÊJGxÁA3›É­Äþ–ÐseëEDGRÍäÉ™KÕ’pn5·Ð† 0ÉC¹É`¹#Ü–[¶`ð‹‘i Õ†¼¡ˆ9Ù t´\ ñ›/o,£±=áA�œ"Ær+Ç2!½°¦CQgÉÈš©3bm @lTžG¥…„¥xÃ$AjFßLûb�ÙÀõG ƒâÇ/$äšC$1‰-YÊ „ˆÀŠ~: ]´�µà9!”##ë3« VcÁƒ9^ô‡äå 8=q[ÒüŸNp¶'x@5L¨…†zø“Øh@œU‚[Õr2à¶zYÂ:aO"®¸õœþ¹|8ÄQ.ým'=‹°)aºDiS™¡�Ö¡’ äa9) lºê!JÄ CG»1q_˜Ž;r°ûEÞ<hKS½x%$ª„œºÿžÕÜ(† Uy¥"ò¹#8LºjÄófÀŽT6Üï"Áe‚#ü6P(!€I²®ó¡„3ذƒBQ±š˜`da">¦ ?yè@È‘÷>€ÊIæGŠƒ>Œ� `4¤d’òŒ8¤6±·ð¡gkã’Ìô4rìÄuKÈK?6CŽõõ03¬ “˜~a—'ÑQ�ÀÔ ,•—7¹¡‰‘Š˜µ± ‘‰X„"Ef*2�;���������������������������������������������������������������������������������������������������������������tkHTML-4ee7aaa953d6cb59/tests/page1/image12���������������������������������������������������������0000644�0000000�0000000�00000004644�11512242631�0017434�0����������������������������������������������������������������������������������������������������ustar�00nobody��������������������������nobody�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������GIF89aP�F�¥��ççæ°°®Ž‡ˆ…vusddb||y—˜•ÉÈÈÏÏÎmmkFDB$"" 1,)MLK··µŸ žUTS><;840þþü]\Z¿À½"¨¨¦ÙÙÙààà‚~~‚|ððñÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ!þMade with GIMP�!ù � �,����P�F�@þ@pH,ȤrÉ$2–¨%ˆ€ªÔˆÔ¢`€¨ îÖò +„Šóðp1,2j¢¡P6W¨4{µÓhg [BU zQ_^�UR C G MD € �—B§�h‡¥B  ÎiÓttCiµ_²Ü©Þ²B�i~CêÆÇ³óâÎëþÿÿˆ�Ø€ ž<z5H€çÎ]< "΂؞ŋáEÜh/aG„ ëa0Â!A :((p¡Ú;0Èà fƒ›8˜È±çþÇ�8�J”A|èq< `@H&À@BJ&¼¬ 3ÍšrBXÖÌ_‡í*jÀ‡áäÂhv˜;W³çp)P[¦/íhZ@ØÚ„Ç—u°ËïY^½©Vµz%a‚ŸX³¸)¸"”, °�ŠëÁ¢aq:`P©!ªX¹Rùq·oB(xÎèTæ`ù~¥M€âàTXPÁé!°.x}›VîÝEP’@a‹‚ ˆ¬L°…h0’ìa�nN ¬�À `ß„úH³’eK \€Á+ä±]h!E‘À>ÎpVZï¬å mù—1þLãá‡"_”hb‰C1A\,¶ˆVx aC4ÖèÐE4Âó9&-tŒ@! d†)}Ç\L21 $<4Ñ“PN€`@eXf™ÀnA4ËxQ’,ºiÅÕL_Ù”Óš7@×YñD’8Þ @•Tbž 1åcý@Æ×SVÕPp&„FGbd•åZî¼øf]:Ù¦¥l AV/5êèýØÆé©¨î@SXp€ˆ¨RÈ-‰,²…# J¢ •\¢Ýs @sB[@!RÜy^Š'…y¹Z²^-¿qÁ›9 l,PþtÖÝ‚Ó&2Äh À™l”YÚgšqæÙ,E´'Q@}£lÚí&‚Å$ z†åÅ¡Ü&d�Uv¼,°N¬u±È!'„8Ö oÇùFNpñWÄ (ÖM¡e�0,Íëa5.PÀ‚0…³¶J+JlL\ 0AW°¶ÀNOò"á>û|ëõ×# ±ÝºQ|WmyçyQÄ)ýHHé;ù’Bºñg÷Ýv‡™jÈh@ŒsÅèDõt¤Œs¹˜¸‹,žE¡U¶E'=ø ÀœhbÙØÔ7Z%D >Qع$PÕàkQY¥¡ìçŸþ׈—‘è¦[¸§žlaè;ï0u�꩚£ŸÐ€zfš`9€5”>õÀå˜Wo=¡TTú—z“³(P@‹zÕ|jl6 @Ü…�|ð_SåÙH>þéÌc†¯Àä£ÚùÒ×€è´mBP#ð¹ÝuÉOrYÌ:À›%ÐÏ/Á‹Ýÿ�´<æQàQßšFYþ–8‡�©O5»¦ø!€î¥jPUZ]òª1Á˜Ë†™@ÓðŒ7M…Û›^†bÌEà\‚Õ !˜Æ@�A¢§HÅ*êå `€j˜ªØ.¡«xQ��QHÀ-qfñfB€ãþ >Ntb,Yl͇F¥‘Ñ]qdÄ,Ñ]yç`UyÑ­!`€Žˆ™DÁœ€)BT¸ AŸ„Õ¢ •ØÀ†- Øj¤°B€7<0—¢FÒÉmQëh´��ΘŠD”C P¿ )Øë’$a&МWr`,uxq¢°ËZ”ÑŠœšXs†f„b´’:¸£û؈?ZA¹Tã²Úx´ ‚À_œà  �—‚A¦[I‹B& ɰ²!Ò Š¼V'Æ µe'Ø.ºUK}²§¡”VƒL9l á=k€±�€ d¬�ûø×.#ˆS ÓÔ%/ËþøË(sÄ4f^"ùž°4éE Àp³~ðÇCÿ Õ° L 2k�jVŸ °F&¦‰ÆJZò:€ãã%ЙÆ5t N«™SЉ` ƒ…å¨ÂSa5ã;µ;ŒB‘ÏAfá Zæ4S·Q¨âcƽô¤”8%v³ûš×ˆˆ†ÚµŸ£Ì«)ôÓI¥å"ò(O¬Ò”þàMÌP€±ä˜Òj˜Âü*,ø1¡Š8É?ñÆ„åÄÚÖ–¨C@�@nt„àCÿˆ@„+¡ Í·BXQ\è²\¿1†Œ‹®(NØEK®³õ„Ž"ÐÇsbuÜn‡þ»·`v!ˆ_ÜW¸íÉiOÙÒªBw»9éIÑ#]ô4�+*N÷ГAಘ×ä-ïDt4'q4˜N“ ^^J²ºc´.K1 ¢#E£Yӑ釧ßa(¾C¢ÊB&Ò½¨Xx„CˆUTb&ª™¯&MqOxÒ¾+iéÇ[: G¾t€(ªWM)°ÏZò6'Ï‹’œ´ç1ͨP÷HŠA<€(‚€~Ñ0�·4=9}Ï“›R:²'¢È/‘ó–•b›]µ�èQ™Ždæ3° 5Ff’å ±~öspðü(#¸8|Ês2Xþ\Àâ²èGö€ð‰ͧ·/%ùÏ8ýT\Ÿ ©+\Ó"ø¡ŽÖVH~KÁÅÐP 5ö`‡¨�öyÒ Ða¤üaÙÐI�C« Ÿ«î6†¤ž!™Í¬‰.C„»t<j½ìLÍFŠ„Ý~Ƭ(Q቉aY,õ&¿±ºdDÔTê—}l&‰KD7bFzëL9c�ýE®£¯«'t؆ŽÒ·ýíŒf üT�ÐÀ:¬Ä%ðø ÅÙªN�Þ{ �;��������������������������������������������������������������������������������������������tkHTML-4ee7aaa953d6cb59/tests/page1/image13���������������������������������������������������������0000644�0000000�0000000�00000007751�11512242631�0017437�0����������������������������������������������������������������������������������������������������ustar�00nobody��������������������������nobody�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������GIF87aP�8�÷��t†„¼Â„´‚ŒÜåá,BDŒ¦|ÜÒŒ„JT”Žl´¬¬Æ´Ü°¸Pbd´©±üóÙÄÔÍœ¢œ´³´”‘œ|šl<2TLEOÄÃÄÜÆÌ$$'œ´œ„‚zľ°tmtLRTôæÌTrDœnt÷òç´´ÄÄËÎÜÖÌ„…Œ”ž¤äå씞\”jt¤®´tvyÌÆ„\Y^447ôÒÜœ´xddhÄ¢´üþë|v”ÜÛܸ¶t¬¤ ¼º°„З𖀄~„¼Ê¼´¦Ì¤ž£ÌÞÜÔÃÌÔÍÔäîìt~|ÔÒÄ„’„LKP4&L¤´¸ÐÒdX„lko¬¦d¼Ã¹¼µºÄÂÜ,+/lup¼½ÄìíÜ4T4ÜÒ¬´®¶œ¢¬¤’œ„‹ôôõìÞ䤒¤¤Œ¼Î¬Ü¾ÄüýÂl:DÌÅÌÌÌÐ|y}^^bÜÜä´¶˜¤šÌ„œ‘|ƒ—”ˆ<<AøÂÔT\\üâ켵̌†‘ÌÆœlb„üþüŒŒ˜ž„TNl¼ÄÇäää¼²Œ––¬³¤ÄºÜ¬~Œ¹–Ÿlvd¤–l„X`´Æ¬¬º| <Z<DDGľŒÜÞ¤l~|ä¶Ä\ddŒ’|ìÌØ¬v„|Œ|¤º¼ÜÚ¼ôìôìÕÜÌ®´”‘“\vd¤´ÔΔ¬ªtì¾ÌÄÆ¬¬¦µÔÕÜüþÜTjT¬ª”ÄÖ¬¼¾œÔΤľÄÜÖÜœšt”–”ÌÖ¤¤¢|<>TÔ¶¼ÜÎÔ0:<üÚä¼¾|¶®É\^|¤žt´²¤´®¡¼ÎФœ®lv€¼¨´ÌÖØ¤¶¬ìæð¬¬°ÔÊŒlfmäÞÌììŒŒŒx¬£ÄÒœ¼º¤äÜœäܰtrv´Æ¿„š|„v¤|~ƒ¼®´|‚|¤£¤TFTäÊÔ,&,TTYüêÔœœ dV\TMT¬²´ÌÆÔ4.4¤¤­¬” üöû$$äºÈäÜ䬞ÄD>D´z„¬štŒZd¼Ä¤D^D¬¾Ä̽ÁäÒÜÔÒœÜÖœ´ª¼´µ¼ÄÅÌ„„„TvTty„œ²„̦´¬¦¬¼»¼ÔÎÜÔÓÔ„–”,����P�8��þ�ïH° Áâîˆ#–fˆ3ï¼õKc)áKwhˆÃqŒ¨ØÐI²$ƒ(S*gÑ båÒ„2ã/Ôzr^@5g•(¡ÒTºl™2e¥ëså6Q$žTIõ`Ë\~¥ñç-'?*öä¬g&¬2üFŒ ²‡Ê“uëX1Z‚à Ž`òNq:5LDË«U¡Õ¦™2dÍxóV±™!ý†@îçme> …)…ìP -8µè¤ê‡å*®,Ø*Kb| ›I\ó¡í‡C^½R1‰\$|±¡` †ñEœâ-²•€Ç±h¨úu©È²uJ.-aÛ°ÊŸCÛþþöóGÞÌ¥jxWÞÓŒÍ(+V@PÈ×ꘂc<x|ù’Øo©£šuTÁ†CipžxäÕÄ*b0€É+B8Dí ’H"šL‚5Pc‡X@‘Ã4_LÅ|ˆ@ J¿„WS ¡¤Jw2Š7=¸¢N‚ˆQ ,@, †ÔÀDIè‡%æ�‰1y˜RIÖqA8¿ 0Ç6–wAmT˜B¨ÐôPxX¸¡d"H$—Àò DA�Oì1ÇNÚA‡.ó�ÃÃƨҊŸT]k ¥â üÌT?¨„²æAÙ™?iÐ^õð‚:’ £ þrtQN ß=ñU=ÑBË LàFd’ ¤àâO9^ öK?õìÊfPŽà¤Ù¨øó õÔ“ÆxoÞ89pÀá9²°$Ž%å P ÕM6ÅL‰ M0Ã@8�Š.~HPرV%¥šÑOÀd1 xLà‡x°€G=¿„RÆCÝ݆A$ž00ƒ áð‹¬îîó…e\ð$ƒL4g0Óƒ.´�29�cÁT‰ƒÂLŠEA…Ð1xôPŠÈ� åÔ6^?‡‘uÉ ZhA‡ Üt€G&I7F@ü± Æl±…4̘àÇ<sèúC¯~øÌ‡þÁ Mc�L‡ ‡.mM€3„LA½iã›ð€’·.ÄË»° ƒoX ÃÅ@R ,L!º`1G4ó´þ…yøL ßw¤Ò {Ì;£G;LPƒÙàØ]w©pœüx¹¬p‚JüÓ@ÿ0Å#(r»´±C°pÆÌÙè Á-èã ™¬¢w² ­p(GŸ!ƒ+RXÀ >.t> ɳA©¶‚3À ½È…;Ü P"�lhDâx@®¨…÷L� |è«|H†I¡ƒ¬blÝðFb#*È$ ý�ÇäŽ 4¡ gàØvº3„™\ þ$ KMH@…z€þè† Î°‹îB.Pð&0làÐÀCn¡(œ9ÈÁ*ì±`Ø€.ˆ8¼ŠrÔU©HM¶Ò&Ð$(áᇦñ°ˆMc ›Mf³;Š1£ 2\Ðd#ºÈ: :P ô €ŒLö(ßcbTÝaLxÈ2´<JŽƒÌ€¢ :`‚iðà i(‡Æø1­3 ò×@à ³ ,p~8Ãì‡U€ ôàÇ1§aEf’àŒð»ÃˆpÇ1éNJµ ìÎÌF")̳ ¡àCl¢%¤1MXÀþà¨0~Ðã“Êì²1 hš¤˜Æ*à62avá=BÁTÈ„;fÈ *v×DB ‰l‚:…ÁŒæõ¨‰ Ráh)æœ" Nøñ•fÐèÁü0žÒãÓX0¾pÅ3‚¢ðÛ º9Ï `x€F\@UÊ@¤W•Á#®z† � . JÂp²Ošú„Pø æ�Œ{ÙÃÂzä1¿àÉ1ÊÀü°&ŇiP—©¨‡./@sNÃÆ!×Ù‘Þx°%´¼a†Pf,³!,=æ@ÓLJ †&°š¹ ‚£§=ÍÄ#šPŒzƒÉšþ€?¸P†qþ°˜â¬1÷xE£ø488¾ H�,û,©ü[~èD“þôçn% :,3b«XÅ4NÛÓläaªÌ `{@\@ÁƒLe’“P�ÐpEô @‚Øqƒ ?„¸…™Ìa³4M°? +Ï^�”µh3Á°Ýîf . ÅÀBŒœÈ¶©*4Ùàcbb2¸Æ¼pƒ#8 ü€  Â¹› ¦úÉOÏ6ØœXȾq:a­"Åh_v3!X !ô°Á°GÚÑ!pïA³ŽL á7ð�á)¸ H¸†þ ÐÀp4&“%K¨PX(0ؘÇ8 q)|£ ö8ri™ < aŠ00ŒÀ/uø\°D/“eœÄà ��€ XCЏI‡;ÚN£ˆdÍ1L%Ð ,ô˜û�?öñD�à×(éƆ‡AÈ ^P„=|?oð\`)cÐJc‚c 2"nà ¬ö Å‚s/� <8²M`ÁìFgN‚ãÜÏôï¥ð‚7 YÍ.@ Æá…q a XèÅ ïPqó!¸-¬¹ý ?0#ÌHÁdí ðáDˆ ?2уl€5Ë`A ?ð|i=Çš˜Ù˜@»þŽ4\Co°¥ ÅLd*wøEFËA €£Õœû˜Æ?­8Ž£XPÓR_‹Kp~pdMÃñbš;çà (=Àa)¸€´x×üˆ3@bÑäh(F .�œŸæ<7©%…7(Ü…ØÉæK:Ì´|"—¦ÐÊsVk ÔÒàŠ`Á€a>Emaö0Æ445Þ:Ø Êq4 ìÕ5¾ñ?”itzÍ0 —°üÀ 0FëgSs@˜V&Þà:tà ÛÉèž�-Œw}|–ÇÉ\Ò àÐÀ¦u «ûA°Žw‰ ¨0L�#MTÀ-©þ°ÉgÇž ~ØÇÄÒ,[˜¡ | Àv¶3Þl*D þ¸eyPAîKŸ»Š~°Ã 0*ØÀýÁ6`t ª§ô£GzöH±‡meCÀ²Ã{ÕhÀgÁ4µ05Ý gàÐ+UÄm‡ ^Â7 Áõ@MÀÀ{ÑESOõH\6lÍ´n— C \PpXÍ‚ç†4~Ð/ðg ;ï‡sg``}ª—`ŸEƒ¥×esq ô0 �HF�MÝr çITdøÓÙp•kfðH?È}k‘vä™01¢H°Ý_ˆ æÄ)þ{ MfXC5´x` ~@{S{Å‚ u O I mzhEÙ ^xÓ 0‡á"İGý„ ü”|5$9t@` ×° ”˜‚Tñ,è‚–'ôpZ =�UýÓ«PJ´€Ñ##ÀVçI´&p à=`FƒèrøIüp`¥ — ލ‡2ðWwã%øY?Hnfx�cEtP À KhŠîø%@}ÓÐ k µ¼†ókq`:@�û4•“}À@ 5DEZ<2ði, þð†ùx¡p«�˜dNyhEæ^€=e )þ«ˆi äHEI32à®À†ç·ŒM8U`),_a#Up×Ð’,p ’Ái°;þuºpTäˆ,ùMàf@Ý脦„L“ Uˆt 97thŠpPYË,ÁTÀe#0-Y  TÔ=p ý% Éø @é UŽd'¤X×ð-) 0ù" ‘spnfhO;0<Špoð•ç7–×a ˆéÃE6=pH.�™tÀíø"° |„in°=`?µðˆð™`I…zY ü° S¥bR ra¦ëØx/"D`àpB~ÀM`Šà^Úðg0 %v/ÒhDe°™ÀQô±ðQƒ¤–~A™S6}Õ¤9Àô}v öÐ ÿ'Ÿµnt Ù°7”HÌ xþ×hAɃ6 Ù`gÐ?/ð™mH0Á4D�bÿ4 `@P:€{1i-ÁÄ9 [ Š„n‡·Ð §èŸj$êF`6ðP2zw ¡PÀ`ìÔŠ÷3J)¯õZã…F2ŠÄ�bj «[dDÙ¤Vñ~GÚD<UY퇥bêŸ(OT[W:¦X�;�����������������������tkHTML-4ee7aaa953d6cb59/tests/page1/image14���������������������������������������������������������0000644�0000000�0000000�00000000065�11512242631�0017427�0����������������������������������������������������������������������������������������������������ustar�00nobody��������������������������nobody�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������GIF89a��€��fdÿ�ÿ!þMade with GIMP�,�������D�;���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������tkHTML-4ee7aaa953d6cb59/tests/page1/image2����������������������������������������������������������0000644�0000000�0000000�00000000052�11512242631�0017340�0����������������������������������������������������������������������������������������������������ustar�00nobody��������������������������nobody�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������GIF89a��ð��������!ù����,��������;��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������tkHTML-4ee7aaa953d6cb59/tests/page1/image3����������������������������������������������������������0000644�0000000�0000000�00000006621�11512242631�0017351�0����������������������������������������������������������������������������������������������������ustar�00nobody��������������������������nobody�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������GIF89aH�Ä��  NŒŒ JEUYXÁÐÏfdŠŒ13üüú²´ÀÀÀj¦¤ZU.ww157ÿÿÿ������������������������������������������������!ù�� �,����H�@ÿ $Ždiž%�‡Àp,Ïtmßx®ï|ïÿÀ p( Ž¯ZcX8eƒH­Z¯Ø¬v[0¢r „xL.# €¤,`n�žt>çÖî¼á�“> NK?tKyn|;…AKa‡�:^q?e k›dprRŸch¤¥g˜3x©gЍ›pšy *�®‰0±n½µn1®’*j5ËT ¿Ÿl©p ÄnÊÈ©hIØ»S­Ý°¥pÜh” »‰å‡ÁŠÙmÁiõy’”9«@Ñ¥(P &ùv™ñ.�ñ>íñe_*$#,†€T¥BŒ„möÿUÊŲ¥Ë—0cÊœI³¦Í›8sêÜɳ§ÏŸ*J´¨‚� ø°QÐ飸‹¾Ä!dZ #¤ã^`#zõ¢€Œ Œ £�†VC0pM…« ë”Œ  Âˆ+U+£FíB{#rÊÚaÔEj`š×Ö*ÚU2‚‹ƒÜ-{Òí †>'öÅÒ·ãÚFþºà3Bq™ÿ¾Õj ,ÓëÞ½Û�2¢¾Ñ 50 ãÐ3„ ­¼ø€ßD  +4ÁóÜ žNÐ8ú�æ ¬§ì›+ñŒãÃ;gn]¸n‘뱟IŸÙtÙé‘o/î6}ûºç!‡Ö|à¹5PÚ!÷Wÿ$ÏI—\Ýe—ßyiGžs¹ù†ÝnGtH‚Iv„(âˆ$–h" –b …cR‹²øs¢m2‰î¸ÒÑŒ,¤R?&0sŒŸ„5‘‡„2ÃFÀ9˜BÞÀP#“‡ÙÇHTîX@� �Hy-Éä7xaÑ `ÙF˜HÚ‚ 8Tê‘FŽ©8&ԇܨ¦p´Y;b½s�žeÌsÒ'·¼€’?â0‰~êC'¢�À É�|,úg3hZFƒî¢gE‘Š褟ôòd†³‰2Š&óh?Dp€M,¬WN5ä T./ÜŠ Ì{“"àtæ ¹²à“®2ت‚ÔVëÿ 80Ó²Íðf”—î¹E·ä¾·À¸å*÷%Wë¦[íºû. NÄ[׆æ2ç%ïæ†Àáz;†¼ˇ/ÁŒ”�¤`U€ˆ àÂm_°À 8Ð�Æqg€V^õS8ÀgÌ6QjÑBÕgµ%uÛmÏ!5À_-‡ñ_¾m,VÛqÉ Êð®%W‹,ÎW‹a´¡È7_v@ryHR_Áuó[VG×ÀÔ—9Tš0@°hMJÕ_Â5±d\³€>/•ðÝxç­÷Þ|÷í÷߀÷íáà%pËãáˆ'®x)>‚‹G.ùä”ÛиŠ44 ô.¤•Zhå;êFÿ˜8r>y4Hípù‡7xJ†½èŠ’ ß zdŠˆê&Zžèg£ež�m§»œMƒç È¸%À{š1 iGð¥Höxô·Çôk|©=GÃ7�0¢QØÐ<"ãh = ¤•0 ÿ†òÖ¾d•5»Cr Küd_(.CÇX¾—‡ŽDJ ¹P‡=HC¥(OÛë@Á¢ÙÉHsÞ# ò—$î‘CTç 7ÕA@M­òÔ�ø1ÁHÌj}ÊóAš’ùñ)òƒmÄ©U¡ãN ¤¥vè†S ÊS)”.Ü— àY.†@°á0Â5UJ…™r…¦)øïu!Œ$ò¨ÿ*¶!>†0T¸Œ:±CÐÜæŠW) ŠeO;Ÿ*„ÔB~ÑaÔ_%ĘPJòXc’ÂBYnPÜô¨Ç*/'Š˜cŒdp�|gzßóF!QÈ<d øcH0u(2.KZžœŽHô8†VÍ€ž%0¬Ã]M,Bí†IÌbšEbÈtÁâ�¸f:ó™ÐŒ¦4§©7Û<ˆ*i¦Èâr0o±)7;»¦¼Â™°®°Àt»Mhò2•Ý,í;WÁ¥8ã©©‰“7\ Þl†–¼0Œš ;Ì,ö°ˆ€KûNUÐ�|')Q�4ˆ²�Œl �@F'nvt’ÿ"-FCJÛâ³MƒÐ@ŠG;a¶hM- ^qô Pñ6,7ÃÂL¨miô|šE£†²›UmmМÖ\Ú5Ñ|£¸<é#A’¦í6kCÙH!ö–4¦¨_ÚBˆsÏ¿-L8arÊšp‘Œœ4e;sëZ;‘1÷ø”d[*)TWR—¹e/GkBBã´ºtB©p™ŽX¨²€0$C©øZÓXx]Dg ]@X”ÖÐzÚL¨·ʨ¦Õ¼ ¥.õ«r¾†Œ¶Æ“l(5RÊŽ‚UËrÓ´Œ­˜V…2ÊfT³4¨p‡KÜâ÷¸ÈM®r—Ëܼ9î¹—h2IÝêZ·ÿÐE*¯ËÝî^wuŽžwÇKÞÉ·Cˆ`y×Ë^Ä×1Ä –¬=hÌò¾ø%é®Ë¥üúw–ê#ÑìAÄõw–ð[ßà ¥ÊZZDŠ æ0l� cÁŒŒ²0‰j„)õb½6ècHˆ#;kDrÂA,ŽÄK"MNñ…<Á‰[¸¿’TÐÄÝ¥0‹/|ÈY*%0¶ <ÜÊ€8�r†¢š�J{" ÎÜ’©A:ЀÂÑ¥óʇÍ1O{½“—§‡_ÍârÔ²>Ž\ ø†n =žg@K{P6Ø ¥ZbÐ`rO|u†Dï�ŽÀJû2ëvÀÄ:ÉÇt¶ÿäyœÓW8¦úQŸ¹3Áý:U ŠÔþ>Â*è5S1†ÀŽoIË®ÞØ 4Ðÿfv"æIŠ.Ä$ŸE• ×% æ2å!Óø?T.Št @§¬œãUgn#›³”™Œ_^÷ÑwHqófAÆ’˜0{IÔN]ÕÄ 7C'ÆAÔ,=Ž$ãÙÅ¡L-ŒH-2Iuäa W oç)ÒFé%w)ÞH#¤;ë®ÓZçÜçRD©qÞµ½…#[/¤ŒGT"=”«rkØF¸BÄánÿÁ!£ZDuŸ­¤cŠ Òâ$ ÔŠ‘øoR.Ñæ.8ª‰�ó<PÂ?ÖG»±s\ÃË‹Ú6°ÿÈo9Omtd%œ­b_ Øó º6†îðo‰–È©9\Žo†é[æ©è¸kÎ*\pý‡$‘å gÙÑäoç¡ ‡–Ÿ°"^%¥ñ°>aô»–l·âvqþñ!|Ú…³ˆ»®­Û"I§?Ðó,…ú¬,@"müôWå’ŽG)án³Tš€¦÷Èa— ¿oÆÉúÎãË ¥¤¼ÞÊXñ<^‰!$Ë“Åñò}SœS®À$ pŽô§?}9‹ZÔϾö¥¿ÄdSzùËo~Kýíg_å7¿ø ç¬i!_ýÚ~ le6ß�âþ€ Žó±u¼�Àß9¸ÐxTLÿH€V€˜L7° Ø€ ˜ˆ€5À€H€1PÉ4wÇ„ ¨Èd,ü#1H¨×^(˜‚æÕ\,Ø‚.ø‚0ƒ28ƒ4è-aÁ%CqXÁ¥7ñ42cZà@“.Bx7v"1[BÓ€.±1ÜDW|õ/86CøÒÓM \Êq…/h$íÔÂa1Ìñ/aÈ/!ñõ0W±1máç‚o(,³ú’XÊáÇð² 0v؇ @„ E-¨�…—å† ¢‡ŽZ ZÇÑ(Uphìâa¸Y!ó%@ ˜ˆ}H’˜&Ž”щ¢Á<h…‰Ñ´0ÿ MI¡1?³�´ð¯ñ5Á¢1S KUãI½XkîÑ2Ãá$·2G#1ÓP�@EZs1-à„Xc#ã#HaR<•4F\µ1žä5ÓZsS àfcaÀRâ¹wsSEóŽñeÓòHXúè;#‘^ UV~sV¸UPc£9 E lˆ2a‹±�)4\1Txe2–•2me9#þ3±å„1s3áq©Õ [;xŸR>ÈÐ2GÓSùNMƒ’Ç¡‘öZõ< µTqã5`ãZjk2W5Cl3r¤5CéÅøXÎtVžÿs1Ÿä–5Z¶A Å%8>ÅN!aQ� 2 y›‘Xþô%Q�—…5a°YßÁy^âZ:ˆ '¥ 4ù/HÃPœTŸ•‘#Ó“l£Rµ!”»åTE)6ê¤5t£”´Å”Z%2b9PQéŽa5b8j1ƒØOk!Qc‘õÄZÕÁ¹'ÐRn!‚±ÉW«1ia+ÉA�§™{ãƒIƒ5`s1(•,,ÙTÁ€Ç �ºI2 ‘’‘Qs›†%œ}u3¬)dQI!] ”›rÑR¶5Ř+½yšhÑ’aPa(u+É9†-ù51š/Yƒú¹ŸüÙŸþùŸ� : Z z j!��;���������������������������������������������������������������������������������������������������������������tkHTML-4ee7aaa953d6cb59/tests/page1/image4����������������������������������������������������������0000644�0000000�0000000�00000003704�11512242631�0017351�0����������������������������������������������������������������������������������������������������ustar�00nobody��������������������������nobody�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������GIF89a<�F�Æ��ª¨ÜUMy8JIi{{±ØØÙ»·Ïéé霜¡''&''MÈÈËUToiit:.<§§¨¹¸¸667^\u6( GD=ŒŒŽxxz”””„„†'µ¨’ yפĤ¼–°zÙ¸ñ¼èËèÄ®šh»ƒ 㪠çÍT\F ;;s…eÑ• Õœ sO …Y ºŽD•gwkn¦‹eûûùnYW¬—§Z=Æ‹ ¸•hJ0¡k€hLŽv„I9I������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������!þMade with GIMP�!ù �@�,����<�F�@þ€@‚ƒ„…†�†‘’“”‡‹ ‹‹› •¬•,-(#$$)$%$",›+¤ ©­Æƒ+ 5Í5ªÎÌÒš½ ¥ÄªÇ’¡ÌÑÎÍÒã㘘›+ÂÚ«Æ‹áõÏåâøÍüýŒÀ2$–êÝ #*,¡°!¯E ÆÙ«Ç C,16!bÆ… ¨2ˆ€Á<B„8‘#ÇEŒ.N„€±¡—Í^;d°tÂ…‹!Øpà`0 "pY°ÐHU¨ „ iªª©©Ä¤FÕ:ÕjÕ¬M r#Dàf¯„*u䨷þ@ ¸0ÀB6¨–€C/H³5…ÛJ tÊ aâ l¨Öàc„n r° ƒhäÌAÁ_(QÙܽ-*UhröD¿>}z‘€À·Qº«C†ò.” 'î5#P¨°Ùá Ú tÃCB† 7rlÁ!tì §7„°®}v† HÏ<Rª„dÈpAƒ`øÚ×p¡¿ÿÿõÙ—Ÿ}T Aaq³ÊS@,( I 2(–f‘$`Ö"™ °€H™Qx †èÀLéæ!%� à™H—ˆTô‚AR¦ b≅ȥ€! —‹o˜°W/@'Œâþ(ˆ�Àà.%€ÐA¸ƒuQ I3‚Äa’ ˆ5ð•HϤ‰e/+4 ‡J‚èÉVŽfÚtoв¥™&qÏ0Pši¢¬f%+„B ÓLdN4r]ò—¢ðø£Vl÷¼– 5TSÛ"X6L‡’€v,L@§wú *h "ˆ°\/T€QÕÈ'�<iTÞ8,B€ ‚*T àA‹KB4@G£jƒT×vÚE9ëžÊ. «Ý‚™è“°æ&硤â'”{ÝF.Ø@Qüa¡TDpÃð <È� 8¬@ÔÃ3Ìà�FþáÀ§Äà U1t ”ÛPIÅ€)ðÁ—€|óÍ·rʈyõžÊ+·üòUH.êÔ=ímÕcO´Ï9+IÈŠ\øƒF·"ç… 8ð€†9ëÜ4!Z* ‰E_]HŠZß4ê‚Ùè5!)*PJY‹X ]½˜ŠíÙ ZHdü à� �÷"€]ËgÓrQ€%•€ðÁšïýU*)%ž-H^'È‚K-´”`+›¥ ~cÓ¨`/-·ˆ�‚O/Ød-Hƒíp2„� ´ÐB Êg<^ŠÙ^s6ƒ™Ð@ƒ K¹Vž½Üæ¹Õo ‰Aš'“ìò79�ùÜZ8@DþøÄêÌ 7-à¯f$í¶ò@ŠÊTÔ˜U@ºÐW¢?ŸÉª4%!ã?‹ @Ù>g ˜Yáó”þTñ�L`T`ý a!M +\ÉNš˜çQÈ­u“ðÓ÷+ Öc£ZA¯FÖŠ `úР¬•&ÚØ)¬++6A€ $°SÞ™”4°4*Rá†{’°uZEœ&~Jˆ5`@cÔ»~ýN‡“ˆ½òä¯8?LÓªJp+~ ‹N6h€Ü ÓºW”HE¨FƒÖqApŠ È€<Ï9"Ÿt ‹aý§Q�•%Ä�&¶k½°3AÞè…ÜÈoîþµƒED ŒƒÒ�â¨É†Ð�%2È ¶˜óläû³d$3ÊLvK!€O[Þ¡EsqË]0pÀŸa& TcOJ‰ËXk€Ôa‰K$™í  0¨@Ö6±ƒZ6#-èAÔ&öÌË`k4p€ 2‚–È„ ƒÀ Ð� xâaD¡@�€°H32 €ÇÈÉÁ ¦d(K@ @à�?è˜ÄŠ‚Ÿûìg? }(D÷%±Š Dd»$DɨB3úè¢öqÙËR&°ÜÀ¤'-PRöT -h4&« RF ˜]+X© Káó•Ÿ9hOIÅûLT°Ôh%cêTŒJÀJ¼ChOÝÆQE*4¡5Hr`-D ��;������������������������������������������������������������tkHTML-4ee7aaa953d6cb59/tests/page1/image5����������������������������������������������������������0000644�0000000�0000000�00000001715�11512242631�0017352�0����������������������������������������������������������������������������������������������������ustar�00nobody��������������������������nobody�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������GIF89a"�,�¥��5  –ÑÐÎt`Vǵ®‰{ròîí¼™†êÒÈÓ¹°¥rŒhZZ@7àÛܯ¤Ÿ˜Š€À§œ’:M/)~nfdOFîÜÓŠR0R ÆÂ½rgÙ¹¥Š~úúü•v­–ŽßÎÃ������������������������������������������������������������������������������������������������!þMade with GIMP�!ù � �,����"�,�@þ@pH, •¢Ò¨ATžÐ#€BNëRH B€!4‰RB�#>VÄdèL2Rùhþ y`aOBH wm€bb‚‚P[  •fvT‘¤ŒKHqW GsVO•| MœZ¢zgp ƒˆ  œo´K]Ñ gN~ƒ � ¶IDG¨•‚›œü”@�sÕ{’0á‘aÃ256®ˆ€41b¦,*10l@ùÁÓ�T Щ“˜'"èà€&þH16$·OO4Øâ€ß8Î8gMN ª &AN &˜3Ó&Y4VY0À%Α¶JñÓÓ¤š³ @§ßgt Ä"À`B=f«|ÒÄÏ&(Jð‘9õàð4Nìúxpà@–„¾íÛ@�©‰ ލܰàÖ BA"èkìŽV> è�'¤CÜV¤ô†øµe‚+}0H‰È•+H{EtVʹ8 °y²IŽWóPðz… �$è)¨»o%(H€€¿ ù2€QPa¨M¨Ð–›œ!@D0 ÁÄñ•$jN'S€ Ú,pfNÌx©lðÀ� 0€P½±„$x|0•¾áGTæb5b|Š] à@V¡u× øq�.ÇUN0—fý“×çxøA�l½˜t<à�:—)ùÁ, À ðŒdtQ�%˜TãX'h|ôÁDoÑ‘$P KOücSဓÅR *€‡õt†5˜=Q@YÈqÏ(t@™4›„³Î< Ýgµ" ?À£$:©>@@,¤€Öª� ”™J�ðÓ™i§‘’m°%�;���������������������������������������������������tkHTML-4ee7aaa953d6cb59/tests/page1/image6����������������������������������������������������������0000644�0000000�0000000�00000004210�11512242631�0017344�0����������������������������������������������������������������������������������������������������ustar�00nobody��������������������������nobody�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������GIF89aP�=�¥��öê香¤””šÕÕÖÊ·¸:8YP:+Q~m„zx~‰‰ÌÇÉ_We@JEWhgnãäåîÙÙ(&L';ª©­¶¶¸R7HÚxxꙘð¸¸ñÉÇÉ™™, ÎÑ))Ñ88×XW?°ËØihȇ‡Ì©¨€:PÕHH³)(¹YXºgh¾zzí¨§ç‰ˆž¢''´IJþýû›¬£99d±‰a ¶:;–~|*)U$%Hÿÿÿ!þMade with GIMP�!ù �?�,����P�=�@þÀŸpH‚à·,:ŸÐ¨tJýE, äÁmH$\ƒ!;nLÀYNÇó…6„Å‚@' fuï¤0Ð]e[b]\4$Œ$!uqst''./! $#402++,-&˜8C/�� '%:5##!/.r'-+2 ¡Žl)-prÖ ./%)Ï¢51:,&&88 ²F/:ŽÂÕÉ-àò!«•t-!!) 1j³‚Z%9w´yûÔhD ¨Z<ÀÎ&¹((``áF`¢hÄXqÂZ¶ :C†A“"lJ.$ŒØ-¸Èó þ„<pУ£Hc°€£d€.RB•ƒƒÎžX³�T(Q£4ªP°@Ö"ÆüAD±L &@¡ž³x�@& "aÐ� SÀ€��NŸn*ñaÔQ5j€šü!E$ è‡)Ó�%¦(AoA…®CÝf™€Â`Ó°¢Q)_ÚD*Qâ �l`!Æ f:>Ô¨ê ÉV¨ŒCýªáò<ˆµ™áÁ1:òeB ûiµ‘‚UYð[¹†Ë˜oã‡Οp :´GŽÁ„àBˆA@€ 2À  ÂüFžS ¨ RÁŒv{·Dp‚ Ëþô W;yË$ÀÀ7ÜàÅü4‡22¨àÈ#nÔBà žÀÀ‡…xÖˆ%r”"H•€™r$À£Lö„Ë�w4Y„� „!†<À?™%å— €Æ‡x!!VvaÀe ‘ _òÁZ‡”ÑÖ!_”i� àôD©”¦„—LÚ“�¨Vg¨éW7¬ Išø8$C 09c0ælPÒ5ØJDL?U ÀPƒ¹uf tfo�1ÄDúÐͱ92Ä`ÛQDvS~C@%#¤¨ï9”‚ä@ì#lD2à-8nÖq*€òi#¤pÁ¨þ¤V€À±=jð¹)˜pÊ„P‚­ ºñ’IdÐ ¾¤È`Ž LqÛ+�˜ Ã°G1GÖVÜ¥ð[.s(ì H ›ªÐ©<£yÌý—\M3VF º(Y‘O-õË(Ôµp ÐÙ: 6,Ç-úBc¶µdNI¼úŠ’ÇH1‡,@šØÑ"ðê#½ö¼K®0µ su?%Ôê'#úÂÑrN †¸ŸWþu[e/D‹° %¨ÞQ5cBY:E‹ :¬Dœ[e´QG�’[@ӌٶ€ÃºcõHøk÷÷ßµ4^`KyÚÉàáXm^þãO=€¸§#À0úæ_5þ0„©xPØ$@Vé±`b¼úVaøNÁ]ÁÿXe2Š&šx®é€–7?ź…�FÆ÷ß«VÀLŠä×à{œRFô]€Å!�"‘€PB®q|Æs•È„ê 0€'¾ŽÖmÊ©¸Ðˆa  AIXŸ`1ØI5H�üp�f�–Š Â^°LˆskÃ4¬C/]A)JTx^_U'A,J‹Æ?J™T,&`Á ÀQ™>ÍHÇáBbrŒ<è'0Þ!°T¦-pÁÍÇØÊe3RqéAA{A ¼ƒ_ä&=¸ þèf5Ó¤Ž (Œ£¬ä� h2‰ŠJhS¬`yË6 ¡$ð�»låøRKªq‡y¥ @„AK&•´Kµ Xò¶@ÏÕá­¨Ãp|@É êRŒñÎÊÅ¢hÍ`«r¡Š¢Ñžßxd Û'Pƈü…Ê:Ö€ji�„€A%¸™5”±­‘K/U.A¯YáëVÕév€¦ `à^w¥ TÀƒ3TÒK�ÀÀТ±Aµó:OA Ù”[6¶Œ ,ä ¾ ` "ÅQ:0ÉJ‰›°”†àI,ðd“WOiä#‰% % ,Ž‚Tþ)šI]­3ÊÓ=‹à®`dsÃÑŸôW ¯m†8ÌdP. ÎW¶–÷Û#Ò¹�iRó ØGM–†�úôæ#‡.9lc;Z}ˆÀ¬–‡Ä(ÄÝA x@K‹BüùŠzògRvš *– –¢1f@a Ë[>Šò 씜¢èÜ 5T � p�Іɠój&X§<õl‹+ºHb/T)®rÕâj€Lmé$à ‰ª(Ç*P»Æ@Gë½6pO@N“,`(I V!s(ʰJ!¯”‡û ÉQ”R ¨Pï|×D9PË‹2)sDùnhš7à ³#]O+‹Ñ·„É€"X¬%e—© )ù ÇfÌ9FsC¨ßLµ÷¤ÔM $މ¼¦¨¬ÎÈ!<èq½«½­ &¼n;г6 7…€£Š}Àò*Œ¹úžè¾ß|Á@‹11€µ$þŒ‰ XÓdÀˆcŒ•T­J®ŒAˆwÌãuÅD=ðKä"«Íp�O‚��;����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������tkHTML-4ee7aaa953d6cb59/tests/page1/image7����������������������������������������������������������0000644�0000000�0000000�00000003746�11512242631�0017362�0����������������������������������������������������������������������������������������������������ustar�00nobody��������������������������nobody�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������GIF89aW�@�¥��"."+<*???4J2>X;KKJRUQ__^LkHYwUfkapxnj„h|“zƒzjÿ�ÿ™€Vk„„‚Ž‘˜—’¢Ž¤¨£©±ª®¼­¹¸´ÂžËÏÊÚÝÛêìëúúûÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ!ù���,����W�@��þÀpH,Ȥr¹„8ŸP!G"‰X­ìãÊíz¿Zíw<G¨íTÉ𸼜w%^ÏvÛÿ€ry|O^ ‘’“”–Ž–‘˜›žŸ‘ ]†‡NoW�ޱ –³•’”¹œ›±š\§{«­• ÎνÑÒŽÏÐ ÏÓÚÍÕÝš W…z\ÔÝÐÓ ÑðõÛ±õ úÕ •[W&PfÌ—`åËFÏÚÂ} çq{q_ƒ‹üžAueÁƒÅòpA `bÄX2D¬†qe·‹Yö+î Ñq `À¤þÅz NuÀà’ėúZ.|”€‹›*„ÜY€¢Å£Ð6pp€hQØàae«=XNx¬€¡—’õÌ*pp1ƒ±ðpÈ`Ñ‚t5¸àL¹Þqð”AÎoM†Õì`,4°€ªÃ†2x°«T&VÅWC5ù Ü¢‚·mЖ†Í2XÀÐáB†ÜtK †é­Àbj£»ò`@UØ |Ãæš³ÎK•ú,¼l÷GÇ x •óWó½kàá.<És»nØpݳV‚šÅFÜ45òñl™wEBï¬Tˆ\:³[m¦GoÕ¹gqg-6€xä•bE�þ¸“`=èaŠÔ|èÌ|Zqpa˜åVJ~1]•Ñ{Æ¥¦Z†žÑ¡‰bað] Uã@˜‚ÁøÜ|Áíç]…6bàN—F½Ôcän{!iÁošYpÊH¸‚5Z1ÀSX¥Lb]0"ÎxF—ó!y _úXPˆ!î™Oš¬ùŽbàáJÍðöe&RCš>]…èÁmûV‘“êY(¥†X¼BgzÑí“|øäÓY‚Å%h§þ:%@¢FXz lÀjb°Å´§ j(€ ZAàCL>£"t.l¤Â^HlŽ×o²ÍeØ<Ü…ê¯ÝuÛÊZlþ¢rƒÑº>>“$CÞ&˜åpÐùãé´TM$hLHÞ5ï{%Yâ¿ÌB­¹Ôî8ÜaÝ0 GeZY§{ìA, ] aÁšD�а8æk…Ï ¹Áù©7Ô`Dþ敟ytP0CãëšBÞUÚ¨ Œš]~Z Àv´‡ÔI€ð[8—õ’¯C3Úa¾í³"o*=„˜D5‡|³O%ûÕàŠh ØÙe³²3¡]0ËMœ' pÜÒ®-Úh{¨Ñ÷! bÍÔ”Ò׌^nL÷RäÚˆ·”ôa)¦T^9*•ÏgMnûøé6ÛóöÁÌÙ4®¦Ò6Cž®~01Ѐë¯{–þ3p—ÁgF!N:4v{Ü›ç°úÈ-5Cò{ Y¶mf™¼õJ“Üz;&Hr3˜%‹|ò™¥±ÄfV·»3Ñ;>}õ³'ÅPüµIY’‰¤zd†ruB?Qù§?Ný›VY$Ò l4Äx~9hNѾãÕ‹…^Âô6·~8Œ4ÛXŠ#63¾l@1þ«^ÔbQC4@KU fºâC̈À¾ ` qV5Ñ»þM¯°H@úâ! |FÙ¸¡=HçJ”ë‡éº‡ñ)iôC‰�“Œ YØBNo1”"gnwD+ñŒ9ÌiD€ÜËkT`À+þ‚È m„(Ðo(E$ÚÃ�F¬¦õ L rèã;Ù )ÂBkŒÇ%j"C}j g8ƒ„w‹O0r¶ÈÁzA� à °äZŠ¡§/rŠÊE)#'ËY–ą-o)€�¼’–”ˆ¥.gyÊ+P@•0Ç)’ —¿„¥/#çKá��×€6£9ËiN“𨬦8Ç)Î^Ї 8À°Ìb|À uæIÏzÚ“ º§>÷‰Otž!T˜ÀšT㘠âµ»À*â)ßu ‚s º¡ ,` ÈYK):€ÐÀm ¡ é0Pƈ‡í<ý<þƒ L`8€Ò PÒšÚÔP7Í©NwªÓ™ŠG£èX)4p <�¦1•éL—ÊÔ¦:õ©P*TðÓ(3*Q)00` «XÇJÖ²šõ¬h5+#P c<¡†*9¸šØõ®¸+òª×¾úõ¯€ l`³ rœ#Nèh\5p¤ T€¬d'KÙÊZö²˜­¬c¯¬FáAD*1º"Œ®öj+*íi”ÚÖºöµ°­0fkZbl _àâj9ÍǿՊo‡›½á÷¸È=n‘L ÜæV· íŒt§KÝêZ÷ºØ•î1Øð\èöí»à ¯xÇK Þò†÷Ü…@��;��������������������������tkHTML-4ee7aaa953d6cb59/tests/page1/image8����������������������������������������������������������0000644�0000000�0000000�00000002242�11512242631�0017351�0����������������������������������������������������������������������������������������������������ustar�00nobody��������������������������nobody�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������GIF89aI�;�Äÿ���óÕ¦¡žœid`g:ÎÌË0 ‰['Ú·}¤z@õΉèçæùäÃÀ›_853ì¸UÞŸ1ÀÀÀõíß ������������������������������!ù���,����I�;�@ÿ`$Ždi.E±˜lë¾p\ô:¢Â@„3üƒÄc¨0ŽÅI…˜4¨Z«Å�b‹H$x`L Ëx@Y%¤ñD§’«UÁßÒ»=be…†�IKLha;‘a-G X} _`a‡¢£�44)6739‘‚P" šI tN”¤½‡¦ª"˜š4,¦b¦&3:¡¾Ðc>v-8@¦wS0(¬4צ§vÂÚäå%*³9»<;ëÔæðxµW~^”>a‚ššJp™IÚ0ú‚®\=Vð¹…‹;B½ l”€Ï¢\ÊÆµ@²‡aC/_vñŠvè@ƒ-!ÃÿDò(u< AkžGO Hú–ÜŒT4Shéô¢ÎQ> ŽÀTDï‚­ÖÌÁQ2¦)ÇõE”OPu+ãÇ;kíT:h÷¤@ž…þæ$ˆJV›„»w­Å`KÑFúÅm’`€ÆxL÷lbèpd™ºÔjóÉD:PÇ@رÈÇ”F @)­Eoäf—³-.(] =j"“4ÚxJPF&ŒÄl`+Ì𶝠k°¸Iˆ¸‚€i¼a®¢W ©}®Ûæ^Ò¬¾CÌ&—딌g/5s ŽV@¬ •P\é׋’ÙsÊŒ�®´'B áY êé‡Mÿ Ä4Å3ð €ð Ÿ(ˆab�C—{3Xu!VZiFÓ(ÖA ­DBJV>`ÓŸŠ4¢˜"8Æ @ Ýåè# À$ì„5ãðüdC3ëˆää6hE H–`MThÁ]s „LÔab]Üh”eX4t ‡—_‚éÄGª(¥¸ Žì…_’1eÑr^ÈG#pX„‹=F©ñ¦U Q™&”1ALJæÌ£õ¤ô‹$Ð@ d—C‚šsk†ªé(<™_L¬9„C²”cé·Ü2”C`@Ó€ì�6Ø/É4¦ ¨ÚÂG'¥—àcË¡±K£zAHÿ­1ܺØyÄåDRE˹Á©In86†„,hëÑp Ð\~GUÐ@@K,Ê7œÆ¡ë2 vÙQ aÞY 3ì�†¾$pTÝnŸìòÌ…PÐ!w×4Þ.ØF@]ª8Í6""× ‚7Þè R§Z=Ö!:ñˆØÜHUÊ+Mƒ¢ÃŒçìÈc<HÊ&OÈ3JJüìQI™$+ªÐ×Ô¡î"¸ôQ Z™W 4�@©(Ôb~M†Î$Ü5Ù2&p8ÍB1¦ËÕLg½Ô<@5N§ôôß¡½š- kçÄTqVCêfCBø998Õã ¹àŽkxsßǺ€ƒˆf¾U•Aµ¨Óä5“.‹ðåœs|vŒ®º{ܤ`»í6Ï>B�;��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������tkHTML-4ee7aaa953d6cb59/tests/page1/image9����������������������������������������������������������0000644�0000000�0000000�00000000213�11512242631�0017346�0����������������������������������������������������������������������������������������������������ustar�00nobody��������������������������nobody�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������GIF89a ��ã��FRTªª¼z†„2fdþþüÎÎÌŠ¦¤Zroÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ!þMade with GIMP�!ù ��,���� � �@&È)‹9`”Á»çÓñ¤GIl%'¶àY¼ERÚ7Àœ 0�;�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������tkHTML-4ee7aaa953d6cb59/tests/page1/index.html������������������������������������������������������0000644�0000000�0000000�00000102706�11512242631�0020257�0����������������������������������������������������������������������������������������������������ustar�00nobody��������������������������nobody�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<HTML><HEAD><TITLE>Slashdot:News for Nerds. Stuff that Matters.
    Click Here to enter the Sweepstakes

    Welcome to Slashdot Linux News United States Education Space
     faq
     code
     awards
     privacy
     slashNET
     older stuff
     rob's page
     preferences
     andover.net
     submit story
     advertising
     supporters
     past polls
     topics
     about
     jobs
     hof

    Sections
    1/23
    apache
    1/29 (3)
    askslashdot
    1/27
    awards
    1/29 (2)
    books
    1/27
    bsd
    1/28 (2)
    features
    1/28 (2)
    interviews
    1/19
    radio
    1/27 (2)
    science
    1/28 (3)
    yro
    Andover.Net
    AndoverNews
    Ask Reggie
    DaveCentral
    FreeCode
    MediaBuilder

    Who Bought Linux.Net?
    Linux Posted by CmdrTaco on Saturday January 29, @10:52AM
    from the this-game-again dept.
    So Fred VanKampen (who has to hold the record for most money made by reselling two domain names) e-mailed us to say that the Domain Name for 'Linux.Net' has been sold. He won't say to whom, but it supposedly will be announced at LinuxWorld next week. Of course we have no idea what he got for the entry, but the rumors were that he made several million when he sold Linux.com to VA Linux. Hopefully he'll take me for a ride in his yacht. ;)

    ( Read More... | 58 of 62 comments )

    Book Reviews: E-Mails from (Over?) The Edge
    News Posted by Hemos on Saturday January 29, @10:43AM
    from the touching-story dept.
    I'd like to thank the author of this book for sending it to me. Nick's written a book that's touching and endearing, and one that's well worth reading for everyone who's ever had social struggles to deal with. As well, his involvement with the fine folks of TheVenue. I'll warn you - it's not a tech text. But it's still worth reading. Click below to read more.

    ( Read More... | 6197 bytes in body | 6 of 22 comments )

    Linux Kernel 2.3.41
    Linux Posted by CmdrTaco on Saturday January 29, @10:21AM
    from the download-compile-reboot-repeat dept.
    sdriver writes "For those of us who enjoy *panic*, *oops*, and suddenly seeing their video BIOS... the newest version is out! Be the first on your block to submit a new patch! ;) " If you don't know where to get it, you probably should stick to your warm and cuddly 2.2.x kernel *grin*. Now outta my way, I wanna crash my laptop!

    ( Read More... | 52 of 57 comments )

    Congress Still Figuring Out E-Mail
    United States Posted by Roblimo on Saturday January 29, @07:28AM
    from the voice-of-the-people-can-get-awfully-loud dept.
    Jett writes " Vote.com has an interesting article in their Webmag Fifth Estate about how congressmen have responded to the popularity of e-mail in their daily operations. Quote: 'Of the 440 voting and non-voting House of Representatives members, 22 have no e-mail at all. Even House Speaker Dennis Hastert is wired only halfway -- his office receives e-mail, but does not respond to it. And while all U.S. senators have e-mail, they, like their House counterparts, routinely shun non-constituent mail -- even though they chair committees whose decisions affect the entire country.'"

    ( Read More... | 66 of 66 comments )

    Ask Slashdot: Sci Fi Literature 101?
    Education Posted by Cliff on Saturday January 29, @06:56AM
    from the recommendations-wanted dept.
    ohlaadee asks: "My niece (she's 13) wants to start reading science fiction. I do too. I gave us both Asimov's _The Foundation_  for Christmas. We'll read it together. I suppose we could spend the rest of our lives just reading Asimov, but I'm wondering what books and movies you folks would come up with? What does the /. recommended Science Fiction 101 list include?"

    ( Read More... | 345 of 345 comments )

    Could Distributed.Net Help the Mars Polar Lander?
    Space Posted by Roblimo on Saturday January 29, @03:35AM
    from the food-for-thought dept.
    Anonymous Coward writes "This official JPL press release describes the current attempt to listen for faint signals from the Mars Lander. They get three windows a day, and it takes 18 hours to process data because the signal is so weak (if it's really there). Too bad they don't have a deal with distributed.net." Interesting thought. Is anyone at distributed.net or JPL interested in pursuing it?

    ( Read More... | 99 of 102 comments )

    iCrave TV Loses Battle against U.S. Broadcasters
    Television Posted by Roblimo on Saturday January 29, @12:21AM
    from the shut-down-just-before-the-super-bowl dept.
    Doran writes "C|Net has this story about how the Canadian company iCraveTV.com has lost its latest battle in U.S. courts over whether it can rebroadcast TV signals over the Web. The broadcasters say it's theft, while iCraveTV sez it's just doing what's legal for other cable TV companies in Canada (ie. rebroadcasting TV). Of course, by framing the streaming video iCraveTV is doing more than just rebroadcasting, they're also adding more commercial content, which the broadcasters feel dilutes their TV commercials. "

    ( Read More... | 152 of 170 comments )

    Win2k Security holes found
    Microsoft Posted by HeUnique on Friday January 28, @04:58PM
    from the and-it's-not-even-out-yet dept.
    According to a story posted by ZDNN, two security holes have been found on Windows 2000, and that's even before the official release of Windows 2000! Administrators who rush to incorporate the patch from MS beware - according to one of the talkback posts on ZDNN, the patch creates a new problem with Windows 2000 news server service.

    ( Read More... | 510 of 534 comments )

    Encryption Debate at Mitnick Trial
    Encryption Posted by Hemos on Friday January 28, @03:33PM
    from the gimmie-the-data dept.
    A number of people have written about the latest twist in the Mitnick case. Kevin wants to get his data back, but the government is refusing to do so until he gives them the key. Apparently, the government is unable to crack the encryption that he's got on it - you'd think after having the data for five years, they'd be able to brute-force the darn thing. It's a NYT article - free login required.

    ( Read More... | 504 of 521 comments )

    Forum: Future Ports of Games to Linux
    Games Posted by CmdrTaco on Friday January 28, @02:26PM
    from the it's-been-awhile dept.
    It's been a long time since I posted an open forum like this, but I'm curious what people think on this one. What games do you most want to see ported to Linux in the next few months? Of course, for me personally it's StarCraft and Diablo 2, but I'm curious what games have come out or are due soon that people would most like to see a port of (and note that WINE doesn't count. ;)

    ( Read More... | 648 of 652 comments )

    Features
    Voting has begun for the $100k Slashdot Beanie Awards. Talk amongst yourselves and choose who deserves the cash.

    The latest installment of Geeks in Space is up at The Sync. Listen to CmdrTaco, Hemos, and Nate talk about the latest events to happen - or not happen in the computer world.

    Perhaps you are seeking Jon Katz's series of articles related to recent events in Colorado. These articles include Voices from the Hellmouth, More Stories from the Hellmouth or The Price of Being Different,

    For something different, try reading a little essay Thoughts from the Furnace about the internet, and flame.

    And for a bit of an amusing take on the Open Source world, check out Open Source as an Ant Farm

    Update: 01/03 03:10 by CowboyNeal:

    Past Features

    Ask Slashdot
  • Sci Fi Literature 101?
  • Linux and Satellite Internet Services
  • Open Defensive Patents?
  • Technologies That Shaped the Last Century?
  • Disk Repair Tools for Linux?
  • Why Can't the Command-Line be More Standardized?
  • Packet Radio Networking with PalmOS?
  • Cheap Rackmount Enclosures/Systems?
  • Open Source Software and Tax Breaks?
  • Building an Upgradable Dual Processor System

    if you have a question for Ask Slashdot, send it to askslashdot@slashdot.org

  • Slashdot Login
    Nickname:

    Password:

    Don't have an account yet? Go Create One. A user account will allow you to customize all these nutty little boxes, tailor the stories you see, as well as remember your comment viewing preferences.

    Slashdot Poll
    The Tech Advance I Most Want Is:
    Nanotechnology
    Cold Fusion
    Powerful Fuel Cells
    Hard Wiring my Body
    Universal Strong Crypto
    Interstellar Travel
    Cybernetic Body Armor
    ColecoVision
    [ Results | Polls ]
    Comments:656 | Votes:29121

    Older Stuff

    Friday January 28

  • Abstract Programming and GPL Enforcement (235)
  • Interview: FreeDOS Leader Jim Hall Answers (86)
  • Open Source's Achilles Heel (466)
  • The Virtue of Communal Instincts (237)
  • Gartner Group Debunking Open Source Myths (165)
  • DoubleClick Taken to Court (310)
  • Updated Slash & Server 51 (81)
  • XMMS 1.0.0 Released (128)
  • Linux and Satellite Internet Services (138)
  • UN Wants to Combat Online Racism (531)

    Thursday January 27

  • Crackdowns, Fools and the MPAA (351)
  • Heroes of Might and Magic III Demo Released (157)
  • Sandia Labs Venture Into Nanotechnology (117)
  • CA Announces Program Ports to Linux (195)
  • Interview: Larry Augustin Finally Answers (210)
  • Final Call for Voting in Slashdot's Beanie Awards (178)
  • Transmeta Code Morphing != Just In Time (449)
  • Intrusion Detection (65)
  • Using Enzymes to Help Fight CO2 Build-Up (165)
  • Jon Johansen on ABC World News Tonight (415)


    Older Articles
    Yesterday's Edition

  • Book Reviews

    Jon Katz, Resident Gasbag, has a new, very appropriate book coming out soon, Geeks. Preorder now and receive the book early.

    For probably the best fiction read around, check out Neal Stephenson's Cryptonomicon, an engaging read about WWII, cryptography and buried treasure. And data vaults.

    If you've been doing a lot of work in Perl, you've probably figured out you really need Perl in a Nutshell or The Perl Cookbook. If you're still learning, grab Programming Perl.

    And if you want to learn more about how to become a better coder, grab The Unified Software Development Process or The Practice of Programming Additionally, check out Refactoring: Improving the Design of Existing Code .

    Developing a large application? Grab Eric Greenberg's excellent Network Application Frameworks.

    Visit Our Book Reviews Section for more.
    Update: 11/12 05:19 by H:

    Quick Links
    Cool Sites:
  • Linux.com (What is Linux?)
  • Everything (Blow your Mind)
  • After Y2k (This is Post-Apocalyptic?)
  • User Friendly (Laugh)
  • Themes.org (Make X Perty)

    Support Slashdot:

  • ThinkGeek (Clothe Yourself in Slashdot)
  • CDnow (Support Rob's Who Habit)
  • Slashdot Advertiser Index
  • Freshmeat

    January

  • We should get this out of the door now
  • Is Linux for Crazies?
  • SQN Linux 1.6
  • Limo 0.3.2
  • Fusion GS 1.3
  • MMR 1.5.4
  • KUPS 0.3.4
  • 3DSE patch for XMMS 4
  • Linux 2.3.41
  • Free Code for Linux S/390
    Search Freshmeat:

    More Meat...

  •   Wasn't there something about a PASCAL programmer knowing the value of everything and the Wirth of nothing?  
    All trademarks and copyrights on this page are owned by their respective owners. Comments are owned by the Poster. The Rest © 1997-2000 Andover.Net.

    [ home | awards | supporters | rob's homepage | contribute story | older articles | Andover.Net | advertising | past polls | about | faq ]
    tkHTML-4ee7aaa953d6cb59/tests/page2000075500000000000000000000000001151224263100161765ustar00nobodynobodytkHTML-4ee7aaa953d6cb59/tests/page2/image1000064400000000000000000000036561151224263100173550ustar00nobodynobodyGIF87ayOö9!!!))))9µ11119µ1Bµ1ZÆ1cÆ9999Bµ9B½9cÆBBBBB½BJ½JJJJJ½JR½RRRRR½RZÆZZZZZÆZcÆcccccÆckÆckÎcŒçkkkkkÎksÎsssssÎs{Î{sÎ{{{{{Î{„Ö„{Ö„„„„„Ö„ŒÖŒ„ÖŒŒŒŒŒÖŒ”Ö”ŒÖ”””””œ””Ö”œÞœ”ÞœœœœœÞœ¥Þ¥œÞ¥¥¥¥¥Þ­¥Þ­­­­­ç­µµ­µçµ­çµµµµµçµ½ç½µç½½½½½Æ½½ç½ÆïÆÆÆÆÆÎÆÆïÆÎïÎÆïÎÎÎÎÎïÎÖïÖÎïÖÖÖÖÖÞÖÖïÞÞÞÞÞçÞÞ÷Þç÷çççççïçç÷ïç÷ïïïïï÷÷÷ÿÿÿÿ,yOþ€e‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿À¡]P@7'Ê&2;GY¯d´TD.#*.20.*'&&#7L\ÁœGç&7;?94*.ÐLP¬@¡ÂäÈXPÞ%*,Ѐ% |8ò®&'pèè0Ò*²Œ¡RìÃ$#¹áàGIHBŒà2Š60Áô„Í›Œ¸8˜pC ”#70L¦É•QÔXý8°A†#@H80ñÁ‚‡;ÜY"ÔÐÇþ2¸P€ÁE7<8 ÁÁ‚(Kä‹$m19ˆCm–¥#žÑøà@&2(ž0ÁEº8##qÑ QPÁ„7& ô…ŠŠ,lØ;FGEe e‡¢ &4Cá¡‚ムNà71 ÝÈÊìEL,8ºok&cqéA‹ „1ô¥‰ÕÄ?À4³CìR ~%` îPq?ؘ·zY0ÁƒW‰•ÁÅ ¬´ &˜ì ÛP™àœ;¨ÐÏ EX¥MF?¨Ñ_*`0‹© ÞsW©Xˆ UdD<÷T"&þçã!`xâ%Yl`ÂGü€±$“œ`%3e0‚== ôt® 'Ê ˜ð¤#YÌ ›k4¸ðA XÐã–Š¼Ð iqñÅCŽA(ĸЙYä|°gÁç#GÈÐ```AHá`„€¾9é#\P!Ä &ÆæÀ«œ‘ªÂBPÁÝ©¸æªë®¼ê2…0€™@&- / ÁSˆ€—8!ì—À±©¨ÉH²)RB È. ‰:lAˆ%`« ¨ K8Ïh ¸û‹ÐÂ"Z!B”`¯ AÄpE1<+H >þ rE ;Qƒ 1È:[B A¢D â…Á§`!S´ -xQJÂÆˆЂAt€ ‚àœ‚à.è[FÈAFHË­B pA:—l „€- 4]Q@ F”€¥h!@°€]ˆ`ó -<\Lë …Óe€ÀÞ>L«|o;¿~ "t¸‚L/áeøwP^¹§¬ãƒ @ň®!†;íÃÜ‘—¡EøÍ¯¿eL>¼ŒÚ®è í´ P€"€ƒNˆáˆ €!¼›{;!B,¿Šðë{+%Ì]q þÆ#¯,ë¸@†àl÷ôƒè^†D H³ñ§°D+ÐAÉŸàæZÞá‘8ùB}×ëõ@¹ Äo5à¿<—Š8+s €ø”÷¸òÐpÐ@É §Àö1PZæ!ºRÈ‹)èìL‡ºC$|®›[!´@ì}’;¡ 6BFî £pú Qÿ•ÁmÔ*ÄÂnXˆÖP  W' e¹â瘶B¿áîÏE² (ˆü‘i¾sBPGEš¯"°Þë4¸;-‚B+À•€Ð uJð#)DW€üq«> ÝŠ˜?^σ™{ èHþg±€!À€_»›$™†:-ð® ÀöJ1„0±ƒDâ–(»D`a…°|!!®°·%…Œ½êDÈhLN ³˜ž¨‘iL“™ÐŒ¦4§¹«XóšØÌ¦6·ÉÍnzó›à §8ÇiM,Àœè<'Ö @àð|§;ç)ÏxÆsçÌg:÷©Ï~òóŸîl§= Oz®Ÿÿô§>C P„ªsžm'D#ÊΊ&ô¢ Í(:*ÑŽZT Õ'Fÿ‚‘îó õçFQ:RºÔ¤ê|(K7*Ò—*”¡0uèIczÑ–úÔ¦:ý©NºP¡Õ¨H=ªR“ÊÏ’.õ©L…ªT£jÎXõªXͪV·ÊÕ®zõ«` «XÇ€@;tkHTML-4ee7aaa953d6cb59/tests/page2/image10000064400000000000000000000003771151224263100174320ustar00nobodynobodyGIF87a$ôaŒçM{ÒJwÒDnÅ0_À/^½+V­'Ož&QŸ"EŠ=z:v7o2f-[+W&L"E 5>,$@„ %Ž$YœÆ‘(Ì1È,4Ó<@ì<½ØŽoH,îJÈ‘áÀ!…áò&$®X1Éí’–MÈ  Ýqñ\•ÖAÝúÝ”ïø»wÏï{§8cd€ dn?Te=5av T’fo8—†›SqEŸm<¥¥Žy«¬¬¯°±±!;tkHTML-4ee7aaa953d6cb59/tests/page2/image11000064400000000000000000000011161151224263100174230ustar00nobodynobodyGIF87aX$ôÿÿÿöøüíñùåê÷ÜäôÓÝñËÖïÂÏìºÉê±Â稻䠵◮ߎ§Ü†¡Ú}š×u”ÕlÒg‡ÍaŒç`~¿[€ÍTq«RyÊM{ÒIrÇDnÅ9jÎ0_À>,X$@þ 'Ždižhª®¬ŠMp,Ïtmßx®ÓeqÀ „`™œ€Á NAÀH 8`HBIu,ÖpÌÁEœ àÀ(d€‚ƒ„…†‡ˆ‰Š‹ŒŠ-‘’“-Ž–—˜‡CAŸKnfMUiª Q ©CYW`Gt £Q h™ÑÒ—”ÕÖרÙÚÛ$ÓÞ߆C㥇äGæàë«@tTOM€u@âDZãíï–4A£Æ›¡3ŽŠ¨cG±¢Å‹3jܨ‘›Ç CŠI²¤É“+Ô&rܸAƒÊ•0ƒÌ5ê¥ šjb^Ú$“U  Í ‡>¨ÑÀÀ¡ 2Õ™*¤>U‰À † IáE¸²@+!ž„92M.žfYàÞ3^É›F <€S¨P‚ˆ'kå%ÖoÈ2 @äp@Ÿ£gÒT€Ë.î(Ó v@Ñpú8\@1ºÄyö¬j˜—°?LÁ4|M ŽâûÃqy@ü«³¹óçУKŸN½ºóسkßν»÷ïàË;tkHTML-4ee7aaa953d6cb59/tests/page2/image12000064400000000000000000000003761151224263100174330ustar00nobodynobodyGIF87a$ôaŒçTq«JwÒF_‘DnÅ9jÎ5Iw0_À,X±+V­'Ož"EŠ=z:v7o2g-]+W#B&L< 5>,$@ƒà%Ž$ FDEÃ,J‚ Gm7ÔANÓØ·¤å¥äX8àtÄŸñÉêI€v«ìzIµ‚€€“èxE&} B­Gj4.œïøãwÏï c fUib kpj9;@r‘n,ˆ•lto˜5“Nu”5 §¨yª«¬®¯°°!;tkHTML-4ee7aaa953d6cb59/tests/page2/image13000064400000000000000000000007551151224263100174350ustar00nobodynobodyGIF87a9$ôÿÿÿõöùëîóâæíØÝçÏÕáÆÍܼÅÖ³½Ñ©´Ë ¬Å—¤Àœºƒ“´z‹®qƒ©h{£aŒç^sTj—Kb’BZŒ8Q†0_À/^½/J,X±?€:v 5>,9$@þà'ŽdižhªŠæ¾p,Ïtmk\Î5À¤s Àa(p&À#“db"Gæ‚ÀYX ‚ÌoL.›Ïè4çÂn»ßð¸|Ng¯îøüIÍïûÍ ‚DF YHN9B ^A]”“d¡¢£¤¥¦§¨©¡z¬­®¯°)³´i ˆµºjA>:PW=<‹¹HU DJ@‚[9·»ØÙÚÛcuÞßàáâãâ±æçèéêëìí#Üð:ñôd bõµ cÈ·o  PàPa Á%@4 ÑÀƒ†N(`V¦×Y8,ª€$@‚Žsœ|öìÀ£hJ¨ùëâà̳):”åXd!Px’O"‡2å òŒÚJh ÔÇA>ª †*@À!+C‹:¤ŠÑA r4L˯­ÛlâÊK·®Ý»xóÆ%Ç·¯ß¿€ö@¸°áÈ+^̘p;tkHTML-4ee7aaa953d6cb59/tests/page2/image14000064400000000000000000000003031151224263100174230ustar00nobodynobodyGIF87a$ôaŒç0_À/^½,X±&K™%I•!C‰?€:v4j"C?<6 > ,$H`$Ždižhª¦Â@ Œ#"‡A !, $œ©Ëí£œ´Ú‹³ÞøâH–扦j)´î[;tkHTML-4ee7aaa953d6cb59/tests/page2/image16000064400000000000000000000002351151224263100174310ustar00nobodynobodyGIF87a$óÿÿÿáááÂÎ筽ߣ££”¨Ì|‘³yyyaŒçLLL8880_À""">,$RP¥cÊèí:ST±q]ÉÁ”¬£¤d[«\¾šÍ¹î¥¾/Øy ÂÑqX&–Š%cI­Z¯Ø¬v˵!¾àpxA.›Ïè´zÍn»Ñ¸|>;tkHTML-4ee7aaa953d6cb59/tests/page2/image17000064400000000000000000000001211151224263100174240ustar00nobodynobodyGIF87axñ$D™!8–/{&d,x*œ©Ëí£œ¢Ú‹³Þ¼û†b@–扦êʶî ÇÀL×öçúÎ÷þ,;tkHTML-4ee7aaa953d6cb59/tests/page2/image18000064400000000000000000000010411151224263100174270ustar00nobodynobodyGIF87ax õÿÿÿõöúíð÷êíõæêóâæñÞãðÛàîÚßî×ÝìÐ×éÏÖéÌÔçÅÍä¾Çá¹Äß¶Áݳ¾Û¯»Ú«·Ø¨µ×§´Ö¡®Ó«Ñ•¥ÎŽžÊ‡˜Ç‚•Å’Ã|Âu‰¿q†½l‚»j¹f|¸e|·^v´Wo±Tm¯Lf«Gb©D_¨A]§=Y¥9V£6S¡.Mž'G›,x @þÀ—p8$e4$¢rÉl:ŸÐ¨tJ% Xˆë`+ÂÆø”†j˜¼.€Ô«üÁT"ä…Ū¨€‚B} -l/l/bdfB X$/- [‹|ƒ§¨O. B#[‹°¶.¶¹&/F-/&À'B¹¤©ÏÐB' IÓ{ %,B&ß W(/ /v Š| ÝÑøùúûüÐv^~õHЦŒ9 AÀoò4p”&Šaq!€(0£vE€ 2\IÕ  Î¨ æ‹³2g^L aG€B¿6`<’–õq¶²Ÿ‹ $VØÁ°¢ÍÑŽÆ —“–x1ž@¡( À%r6xâ‘°æê…;tkHTML-4ee7aaa953d6cb59/tests/page2/image19000064400000000000000000000000651151224263100174350ustar00nobodynobodyGIF87axð$D™,x„©Ëí£œ´Ú‹³Þ¼û†âT;tkHTML-4ee7aaa953d6cb59/tests/page2/image2000064400000000000000000000000611151224263100173410ustar00nobodynobodyGIF89a ðÿÿÿ!ù, „©Ëía;tkHTML-4ee7aaa953d6cb59/tests/page2/image20000064400000000000000000000010251151224263100174220ustar00nobodynobodyGIF87ax õÿÿÿõöúíð÷êíõæêóâæñÞâï×ÝìÐ×éÏÖéÌÔçÅÍä½Çà¹ÄßµÀݳ¾Û¯»Ú«·Ø§´Ö¡®Óœ«Ñ•¥ÎŽžÊ‚•Å’Ã{ŽÁu‰¿q†½m‚»j¹f|¸e|·^v´Wo±Tm¯Lf«E`¨D_¨A]§=Y¥9V£6S¡.Mž'G›,x @þÀ•pH,G’Él:ŸÐ¨´)¬T `±Ò$+ȇXŠ¡sc˜Ê(€¸Ò·«-Lÿ€PV#&]DCƒf C#xD$)Šv_ ‰§¨+O)«­¯L_‹©¼½O ~CŽB*D+!®’C'{BÌË]w (¾àà&`á忀êêO«ëMÝç÷¨Ê˜D#<²²B„ \2€Ë3Œb ¢+* ‡ï¤ˆ#"q 4|‹´kÅ% +@Xë"a ]@(Ññ;¤ @¨ø`‰O䙬âÀŒB˜BE€+,8¡HÁ€OEM¬ìÙ1ÅX"O©à:ÄT²¨‚;tkHTML-4ee7aaa953d6cb59/tests/page2/image21000064400000000000000000000010641151224263100174260ustar00nobodynobodyGIF87ax õÿÿÿõöúíð÷êíõæêóâæñÞâïÚßî×ÝìÐ×éÏÖéÌÔçÅÍä½Çà¹Äß²½Û¯»Ú¤±Õ«Ñ˜§Ï•¤ÍŽžÊ‚•Å’Ã|Âtˆ¾q†½nƒ»j¹f|¸e|·^v´Wo±Tm¯Oi­Lf¬Gb©A]§=Y¥9V£6S¡.Mž'G›,x @þ@•pH,ȤrÉl:ŸPb!,±Á†àM¶¤Ê ÀGU @ žQu„€EД&` 'Q‡ˆCdm ) prlŽ&$"B*##t* $(*` *])‰¿QÀÅJ)&ÆÊI`eg*’ !p!BcmdBm*qs}pÔpäm¹&îËö÷øùúG#ûF±’À€  , !¡! üS–º¨È`ÀƒŠ† ±uTaâO~$†!€;ÀN…h Ìb àCZš¸9²€Ä&LRñE/Êhg.ôÜ”™¨ÍˆœhC„FtJ¤ðfŽØ¿'w1=G'E€œ’õ‰H…‡&pœð!µJNÐ"¬";tkHTML-4ee7aaa953d6cb59/tests/page2/image22000064400000000000000000000001211151224263100174200ustar00nobodynobodyGIF87axñÿÌ3PwÐ0_À$D™,x*œ©Ëí£œ¢Ú‹³Þ¼û†b@–扦êʶî ÇÀL×öçúÎ÷þ,;tkHTML-4ee7aaa953d6cb59/tests/page2/image23000064400000000000000000000010331151224263100174240ustar00nobodynobodyGIF87ax õÿÌ3÷Æ3îÀ4ê½4æº4â·4ß´4Ö®5ͧ5Å¢6Àž6¸˜6¯’6«7§Œ7œ„7˜8—€8“}8‹w8‡t8zk9vh9tg9h^:d[:]V:TO;HG;GF;?@;>?;6:<27<.4<%-='=!== >>,x @þ@€pH,ȤrÉl:ŸP!jŠª@PB‰¨ „Þ©€rPiú!8#@`s*Ü `·LMQ‚ƒK(#B'#! ( ’ d( ' ˜pe 'o(q’ „´µR‡¶rº„»ÁQhD'(‰]_•cd'$"(oq¤"o!$q¥t'˜ÂéêëìíL îõöPÄB" #|ø\ðÀP,ˆpìÄ  H!B "H5t÷ÒÊ,ÀµYÌ–y!)EDˆ<®}HFŠ !¾qq"CAœ(Hh@rŠì0í„®JB*0€©L$=¢Î¨"U©@€:d0瀮 ']+¨°#Ü$ Ћ-’ ;tkHTML-4ee7aaa953d6cb59/tests/page2/image24000064400000000000000000000002271151224263100174310ustar00nobodynobodyGIF87akóÿÎ=ÿÌ3àµ4Ö®5)=Ž&6y%>›3ˆ,r$[,kL„I«½8ëÍ»ÿÀ Œdižhª®lë¾C"Ïtmßx®ï|ïË„pH,ȤrÉl: „ƒtJ­Z¯Ø¬vËíz †°xL.›Ïè´zÍn‡#;tkHTML-4ee7aaa953d6cb59/tests/page2/image25000064400000000000000000000007051151224263100174330ustar00nobodynobodyGIF87ax õÿÿÿõöúíð÷êíõæêóâæñÞâïÚßîÐ×éÏÖéÈÐåÅÍä¹Äß¶Áݯ»Ú«·Ø¡®Ó˜§Ï•¥ÎŽžÊ’Ã|Âp…½m‚»j¹f|¸by¶^v´Wo±Sl¯Lf«A]§=Y¥9V£6S¡.Mž'G›,x @ê@’pH,ȤrÉl:ŸP!À!&$@Cº /@`³X…,`íø ÖˆPtN¯#Œð$!$ $egirf#v™šP›E# ¢¦§Fx ˜WRXZC jB ¸^¨ÂÃÄÅÆsÉrÇÍÎIS$·$Ú  zTfÛ´aÏìGkkX‹]½µiZ THK»ƒC¢ i `A˜ôQiÄFfШ¹ð“‹" e•"Hj ;tkHTML-4ee7aaa953d6cb59/tests/page2/image26000064400000000000000000000010101151224263100174220ustar00nobodynobodyGIF87ax õÿÿÿõöúíð÷êíõæêóâæñÞãðÞâïÚßî×ÝìÏÖéËÓçÅÍä½Çà¹Äß¶Áݯ»Ú§´Ö¡®Ó«Ñ˜§Ï•¥ÎŽžÊ‡˜Ç‚•Å|Âu‰¿q†½l‚»j¹f|¸e|·^v´Wo±Lf«A]§=Y¥9V£6S¡.Mž'G›,x @þ@”pH,ȤrÉl:ŸÐa€:5 ˆ)ŠØnFÊ‚5|ˆd´˜P€È° BQƒ„IT"#[E'BX j! wB B U( (…±²i²K¡¹¼½†T D~D ‡%[y™T€C»}Ñ 'r^¾á⃔ãç…ëëèBîòP‡BFb(hð(Ã"àˆB¡áÀ›q8PBÄbóÆÕs0`F!š±Úr ¦:(>ð M”`ÄD ðRŠædÔHE.ˆÊP‘ø„F¶h˜âŒÄe „ @KÀ.(`§<PÃa{ä•W;tkHTML-4ee7aaa953d6cb59/tests/page2/image27000064400000000000000000000010651151224263100174350ustar00nobodynobodyGIF87ax õÿÿÿõöúíð÷êíõæêóâæñÞâïÚßî×ÝìÐ×éÏÖéÌÔçÅÍä½Çà¹Ä߯»Ú§´Ö¡®Ó«Ñ˜§Ï•¥ÎŽžÊ‚•Å’Ã{ŽÁu‰¿q†½m‚»j¹e|·^v´Wo±Sl¯Lf«E`¨A]§=Y¥9V£6S¡.Mž'G›,x @þ@”pH,GÉl:ŸÐ¨´  N €Ò ¨G‡X‚Ÿ³cØ(OŽ@ QB1'ƒá„jpIZtS„…GV!#]DCˆf D $Šv ¤' &[(|†µSO&¸º¼L "†'$¶Î„• nC“B'D•(»—›#&B äæ {ä B$ÈÖÏóÎ#`ôøùóýýO4àò÷€‰…~Bè[Ho[ À@$„JVP€0‚ƒ C¤¡Q ÅL…ÑÃ`ÄF=8` †ú*9@¤d[H…B¶uC NH/k²à€Ÿ ž‚€y8Z¡`VHŒÓ 5hÆn  egš JœæW丠èpb•Yš0Zd-=㢔HØH;tkHTML-4ee7aaa953d6cb59/tests/page2/image28000064400000000000000000000006401151224263100174340ustar00nobodynobodyGIF87ax õÿÿÿõöúíð÷æêóâæñÞâïÚßî×ÝìÐ×éËÓçÄÌã½Çà¹ÄßµÀݲ½Û¯»Ú«·Ø§´Ö¡®Ó«Ñ’¢ÌÊ‚•Å’Ãu‰¿p…½m‚»^v´Wo±Tm¯IdªE`¨D_¨A]§=Y¥9V£6S¡.Mž'G›,x @Å@“pH,ȤrÉl:ŸÐa`*1ÄÈ´ !`™Œ–¨zÍf?¨†˜˜ ˆ#°P„$m†‡ˆBvj$%‰”•Qo& Bš&t&C“–­®¯°±•¶²¹ºK˜&&"  Ba&$c »Ñk˜ B `\£~ŠÈÒåN˜#%ì&é"¤"$ &¬æþM$H ѯH‰ÿd;tkHTML-4ee7aaa953d6cb59/tests/page2/image29000064400000000000000000000001711151224263100174340ustar00nobodynobodyGIF87atòaŒçHwÙ3\Ê0_À+O¬$D™,tFXºÜþ0ÊI«$ëÍ»ÿ`(Žd) hª®lë¾p,ÏtÜx®ï|ïÿÀ pȤrÉl:ŸÐ¨ô9¨Z¯Ø¬vËíz¿à°7;tkHTML-4ee7aaa953d6cb59/tests/page2/image3000064400000000000000000000251231151224263100173500ustar00nobodynobodyGIF89aâ"÷ÿÿÿccckkksss{{{„„„ŒŒŒ”””œœœ¥¥¥­­­µµµ½½½ÆÆÆÎÎÎÖÖÖÞÞÞççç÷÷÷çïïï÷÷÷ÿÿÆÎÎÎÖÖÖÞÞÞççµ½½¥­­­µµ½ÆÆŒ”””œœœ¥¥„ŒŒs{{{„„ÖçƔµÎÞçï½ÆÎœ¥­Öç÷½ÎÞœ­½”¥µ{Œœ­ÆÞŒ¥½çï÷ï÷ÿÎÖÞÆÎÖ­µ½¥­µŒ”œ„Œ”ÎÞïÆÖ筽Όœ­„”¥µÎ祽֜µÎ”­Æ„œµ{”­œ½Þ”µÖŒ­Î„¥Æ{œ½„­ÖÖÞ絽Ɣœ¥œ½ç”µÞŒ­Ö„¥ÎµÆÞ”¥½­Æç¥½ÞœµÖ”­ÎŒ¥Æ„œ½{”µ½Î眭Æ{Œ¥„¥ÖÆÖï­½Ö¥µÎŒœµ„”­œµÞ”­ÖŒ¥Î{”½Þç÷½ÆÖœ¥µ¥½ç„œÆÆÎÞ¥­½µÆç­½Þ¥µÖœ­Î”¥ÆŒœ½„”µ{Œ­Œ¥Ö„œÎÖÞïÎÖ絽έµÆŒ”¥­½ç¥µÞœ­Ö”¥ÎŒœÆ„”½{Œµ½ÆÞÖÞ÷ÎÖïÆÎ筵Υ­Æ”œµŒ”­„Œ¥½ÆçÆÎïµ½Þ”œ½Œ”µ„Œ­µ½çççïïï÷÷÷ÿÆÆÎÎÎÖÖÖÞÞÞçµµ½¥¥­­­µ½½ÆŒŒ”””œœœ¥„„Œss{çç÷ïïÿ{{„ÎÎÞÖÖçÞÞïÆÆÖ­­½µµÆ½½Î¥¥µœœ­ÞÞ÷””¥ÀÀÀ!ù²,â"@þHp`ZªPa¡Ã† -IœH±âD–dHÀHA†ŒŽ KQ)²ÒÈ‘&+©\¹2†J—0cƘI³æLR7càÜIŠÔ™ž?ƒ =C´¨ÑE‘žQŠiª3OŸâI¥ÕBx°ZÝʵ«×¯xrX›£lYC9ÐZ˶­Û·p½’K׋/vñÞu´Wß¿‡ <˜páÃ…µÒ¢¥Ï˜>Œ7rCÙ–F—kÆÌ9s£Ï ?»™LùÍ›(o¹yóÅÏ+Räĉ$Îkt¸ˆáÂEÒ:bróæR§ÎpÞÆëЙ3ËœäÅ%_èÊ9€Y¹ŽéïàÃþ‹/~µ›GŒ ‘:X°½û÷ð Z(¡B(ØP @KPTA€@‰D ˜ Q%$` *É`ÒI•X(…ZHáK•¸ô)˜hâL'êdN:u"@¢˜@>QÃ1 ¥“'‚% ˜B QMKQOJS*,¹T“©¢d*S‘°ŠŒ¢Ô6  UWbÖ˜bY%晆(fk Ð Zª°ÇZl²I§yÈuWž{Ú雇Øõ'_~épס¦WÀÐ]a„aÅVDsˆ¡©‹¡é"›‚*FtQjptlªêª¬J²©«þC¸ œt=ôf+qŒ ÇÈn¹öÊE®Ç{\rÈ‹±ÆWqbÔë³®fÜ´tTk­µ¤ÒAj$XD:G$s.säŽ É¸±Éä™ÖñÅ«AX’@$ÁLà@ˆ@•D` h A  0a)8˜À(XBI2 ‚&)‚ hb!%`òR)1ŒâIˆÛH‰)T²É()ªHŠèD &€'ÜxÉBw’ÉRx@Ã&œ‘I¨ uIg4ÝÉ 'ÀRà 6Ì• À‰T¢ €U]ãqÆ)Ì`Õ  hUx ·þU) ‡UlhiŠyäцàÑÆxˆù iÑ ÊÚ† mH9 І!àÀ¦lîÁ ké0Â+†èº\y8Bc§­¶|,)‹ðÀC¤B€º¨aðªïšöÐŒô<#Ë+o|òb¸Êꦩjj­©Xd¿ÆG\E Û7—=X\[­õCˆ!-pC¤?DµÊe!mÀ9k³C "F¬öÿf?ýYIJ@‡:€txŸùx-S‘¯|¤Â·šC.ç+0Du¬S9\,¯c…’á„($C !‡Jr`xÎ/„Ôˆó™$ /ˆL„‡þ¢D‚¨MHA ª„%”˜¡R¨C%ÉÐJDâ’–À$D)ªN´˜“œì„&¤°‘O&0FŸü¤GJ!Ê|ĵ¥ åH]+R× ¢¤¬@JVi,ð *$ä–i¦± %Lk\ZÖ‚;ÅNv¢“$uÆD_€ÃX …àánw<˜ `àA#lÇ 0hÔí‰ÜíŽ<Bd9*YÎ2Ra˜ƒµË^6‡T³B$„iªb–*UÈ4¦ŠéÀj)ó˜¦ÊB3h-išAYÀB3˜Ê›f C8³€„b fèf8ÍvÒá€æDBö°€Íw6›ÙþÃgùòéœ50Ç‚dÎ(È Îa ¼B <(‡…2´…Ú‘ƒä@tÇí|Ø#ÞP ¹! #Z¤¤FLP‚>¢‘R,1‰1ɆRB!–u¨Š•pbM°x¢}QE@íÉNp䓬'Cš@PŠt†!5…kM‰ — 9. ¼£’ðФ@2+„äJé†/€!%Ø‚Zƒ°+\ @¨BÞ €“_ˆ‚eå;©.Ou“êðÄ:Õ°ÒÁb¦@'¡ Sð¨PT 4•ֱŠp…2áo¨‚ Ki…îu¶ dCŠð„2á Nðþƒ¦ð7L±SpC>sÞú`2ZM#vëBŒ†¸ÆÕ«ruË\ÝF! “pî$ôÚ‡(<º/˜Ä ¢PÝÔLáߥmÀû†ôá çͨz×ËÞöºW½‡€ÏBèC¯ù±^<I( H#Zi)’Ä}¤$²̲ž^D(²‰u2™TGC:ê”JF£.•>yêRŒªÖ±Ä$ ÁHP©¦Â«° Á½ò¥°&ò+ib¤šÂ¢–°ÉÇ’d $/§§µ6’sù“ê–ì»ÊP|)L”³0ÆŠaÌo÷JåÉ„V—µª@?x° ohþkâ …HLkZŒ¨ÞôÒ' Ýl*}u`ûöÇçäôª~ÉN ­,dº8uN‹Ó,F+ÏÓšÕû¬‡ªk-B[ÚÊ0a`?øA†ïýjHjú6ÄÔ™À$&bX+P%ä0Tìˆ Ê@0à!N€d£Ð P‰\âCâ©^¦„dâD E%:1€œÝ¤¬w(tò èäŸÚŒˆR#Œ"4 Q6µP€Âz;C–P$½¡­ª/î# ¨Â†¸aÅ ¸ÊR€‡U0l¶"Š€îoVA,ðÀ‰QŒéLyÐC(þ(§¹Æ"tîVÝZC„€tkêò`¨Â­…/†à‹øzˆ(Ä!RÌ]§@ÕàÍòw<îÄÐ;M%SPŸžz=㉒PÞÕ¹ ¼_åªë_O׳žç!ìJ7Œ ³¦tó¬ZkžkXÊ….@¡îv·;Þï…;@a wüŽ0ø¸Ë}{ƒ?Â߯ø¹ßîw<ÝËP†'ØÁ•§¼Z»ùÖRÞ:­ÎAË•ËsÍá\R˜ƒ q¦K[@sxF]ê‚$¤^9”€H²ß’qˆÚˆ‹˜!ÿ¶ÔBÈïHI¢ø!™‚ˆeUDQŠH"MŒFÅÉoþDFJõ'>jjQ†4â6ž¡ªql#RTLªàáŽ2þ#TY«Pi+5þJôð‰ —[!&iH˜ÓHØ‹t9 È&5:à@ ;r𬡶)¿³|p<Øh<XtTwi¹£‡*Ø-¾ä‚³ ЄLçãL¥òL¦‚*•–*é“@Ô2iós>ÒÒ2ó£> D@ñãvïc@Y?OOòóNòÔ´MÛ„t Ä…[˜OBÀ…ÜÄMPÿÄ*8P…A e õA×ñA••RBbö@x8 ö†@j9R74 7T%µ_þ?t&5D"qDÅ·k3…!2àD(Ñ| aXtE,ÂE>¥39#8âaJeFHá#5¢FâçFæ×FUUU%GK,&cQ’ TR_V66cÒ‹bò7h’: „pI‰°RŒ- º£ŠŒ¥BŽEE QR?/@Z°s~¡Qð‰ -tô> Ôƒ¿!$Zˆk€G°e0QVPy8éi}j"9’êõi$ù5ˆQ ¡{F4 0 þ|D„R*…Rñ 2aÈ·`4eS˜Ø–‰T6'pn;Ñ#ÙwŠ!fŠL1bçGUåw$K¢' bXÙŠN1px„_’`Q&bgjŒ?6dHÖ€©3‘Ô–Žp'€•†âd„RÞ(‰±‡Ae~©(~©opBT0ŒEj@c0S€–ÁÃeIºe°‘0KbWG¾‚+·ÂÀR?À"hÎRg„&,…FÇâg…&‰æšÍÒ,®ò+Ñ# ˆ %W.,$`’'ù޵Wjì15ˆ„8 úD½×’)5D!.5D±Dþ²DýEm9µa8EÓa?U_Ô#@‘#>C~§ˆFIAOa$Q媈•…0pJòG€´$Sº¸‹géÁ¸c d ˆ9BÖ ƒIxsuy­cXNæd‰¢XQæU`^«Ef°C¹U˜*A 0`*¹Ô-r–uš"=¬b>«£³™v0Ê>¾‘£|–>¶’vz棿âgÄ¢š¬Y,‰Fhõ£,Ðâ>Ô2„4øL1h*ô™IÃ.™Y.²QÕ^`œÇi{ôõQÊÙ ±°jpÀC b/ž`D °`08 !@ p ý! P!þ° «6×V 0   @!1àDÐ!PJp 2"ã6¢à “º ž(› T ¤0`Š@“ C3zo¤P—p¡À   ¢Jxp«yJKÑ7zÄ«`]3p_•nV!9€%¨€Ÿ P8€{© '‹Ó¨` VQ{Ð@¬V¬Ö*##®6àhÁ®Z¬s#Ð"§l:”ä'8—Kf‰ŠåTP°˜¶*­$K°4u¡¢)ätŸu¢"u›Buf=šâ£µÂ<¼âu¿Âuh÷µ²ÈñgzV+y²Éþh°‰hÅa„FØN‚N‰¹=qGx€w‘:kx…‡³BëOý˜=ñ¨-Ä„iÄ™ââ-¹$JÌ! µ¼ ©gµêB9¦ó¢œdZ§v`¦/¹ ` ¿v |C” Â! »–!Ÿ20ž0˜P `¨¸:¢ €3• ÐSyÛ2€},"£Ú1 œ0À”¨0l>Ò Ñê4¤0£ZªJAœ'—€«{ lðG ‹«4 3À ¢¶(%{  Hy°7…°€ %x   ÌÛ ­¼zHh3«þð‹pl…0œ‹£á»o’$5°€k± oé'ª#‚‘:ZçØI't‹€¿¼óIJ£Ò°Ou ÒSç<ËÃ<Í£À\Çl=d‘ÛÃwP xÜÃ=†W‘ødOö…ô3@ösš¿±?´?¿ñ„t @TO \-ø4†ü¤=s° Õ=ÕQ”×Ãe€€yqX§%f'”-äAK X›Ä²÷}@jµœ94”ðP ;$Å|Îyk˜à{ B  B ˜¢!˜ 27%8ÕS™€ 6¢‰ØGžþæ#4€ا  >ÓTñY~E±ºï‡y€(@•4€¾Ú~1æ$Uµ÷7 J ­°lÐ hðz0erc—£G€h¬üÌ›Ê^ ¹EeZ+q€Œ¹ƒK¸C‚úË)$x<Æ#‚ÍÓûËœb¥ÄD¼tKËDA`†X°LÈDiÔc=Ò’* TioÎ|v@ÁñhnW?¿Áú£?Œ6„?ÎâÂÃWx- d>¥R>ÍÁ-ûx†ÿ¤‚£s°Ãä†Ú¡&„BÀ‘xh!I{ïÁ]‹C;´{¸6é{— Ò¢$-Sr!'Áþ!òD}™H”.A}+r}7rLI £¨Mu#NE•營M~™ÜU/æ6T"ôU¼‹¼X&‹TH®ìc“–h1d Ú€~•:ƒAo- t¸S;µÃ)XÀ¸)˜zj'µóxK¥¥²T×K[׳4ƒé)É”*9ÓB@¨"- Yƒä@ $…Õ ,?ŽýÂQøNìtMÛÄØäMø†bX-™Ù‚dHPeHÐ$J¢ •Ð×sXQv˜mµ‘! `ÚÉI_è’…ØÅ^D¿`ÀwDET`|²“ßéDRÄ!.áD:Ó1!ÓÔþÇ"é9}Fçv#â·FMálÄÈSùFCH]G/¶Ÿ×GïÇUö' 6V RHgY€?¶H@f(=ŽÙ˜Œ¹C;Á*u8Ö|€;˜¿ŸdK¼ƒKu­KïÞ¢ï8Ë¡ù(AÌtLÞLÌÔÙÙ†ÌÄ…B°OÒtL÷œØø„ùâÝ†Ž Ãf€NÝ$OX¨_ˆ³ wÞƒÃ8 Bµ©ÝAj˜ÚÞ‡u(ZÛ!ä-¤†ä"õP«ÝBq0]ê^ñå·=^^ˆú‚ó Ή¦Ã'“Â]“.u·ÈgRâDâÒWTçÑ-éùEDÅ}þAá#7âÝâÇ5fD~L1G†Ž~KâqHíÇG\uÔû) b©…”‡°QPV;pV‰ÀIÉøé'j&PNИc@A@JR`ºuXxAd…so©dy’:X6YD@än)bàÌ»ƒ×¶T.¢­áÒüÏ`Æú¸LÚœÍþ|âäã@ºÄìtpz(f-Wd¦ZT°.¦1Öå\ªîªqØ]à>]Õ5 Õµîo ]é…^'YïöjmÛ8äC]ë¸G¾Ç_â_GôÆï_âæRdâiÒáÉ‘*;U”žÈBuñ: èIb^~rUPpæ êÝþɹÈ6(ïŸN &aalar/ÏHj± Ø u¢Õúúd†BI;¯XŠe|eQöóƒñóA?˜‹¡JŸô¸Ì‡Vv¶U·U¡Ñ[½%\ Z§Áoq ‚Á¡‚»Äg¢É.,uæH,ƒF¤f¤Î¢g.{š‰¶$4BVðÐÞÞ¥ yïµeð¦µWÅcNRúrÅ 1ÆðÒÿES»¦`²Ò>yÒy©ož0AÝTÿE8Ñ#Bñ#NŠD⊉®~\©$PÒG¶xòŽÎɰïÔd™ 2Ïc’d3¯ûni'îXu¹ó e~Ay0G_(B_ô‚˜‹þeLŸeYv“U³ÔiE ¢•EêTà+0 q þqPYrh‡£W+¼QgÒãz&+³R¤íšÇ",CjhFz¬Ù,ºáQGŒ@Iň)x° 1 > FŽ•?~Þ\ĘQãÆ7}ðRäH’%Tié¤%”*]º¬ðÒ’K,gÖ¼)AM –vR P©§P AeT:T(ÒJKc¥Pªi©Mc\­T+©¬1H]½ú•ÔX±b¯žðz†Ô™jÛR:£–-©pÙ²=‘·mª»©H¤R‘ V*Â' á!Ö Xx'nìXòdÊ’sP6”#³!Cx.ãþáOžÐšóhæLš´¡Õª9ëÈ£Ã/:tÊ“ÇË!/yÉ>tÛÑ¡CŽ~×qü7Z´L3fJq7QÜ4×2éEŸ7S¨È!Ë,W®#Œ˜ER¤„™Ãðàüƒtä9ˆ_Ì‚uzÄO.ö3H :$ñ ë¨cˆ:¸hðA!„ÁİB.dArPüÙOûèÈâDûR±!1"Q1 ûˆDˆHà»9䈣 ?¨xHŽ6êà RLBÒ$”@ZÒ% @ªÄNh ‚˜*  Ëšh ášxš‰¦Ÿ(!“LÒ (©¢‚ª©J¤²*«¬àŒþ¡D%“ª¾Ò ,³¼¢ëA-Pb¬«Î „¬¶â¢k­32Aa®¶ôb+Jù:ÃRÀR)„0ÃC…BNPl=ZAT*cµUÉ:Ûì²Îd-T4Ë´–`ƒ5_Y[ÍWÒzcÍ‹Ú`«ÍÜj˹âˆsv7´ ÂŠ à¨â 9àhÎ;*¨bŽ0‚Ž0ʽ‘!èc—]ù\œO?± F†`„@øÃ·Ž{´0C&¸à .øÁ'D°Ázæ/‹‚† ¿‡T¬1,è¨Ñ\ã  øæˆDÜ9L>Y܉âøŽ!5Ò"I™Pé$&aŠ Ml¶ÄjþÒ’¦š àKKzÒ‰&<ª¦¡Ž– ”˜ZJª£ªšëªfÐY+«¼Þ,¯®úä°B%­¯Îˆá.·ÞŽëºîÒ+/¾N¸{0K# 0R ùôS  À¥Á(!ƒK| +A‰A&LáL`¢€4¨D&Љ`›ÀD¡ÆÆ5%\Ehb'À6Rp`1(RO|à ˜À H!Q €¡À”@N( E*Bq<œa 8l Æ¤Á_PƒUÙ@)ȃ`<Ô KЃ*VA=àX>A4à ›Ä@€Uè ®ØÃe˜ C°¡8Ѓt`€b“lÈA C¤@¡NÒþ ΀6¿iÖlˆSBüàn Â{Á,‚´[ĹÖs;öð@ ëƒ7q§»ÝÍ'_ÿ‘DÒ™N1ô`yŒ`„;“—=wŠAy’H¾’7 o Ðóײ P¥h X@ÂA×……BÁ¡}h  щJ´ hEí0Ñ'Ø! véÊP;tô %éHUZóbWHÙxà3Ó“¹ïdRx)$À#)ìȧq°ˆF>ò¿’°&!¡D81‚8à°‰žZOÀ›(ÀM`U ŒÂIóª p´(@•@€ £BÈ€H (!§:±‰fÅJ 8þ‚J|a3 (`1XÚZb0€MäQ ðàâ×3lbwAÛ F‰'Q`Ž +”Š<`)@A³ª¿Ô`ÄÃjàT µ `|)Šˆb˜4s°"7ðÀä>)@8h%æXÃÌà¿A( 1€6膺zÐ!@‡eÉÆ¼Ä‰BÂPM>,âvîC{y°MnŽKï §íØuÍôW ñŒgàà yÉð½ÔY z)D^.Bº††:ô¢O€(îp„ +TÂXÀ‚°›! &>±Ì $°ØÅ-f1!þK˜ÂG¸qޝ…@¬á #…ÂJ…\+¨e8r‘a@bGW˜_ýp?)@â :ÕOåð‡Ä€¨5[RLh€ ´Ä%œ@€Xmb ( è7q“xB„Ø’'F!ƒ6Ë *À4¡³£\"KJ)F ºöu°•'´B Ð`К‹ØjÛijTº Å*;G‰eœÈC2qÙ®eÐ(0t\è–©»˜"g¨#©l‹ë¿ N¶r­cRÁQàáè$ ‚Ê ’q…)<‰¹Ë¤€£n'?Ôxà9Øehô €C´a¾ÅX#›Øþk6ZxA~Óˆ-„=Èæ6à »û."á¼7ñ{þöWÀ 0€Ovþçw ¡C"¯áG€ÆyŒccA‚PÅ2’7Dû9¿¼w=uèŸuÅÔ½™‹!EEQÎUdA”‹óxÇÉC—¶ô 0’•n@hë M&2¤Îd&ûT:…DOƒTŒ4âË!Ú˜·:JˆÀ;³``w®I`Š &`$@2ÀX Ä€£\¥‚”"*¢`´) ŠÀ{BNM´ž*A‰¿‹â±Y…ÙÆ–iPÀóF”4)”`ZS€þ°gPH¸…3¸ø'‘‘Ü‚s: »‚#˜ƒ5:u)—r—û¨˜ý¨ûdñ™9~‰¹AA˜3!1a¹zIA›9‰I‘Ô¹S±ž: ñ” „ú™ƒ"D:ó§{²$[2+:2ø2¨2°þªÛ‘8Ј(ø•0ª1s š‰ – É¡)߀š€Ã+    š¥8ŠªI´Çk4¬èŠ>‹¬à“²0”µ¡@ ¹¸ ¸x‹¸°‹EaļˆXÈÆ`ŒÁá ¾ D@’ N!•Æi4ø€=ÐCb…ႜRÌÔ _É•ÎÑœ_a7CЂ7¨0ƒ7j’/jš/àƒ{ëÅöê¯{ë_0D@t/©)#º9XñºñpFò‚jìÀúÀÆë@‰Ÿ¬A›Çˆˆ¨sì(˜sá˜ÃÁˆ‘L‘̹û8빟³ ÂhþÂ#<¢{)ÈŸ£[„ÔŸj2ª#ƒ8 ©+*”BþÁˆ™ C0\ 1”€1ìÈ™C-Ù’‘œ‰0I¤yCËš¤y“ 0¼–\7Á<­›±ùCœ ÄPK ¸X‹¶µ¶pJhDºqD¼XŒÅ¨ÄJÉ”Ààµ?r ¾>ÇHNd•ϘÉÐØŒÍЕÓ`ÅÍ™ _97‚÷)Ø)¨¦¶œ¦{[|»öb÷º‘™ƒúó€²—‘—™ªFsaôÉÜñ˜Ü@Ÿó9Ã4L Á9ñ±£˜z¼ApD1PAºÌœ#±Ð̹AÀ9˜SAMþÍ1:ØGãÇ œÀh$B"4ÈÜ™€¯˜¯H”´¹µFQDD‰›EqJ™”¤Ì ý¬DPÊÄ •Ä8ŒÈ¨Êª´ÊW™ŒÎ¨[é ψ•Õ@UlTì -ˆ‚ %¸P0P„iòÐ\\/øØKm1§ƒ#„ˆøËˆPLm2Ñ&mRÌjì˜rQ´ DÆ<ÍÑ©G µÏÄÁr1ƒÆ¤3XÍ3@‚$µ%UþÍMAÈ‚'m±,°RK‘ëA}ÄGA°M ™!”Æ“q©¼ $œ9hS„äMô@%N&ƒ®ãˆ˜‘™0C– ˜8Ã1Ä ’ü’éDšJ¸ JH²ЍI4£X ¥Àªx<òìŠ=>É4²pOÅZ R€‹¶ñIDt›ŸÄ GÜOIÄ›¦´DId-á3 ØŠŒU9ÐÊÀJÉ‘•È1%(ETÈ ]ќՠ(x/€0Ehjr¯lÊK§»B&3ÀôP¹Ì¯j¢ƒù¢‘5™õ ™™ÆÄ‚9g´‘j¬Æs1—ÌÆÜÀ¬ÆñQwA$ ÒìÇ,1þƒM,RÔ4±k1³R)E‘)ÝÒ±z9“M ±”ƈ=Ó÷9BüqSœâÍ'KHàœˆ;}™8$itN2´‰ Ô”í‰ *T8Lš§‘Y7ìN6¹C¥ϦO­)OLÍɰ( ö¤"*jÏO•›·aĸ€D½XŒüÜ‹¼ÀÙ¼ÐPY•«5ÐZMЬÌÕ% Í•á¸Ð7Ø0XË÷ØEj Eƒ ˆV'¸B2pÛ8¸–³LÖ¸„Ë8j2—lʦÑ™‚oW‘Ìñ×oE\ÃFumWĤ׎“\ɹØËQ†5ÇzTR$1:h±,ÝRÑÌþ˜‹0 ³B2ðƒ* *ðƒù*€ƒ1p]Ø=Î;µ×Y?ÀÝ×}< ’Ø…ƒ?è‘?ð‘*¨‚á­?ø&C*8Î͈ä4‰šI æÃŒÎ2ü’ yY5¤ DÞð³ì|ԛɧx“ª “<¤«Mõ@ÁÉô¤¢¯@‹±@‹35úüÉI©Ï3hZ¤Ü‹ÀpÊÁQŒ¾¿¸Ú^ÓZÊøŒYáÊÛ°Ð/@„D`)h neÍ:)¸B·%ƒ"(k±E‚8‚7øçpcY·ÙÐÚÐBˆ8 Û×™¦ñ·Ø‰@eQqQÌš:\ø˜Ø“1Óf¤X!ÂÁ„—vYþˆ†¹rùÜ,‚AŸ»,@:"‹ƒ"h^Ѝ‚8°á8ˆèý]ŒèƒGèƒx{ƒGxƒ@ã7pƒŽ¸îÞ;Æã<Öã=Æ/ 0C @] 4C”5š/ÁÎ jÃ4ÁÎ7„Ôš•Š—ÄÙõÅ!8yßK›®à“öŒô”AT‹A<Úµ€ ŸDÚ¥àûजMù”M1`曬åD¬Ì „/ `0H„-ðå¶µ‚8ˆøƒ"¨c& øà ¸`]ÖâÈb–dqácj·ãØ ÝЂFP'a"«‚ˆ9Ø&û\…©Íâ"„òúyçxº@À(ƒ%þ¼ç£;‚+ Ú½*˜8ž„:îŽë°ƒ®ŽëpƒF8hëp脞„ê°ŽIˆ‚)x„Š~„9Ž‚Gè(ã7ðèG€c‘®c‘vc>Fé”Vi<6$ñÂ1ûÈšÉAÔ•ý’—mY8„š j¡¨ÃŸOIž ¬é;<|ß>9OL…ßLË´P¥‹¶1Z¹(å¸1DU^”½Á›J´ZRÁµ«U-aÃZvÖ8„@ƒ]îåðå-@a ‚ä…ƒ€]þ^gžÐÎVVì ݈ æà(¯Úà áXè7`è"°Â20*ƒ*˜ì"çh7èŽø–è "PƒW)Ðì> ‚>˜ÑvØæFXímö†fŽFÈlBí(m7 ܾŽÜ®†Öí‡Îh7 è( èâ¶ŽŒiãè96é6é6Æ5Î;^éê¶n<ÖS‘;tkHTML-4ee7aaa953d6cb59/tests/page2/image30000064400000000000000000000012271151224263100174270ustar00nobodynobodyGIF87ax õÿÿÿõ÷üîòúëïùçíøãê÷àçößçõÕÞòÎÙðË×ïÇÔî½Ìë¶Çé¯Âç¬¿æ¦ºä¡¶âŸµâ˜¯à”¬Þ§ÜƒŸÙ|š×x—Öu”ÕnÓgŠÑd‡Ða…Ï]‚ÎYÍV|ÌOwÉHqÇAlÅ>jÄ:gÃ6dÂ0_À,x @þÀ“pxòŽŒqÉl:ŸÐ¨tJ­Š&ØŒiè‰8.ÛSHÒ¨˜LÇ$äLHî“›tÁNØ—‹|"f&E!'&'BWB]_[W"&zU–K€''B £%C ž™z# ' •©B B%¾À'™€ ¢¤ ³—ÔÉš''% ƒ'ß#©Ö•z£€ ñ´™™ñ¡Ù Öú”qónP&´¦U³$°€ 'x:‘À¤PÃî¬ ß(4@k¢iâõ:ñKˆ}Y"(QHÅ™< p¡½ÏŸ@ƒ ­–‰…Ä91"ÌЧP/);àÀ‰2xpÀDJ !¡[%$ßЀo <÷Hx€×aPƒo#äÒ !«V®&òqÕ‰@pšöËÃK"c;‚ ç¡j-ˆpóº•-O\ aã™×xÃG9VÏÂC2 xK?ŒÛ@ààÀ v²±@Š.Vð¤iHhb'h`"<‘bh·µYë€A5ìÂNa‡ÿn);tkHTML-4ee7aaa953d6cb59/tests/page2/image31000064400000000000000000000001161151224263100174240ustar00nobodynobodyGIF87axñPwÐ0_À/P¯,x'Œ©Ëí£œ¢Ú‹³Þ¼û†"@–扦êʶî ÇÓL×öçúÎß;tkHTML-4ee7aaa953d6cb59/tests/page2/image32000064400000000000000000000010541151224263100174270ustar00nobodynobodyGIF87ax õÿÿÿõ÷üîòúëïùçíøãê÷àçößçõÕÞòË×ïÇÔîÁÏì½Ìë´Åè¯Âç¬¿æ¦ºä¢·ãŸµâ˜¯à—¯ß‰¤ÛƒŸÙœØ|š×y—Öu”ÕhŠÑgŠÑd‡Ða…ÏYÍU|ËNvÉHqÇDoÆ>jÄ:gÃ6dÂ0_À,x @þÀ“p(1†‰Èl:ŸÐ¨tJ­ZMšÇC#Ì>8Â΄$>‰ÉãòÙdq<>áÉI4é˜'¢®|ˆÙ[ÿ€R !C B'# ‘“• ''r'& C¥³´C«B!ƒ%BŸ'G{ Å'›Ã¨'¦¡©žHG&$µÞVB&Ž «'’ ëíïñÊf͎Ѩª'Zô­ Áƒ&,a`€† –(œHÑÛD a€!H”¸;-‰‰‘Ê8y…* ©H|ä!„£\¨ˆðR!žöpuHÈ*z4©¬e+¥IXt*•äøÉÓ ‰# aB\:‚ôá6ÖnukÂ(ƒq¥p V!» L˜b;tkHTML-4ee7aaa953d6cb59/tests/page2/image33000064400000000000000000000011261151224263100174300ustar00nobodynobodyGIF87ax õÿÿÿõ÷üîòúëïùãê÷ßçõÖßòÏÚðË×ïÇÔîÀÏì½Ìë¶Çé¯Âç¦ºä¢·ãž´â˜¯à—¯ß‰¤Û…¡ÚƒŸÙœØ|š×y—Öu”ÕnÓgŠÑd‡Ða…Ï]‚ÎV|ÌOwÉHqÇDoÆ>jÄ:gÃ6dÂ0_À,x @þ@“phrB¦acz@ĨtˆL‡BHx\¿à°x®D™4ù˜&QD#¼HLŸsTaHDDlnl&ˆt&$lLd‘’c   B  &%Q nCž ¨V&¼“ÇÈC¼Ë $Ξ&£&#%&ÝÝÐV Ý€Bž°ÜºÞÐEHÉö‘ÝØÎ&žÔFeòVè«(ÛLlxîˆÖAi@‚o÷2jÜȱ£G!Å A¼c`²*CB˜£Õ­PÄ0É8á“&H b|!›(x0qÁÍŦ±|…s]†" 1p„1;f*€`€ü}M`ˆ* l3ØŠˆ˜(ö¦ëXË„`eÕX¢ÀqwvV3QÀˆe ˆ$²ÀVîlðr—Þ;% r˜`ËàÓ¨Sg ;tkHTML-4ee7aaa953d6cb59/tests/page2/image34000064400000000000000000000007601151224263100174340ustar00nobodynobodyGIF87ax õÿÿÿõ÷üîòúëïùçìøãê÷ÜäôÕÞòÎÙðË×ïÇÔî¾Íë¶Çé¯Âç¬¿æ¦ºä¢·ã›²á˜¯à”¬Þ§Ü†¢ÚƒŸÙ{™×y—Öu”ÕnÓgŠÑd‡Ð`„Ï]‚ÎRyÊNvÉHqÇAlÅ>jÄ:gÃ6dÂ0_À,x @þ@“p8t,Ĥ’È()©@5P„Í¥vËíz¿Z‘D3œTB $ä¤-#%çÁ¨ÄM’Œi¤6]Ò`ƒ„…`% # &‚x ‹C B&¡Bš†§¨©B q $”I¦”Ÿ &&»ªÆÇZ  %” Dš&ÎR¾"%Ä›ÈèéêëìíC%­§»½æîýƒ 2ÀàhY (epiÛ¹z tp¦§˜¿‹KX( «D4~ØPà“'P 4IᇱeÕL|@øÈ@>2 âÀ[ ”óe$š¨ pÉ´©ÓvA;tkHTML-4ee7aaa953d6cb59/tests/page2/image35000064400000000000000000000013241151224263100174320ustar00nobodynobodyGIF87ax õÿÿÿõ÷üîòúëïùçíøãê÷àçößçõÕÞòÎÙðË×ïÇÔîÀÏì½Ìë·Çé°Âç¯Âç¬¿æ¦ºä¢·ãž´â˜¯à—¯ß§Ü†¢ÚƒŸÙœØ|š×x—Öu”ÕnÓgŠÑd‡Ða…Ï]‚ÎV|ÌOwÉHqÇDoÆ>jÄ:gÃ6dÂ0_À,x @þ@•p¨.*NaBl:ŸÐèÓs%©vËíªJêT© 6åÊHXÙ5fSå3ìD$t¨r"cTe!M$ &){e"$*)`kf*“*^¤!C m’ B #»B€!¹**ÅkCU`»£*(»*¦ºÉD¤^¦ * ð'$ ÖÊ%$Þ€€B<áPi‡TD*(œ @!¦àˆ„Â<Ç’y<×%½hroHF à¡0L€Â:` ¤¦úGCPœr& U(PÀ͆bˆOs$³jÝʵ«W—øôkV{2X@0Të‰,fµ˜z÷`Õ€!Rè´©5ù"Ày`À]„… àÏ=TÒ € Y$vQÖA, Û^\×aÄš«q‰¤{'Æ]€LTôPP……… ,uVH9ƒ«Ö”8¨I‰wG,²€‡ 3ÞŒÔÒꀰ¦ÖÖ{‚¯w‡<ô\.$E,EA “°”ƒ0ëÜ ÷ 40€ å” :a`ÊÍ©¢ÁM (jÛE(¡“uQ!WA;tkHTML-4ee7aaa953d6cb59/tests/page2/image36000064400000000000000000000006241151224263100174350ustar00nobodynobodyGIF87ax õÿÿÿõ÷üîòúëïùçíøãê÷ÜäôÒÜñÎÙðÇÔî½Ìë¯Âç¬¿æ¦ºä¢·ãž´â˜¯à—¯ß§Ü…¡ÚƒŸÙœØ{™×u”ÕkÒd‡Ð`„Ï]‚ÎOwÉHqÇDoÆ>jÄ:gÃ3bÁ0_À,x @¹@‘p(Ú$ĤrÉl:ŸÐ¨t:ì@2¢ DdÅj!”ð Á€"‘P(" Qßðx\ØB‚H]p> | [B~r‹ŒItv"{}“ƒ‰"zŽ£¤Sƒ‰‘„ƒC n¥¸¹º»¼¼§½ÀÁR§}€‘ Ÿƒ"²·ÂÖ¦•«” ƒàc‰×çÃÙ" Ùá “ ’èú»ÕûþBA;tkHTML-4ee7aaa953d6cb59/tests/page2/image37000064400000000000000000000001741151224263100174360ustar00nobodynobodyGIF87axóÿÿÿíñùÜäô ¶â—¯ßc‡ÏIsÇAlÅ0_À,x1ÉI«½8ëÍ»ÿÆ'Ždivq®lëNDp¼tm[Gáíÿ&ƒ@ À¤Sè;tkHTML-4ee7aaa953d6cb59/tests/page2/image38000064400000000000000000000202121151224263100174320ustar00nobodynobodyGIF87a'*÷ÿÿÿÿ÷÷ïÞÎ÷ïçÿ÷ï÷çÖïÞÆçÖ½÷çÎÞεçÎ¥Ö½”ÞÆœ½¥{!ÿ÷ç÷çÆïÞ½çÖµÞÎ­ÖÆ¥Î½œÆµ”ïÖ¥çÎœÞÆ”Ö½ŒÎµ„Æ­{­”cçÆ„Þ½{¥ŒZÖµsœ„Rέk”{JÆ¥c½œZœ{9”s1kR!„c!B1cJZB9)÷ïÞïçÖçΔֽ„ε{Æ­sµœc­”ZÞ½sÖµk¥ŒRέcÆ¥Z½œRŒs9µ”J­ŒB„k1Î¥J¥„9ÆœBœ{1½”9sZ!Æœ9”s)µŒ1Œk!­„)kRïÞµçÖ­ÞÎ¥ÖÆœÎ½”ƵŒ½­„µ¥{ÞÆŒçΌֽ{½¥kεsÆ­kµœZÞ½kœ„J­”R¥ŒJέZcR)Æ¥R½œJ”{9ZJ!µ”BŒs1Ö­J{c)­Œ9Ö­B¥„1RBÎ¥9œ{)½”1Æœ1”s!µŒ)J9½”)sZçÞÆïÞ­ç֥νŒÆµ„­œk¥”cÞÆ„ç΄½¥cεkÆ­cµœRÞ½c­”JÖµZ¥ŒBέRkZ)ÖµRÆ¥JέJ½œBcR!Æ¥B”{1µ”9½œ9­Œ1µ”1{c!„k!¥„)­Œ)Î¥1œ{!÷ïÖïçÎÞÖ½ÞÎœÖÆ”ç֜ν„µ¥sƵ{œŒZÞÆ{¥”ZÖ½k½¥Z{k9Æ­Z„s9µœJ­”Bœ„9¥Œ9ÖµJkZ!”{)ZJ½œ1cRŒs!µ”))!RB{cçÞ½ÞÎ”ÖÆŒ½­sν{µ¥kƵsœŒR¥”RÖ½c½¥RÆ­RŒ{9{k1½¥JµœB­”9œ„1¥Œ1έ9œ„)Æ¥1kZ”{!ZJïçÆÞÖµÖÎ­ÎÆ¥ç޵ƽ”ÞÎŒÖÆ„½­kνsƵk”„B{k)91B91)ïç½ÖÎ¥ÎÆœ½µŒ½­cJBçÞ­ÞÖ¥ÖΜ÷÷ïÿÿ÷÷÷çïïÞïïÖççÎ,'*@þ <H°`A]*ÔŰ¡Ã†åt•›H±b¹qã^`dÁ‘9vÈÙ9r—](ߤtQ«Z­Z-nż儦“iNðèDÂëRÏK+0 ÅÄ—Q\tèP£Å)NÓLP¡jšª©N®\–îȹ3§ë¦¯pà@kC¶¬5²©EÄÖ˜!·†¼Èõ’£nŽSxñú°P ,€Ïœ±â¸‹×¯c·ó¦ZÎK˜pþÅi¢É–´Md1jkÌK*/nµ?5cÏ=PöˆÂ’C>"µëµõ–1l!â_²‡ ˆ’`|†¼'!]véå×ܦoæXcMo¼Y‡#zB¢9æ<¡ú1†Å^y"ãŒ4fac߈°Å <’@‚)d&¨c!H&©¤’\4Ù$8[lQC05ŒBÃ/„"(QDÅ×ôÒËÖx≠2t"ÏÂð<WœqtJ7]CÑ%W9·ˆ£É&ŒÐ$¦Ÿ(.’C*Æ0rVzލ©Š ÅH¤ê)`¥Žt*ip€ Ç&çu5Çya…5Vzm8Òª¤þ’^z€6è…vÕ5j=ÚF$‘ÀÑ©#aÖWÈ&Vh5è^b˜m{è±á(¢8¢‡Ü’øaoàF/ƒÈ¡„8FñȺLÒŒ»lLÂÆ¼ó¯àû @ôëJ!>¢Š*A6iÃ0UŽÂ‡–]R0½ä!À™2ÈC °ùÎÆïœsÎIçÈ#×S å´@G&–̱l$­þÚª«ÆÜ)³‘¶±‰%™ÐB‡x™LµVrÈaËÑE'­ÕÒXå"GÓYíÕ&pÜÑò&™ÔrË)zÌß\©8¨†£®†šj«´ÎºÖjŒ:XÈJsž4¦Ú2‡sزtþÒEC-G–ümIàE>¸“LR ϸáL iü†D°Fd>DæŠá¹çË4âÃ2Ç”qŒǨr‚À ©…7\xcƒ ¥” ó1…–RDAÁïaæ‘=ËcqÆoL@7ÿ1"ÇYœÈ$W?ò@õÀP÷,gG Hˆ×D.¶P-Mª¡K—Äñ³QL\r HÐ?ýøÿ$ÿþA URJP.H‹88%ÑÊTê°„ÀÙíTT ÌVœ8ANÓ³ž×ÈF’!§ &ÞræHG;I„!ÙHITò†Z¼¡;~ dÿøÇ]¼á$$‰H:‚qp#Œ¤F&™‘HZÒ‘‘ldG>B‘$r&Q‰!ÿè—¼¤0‘É Uà„YÌ kXƒ2ZÑŠd”`¦ð)ªŽmd#OüÄðè&ã­ yKæòÐ1f2ÓMÎN4™÷¦æ5f4#õÚÈÍnzsÒ1Ès¹;=$"w´ˆE²É4Ò‘ñÈ:<ùÉ]€’µþ0ä.jÁ’—8 —`-‚¶¼¯ ë‰Ë]Á Í€1ˆ ¢D¡ja€øÁ€m4Ñ`¡¡2 Ä)r ‚\å%/ ÈÕ]ôˆ èA) ܃«ºÄè}ñ `2Ä iIk¾ªP-S™Îˆ¦4HjF #7¢¤z£ªB5 P}ªV±êT K¿Ð@(|ÑPp©{À6´Ñ ©LfÎÆ˜—FãÔ‘ wrCò$G<Žã ¸„ê5´Ç¦|y7 ˆ¼Ô…QÖY&[)M9Ji¦ÆVÁH­Eƒly‹!â‚«“ZˆF3ÂéHGª+š2J> *þP­;(ŠBá ØâV<‘€Ì£Àn :q±‹7¸óØ­‰<Ñ‹µBá ŒâtY¡ŠcX×e(ƒ+ÐðŠCt7Þ=Ä!€ð ¸â¼è-ÀvU˜@?âÂ0€¨°,õÎw×`«ðÌTÌs8##6ÙøFåèbHh‚4Ú [5@ƒTÈzÙ§†u³ô€0R²ÀÔ¥@5‡ÁYe T±V§oÅEC1ŠófªËmw˜ŠÓÞ78¨E>ŒˆgÕ€ˆ`¨¡WØ©¢ÔÁWm8XsÈU¨R‡JÔAhU±GeÀ5-Å-îʨÎGªQ%I†Ü $@â gX„þœÁJ°k̘D»Ð¸}½b_ü2¯z÷<°ÖŒv¥È–Üßk@l¿ýE¦òšÉÌçIïŒß4™.ìp‰LŠf2Ë4Ì`VN·t(Šâ À:<ðmèÕ&º‚â\<*< †²‚þ¹°(t`—bÀRTjç Ú2øñJ³ á¯Ä’jªEpTÐŽ 4Tu¬UçÍK€J4hQ@g8£rp~DvC÷9Vô€„àH0ˆ(¹;J5ˆ·¼kDz× ¸øÀo>0€ˆRpG¸”Äk|¢‡ÎbñŽFáHóMóXËH2‘mó›ÆÈâÇåà1ðô=þ÷hJ“Œ¤ß O•–»\U¹2ßP¼6yhSi¬9Áí8ÈzÖµæEýT “|ª$‘‰Ô'WÂÏ—À¤3©‰MœÐÊР—‡8Ò†d„#_ *<@ `8 T˜‚*Pl,ÑÐWT8šŠi̺[¬‹vǘ½˜1á8\ŒtuÞÈ.ŽñÂcÜ9âlŽ^ÍyN<~\Ú©äF4ùŽ„é‡\z]ð†~šê'¤:ÕU0 «×…@ V®‰%ÜÁnçIÏÚn•œ4¤ÜàK_t ÛçJ.’‹Mg´ØÆšÔ¦+Õ‹î?P™†b!¨A…ŒaDýÁÀ A¾ŒeVþ3€Æ«£ ¼T¤Žß«èO*RÑÿU¤n@5­«Y¹´€(¤ ì˜ÀÚêV¸blc cWÑqˆW€åÄx¡NqQIôNŒO–ǵ0 µ2¦†j’b 9P[¶‘5#|ÑP‡1Q…2õQ¡(9@!‰…‚/"#|0¢ZÇ—X`½S<(b{0Rña ©P„²Zz¡|{})ØSNd3Ò p#" ï6 [€…ƒ…Xøn^ø…^oPe%%cµ%QÐð% &pfâ p<Âá1F2w5G㔊·WH±-€+ M þ› Í¢ [C8Zðá ÿA6žU+´’ ÅÖÄ–‰š(ÂW¶'#Í—‚0HƒpR¿GSnñ§ÐS…±ì"e²[½\ÅE\Å•‹ºØ Ée&O°Üp 6"7Â#é†$¬`nÕÕ{ÖŒê0>p¨sÇÐ^}Ögðõ#[8%õEDç0‡–ü•&Ç`x‡Õ“‡gGŠ·qa·€ ™04;÷–;Ø)Úùv€E çE×L #qŽFxÜd2õP—@K°*Âæ˜ ÉJ¡Ò™ŒÀ3A“"V|:.'43¦˜¿2þ©bmX¡s´p¸?ò“kûLPÔ0Uád£e ù)œ6§ÐV¨ªa©FmèC7tÃbyƒb :8•°ªn ´ f€°`9ÌPd0 РЀ bÀ ½*<À < Ǹ$Gò#°;VùCµÃøÖo»#Zº•Lô ]:<[dJtú¯¶fkD¡zI@<×kPA4úz4&A3óY"‰ 8*‘À˜Œi6Ñv¤" t€ òS?©§kqà nàôrgzæþ؈$V oA4 VÂeø ÿFD:»³ZÂ;gD[ù;RdhVDÝ™­ žsxކŽN[q†g=G1``ø°µ\‹ö` =1ä°O-p71 ¥G?;áòƒ ©H@tP@œ€@-§°ø:4ECª¨ö®2[Æ[“Ø+ 9*Û#$²H€RwJ N@z¥·¶$«?Bq.J° áa8p ÀÐ}ÀoS€çpn÷v†v­W4<ÃDôP»C<Ä#SLß™´á McôhfµÆk–¦t„€ èNŠTy˜„AXÖþI‘t(¡tú´ˆä½%¾ŠdñÔIå[¾$à ¾)¡yMwJ©uŽ»BH€uk Bð?v;0v¤`U@€Ø€ 'LÃ4wx‡<_ÔwlâÀïìwaªLÍ`v'Å iÇÛÁgš‡~ˆxÌ;U«€aI ¸I"AOÞ›y£ÄG}Ô{BS§BÓ€?¨'?Kÿ3@«w@Z€{ÏVV+ [(Zò!’‘tQZ·‡ZNøSŽAÐT“1؇¨ƨ¡dÜ ªWÐ  Ñ}å—TnüÆI%Æ¿ PÇó í°íì°bâƒþenÒ1ÆAµÁˆÌ¼ h½&| Ø€ðÄI4à›y'¡Oú¿O§J4œBõ ¸0Pš`4TÃ,ë!®#{áPˆR(ú¡QÕ"üuŠv!|_㈮y?EQúŒs¡R¦¥{ƒòQù(T[}Ðç|Í×Ñ}pœ~o¼~ëçÆY@UQuÍpŒVcUV P÷7  ÐV‡1€Ì32±Wx%‰<ÂŒlÂØ!yáHœÄ+LÉHwÉt¶H@œ0Ê›06í©RÃÇÊ5QûøÐµƒ‘{=e(ì˲,ÑÁ¨Ê3r2(yÑ{ QÅ&¢üáþ‰5eSBƒ Å„=å Ï÷|@õ|Ÿ!#j,…6B%T2o=ÍÓ<=%S†5ð bXY€ÔVÇ© ó °†äÜV½à!Z4‡ë`uUÈБxˆLNgy'ñx'<,½™4ÉZ3ÐJ uà2¦\ ¨lX ·uzÀ3À‚ðÑžÏr ÑÒS2‚ÀçZïA¸èˆ™I â Lü5‰SBQ¸%‚XÐ(ˆ|Â÷ŸÈÒ¨Å|L¸¢ÍY "ð ƒNÒÚ®ýÚN_\ÀÚ¬=]hÔUB£€t\V]¢VVD&ü¥&S‡àj=WG_ÂxÏõþaµà+ ­g7¥<~‘ ”Ê3²(¼Â‘›ˆ‰è-×…m{(Õ{ÕX‰|8¥iUÙž`‹ºüß Á`\ð!¿¸×‚SuÚß%<2Ir<ÄCª@á×80=€áîE&p$Gâ$6 %¹ÍsŒ†øÅVã ½;`Ù&tužêèÕ·`½±Å™ ÂrÊGˆw‘Šs1 Ù+½bY4±I^AéË ‚ƒR̦˜ZxáÞP¬Š¯u ´•!Õ’’æ ß»Å‹“ý‹À•&¼e"oxPà §€Úƒ Næ–áÖU>•â5^þãe^zv^Ð訃:ÓI‚`0"ÞÒŠDmÈÃâkòw/ÞFg`z(Їå –‚£lcoYÌå§ ǦlƸŒ )˜²—Ž c›Å—j±Y’‘^ ŒR„FÈÒiZ*•åbÞŸÅä‚B(u->X"4Ù c.\Ä…‹ÏŽæ¼e dòäÜ¿0¾šŒ=@Øå ÚE”ÜÅ”örgæÎ/yö/®0Õ8±c•ñ¦0%¾•mè¥ý¦K;–ÝTézȇ‡\ëะ…e¨†r(†ÑX"À+²€žÒ—d“l˜6¡Æ—t™+lÌÒA„ÞŽH„5Õ{«ÕþZJÜ‘“µ7³i¡Ú˜ê1m±È0Å-`W´x&Êe"rÎÚ.Q@`Ï`«Ë¤Cù.Ͱôl”± ÷’/æþ Py^ë5‡n•ô5 ÑZQEE{&]„Kî`/¾ür¾:åŒVX TJ©gÜp& !”YC™4Ì€G‰¤c#)ÃØeÊ`–YW|xÖ+Â:ñD¼Ñ¢,†A+­µ¦˜ñœs(ˆ ǺèÉKu} L0Á # ÞÄ[²IÇ$Ó¥–8à{ÎKð¾S <ÕX;ÍhlInMKô,uÔûäð ¹7ëôJ,/†ËMlÉ„ZpÁZðˆã9Ùb͑ؠKhÓíZ»X6iöm“9¤ íb”vÍÊ™óþüóOû„¶ÎWdà \Q0à `Iä•dQDGªF†EÈК•¬{»ÇFq,A²]±Ek¨µ¾Ñãš+Ç8ÅÛÖжHÁ爂þnT—Ü…G{À;"˜¼«0,$@‘ Žc …±H,0°p ?’È8Òì<.ë¼ÝaH,‰%Ÿ¯ d5Œ`“ ®Ø¬K«¦è5 ÂJBm } E°Q®ö¦ö]}Þ8úÿ€G]"_*>$e„Š‹Œoe‰ejqdJkm ŽJ6suzx|{¢¦©MytªRS ³´¶·¸»¼½¾¼!;tkHTML-4ee7aaa953d6cb59/tests/page2/image5000064400000000000000000000007541151224263100173550ustar00nobodynobodyGIF87a:$ôÿÿÿõöùëîóâæíØÝçÏÕáÆÍܼÅÖ³½Ñ©´Ë ¬Å—¤Àœºƒ“´z‹®qƒ©aŒç^sTj—Kb’BZŒ8Q†0_À/^½/J?€:v 5>,:$@þ`'ŽdižhªŽWë¾p,Ïtíj`àz>€‚¦" < ÐH ‡Ð (†åR0œxL.›Ïè4ÚÂn»ßð¸|No¯îø,$@{à$Ž$) â8Œ’FA Hm#PÃ,Éíç W-@,¥äÈW˵z̦NˆX¯X¬rË%ÝbŒ‡Ž•î Q'5=E3Ô£|N'vïø|+mQ Nde‡n?ƒ‰S e8c‹7j”6–‘pPžŸŸu¢£¤¦§¨¨!;tkHTML-4ee7aaa953d6cb59/tests/page2/image7000064400000000000000000000010471151224263100173530ustar00nobodynobodyGIF87aE$ôÿÿÿëîóâæíØÝçÏÕáÆÍܼÅÖ³½Ñ©´Ë ¬Å—¤Àœºƒ“´z‹®qƒ©h{£aŒç^sTj—Kb’BZŒ8Q†0_À/^½/J,X±:v 5>,E$@þ`'Ždižhª®cv¹W,Ïtmßxžk¼& =  Y$B`8h € @I@DÃ0/Ò8(8ŠÃì$¹lßð¸|N¯Ûy–¼~Ïïûÿ€‚z,…†‡‡wŠ‹Œ‹ ,<$@þ 'Ždižhª–YëfW,Ïtmßø½íH½ß¦ì$À IØøvA:…Íp`(¼´zÍn»ßðeN¯Ûïø¼~o_ùÿ€*qƒ„…o>@<ZKHU;ˆX TXS L >j©ª«¬­®¯°±¬´µ¶·¸†»¼ƒ>T ½Ã…>  HJ“BS‘‘XT\E_bT Äæçèén|ìíîïðñòu¹õö÷øùúûüºêÿª°‰“Àt”")«À † ,m€‘ ¢1˜TQYÅå"lY ¬ wÙ0 4¦p¡4Ì™iB} R Í ‚ 0‚,8$@þ 'ŽdižhªzY{½p,Ïtm×[¾€Bé À àØ À$`l‡°ØP‚‚aS ?B`8èÎè´zÍn³-ð¸|N¯ÛïxËjÏï›Ü€‚m ?F ?A9B9SU‹N] h©ª«¬­®¯°±~´µ¶·¸'ƒ»¼€X]½Ã‚ •§AŠH? Ì=˜^g]Ë”ËmÄãäå½yèéêëìíê¹ðñòóôõööæùúûƒÆ “øã1 C( A˜p† ByPaA³ þ:HhqZЬ™° €GÌr€¨Fe¢ bXV IG—3&°2£IAx4ÈQ@[Z²ÉìâMØ$YvRÑ2aA60Ùò$Ê¥–—РJžüȶ­>pãÊK·®Ý»x9¸ÛË·¯ß¿€ûvL¸°áÈ+^Ü!;tkHTML-4ee7aaa953d6cb59/tests/page2/index.html000064400000000000000000001002631151224263100202540ustar00nobodynobody Tcl Resource Center
    Scriptics
    Tcl/Tk
    Scripting Solutions for eBusiness Integration
    Products Customers Partners Services Tcl Resources Company
    Software
    Tcl/Tk Core
    Applications
    Extensions
    Patches
    Tcl & Java
    Tcl/Tk Ports
    Tools
    Documentation
    Community
    What's New
    Add URL
    Keyword Search
    Index
    Resource
     

    Tcl Resource Center

    Top>Software Central>Extensions>Tk Widgets
    Viewed by name (By date)

    Tk is a toolkit for building graphical user interfaces with Tcl. Your Tcl/Tk scripts run on UNIX, Windows, and Macintosh.

      BLT 8.0 Unofficial zip and DLL
      This is a compiled version of BLT 8.0 "unofficial" for the Windows platform. Edit (September 24, 1999 06:31)
      BLT 8.0p2 Unofficial tar file
      This is a contributed patch to make BLT compatible with Tcl/Tk 8.0p2. While still "unofficial", it is widely used. Make sure you get the 8.0p2 version because the 8.0 version does not compile under windows. There is also a 2.3-8.1 version that has been patched to work with 8.1. README file. Edit (August 30, 1999 06:38)
      BLT Home Page
      Author George Howlett, Version 2.3, Works with Tk 4.1 through Tk 8.1
      Download, BLT2.3.tar.gz, BLT2.4h.tar.gz, BLT2.4i.tar.gz, blt2.4i-for-8.0.exe, blt2.4i-for-8.1.exe
      BLT is a set of widgets for Tk, including a graph widget, bar chart, drag&drop, a simple command tracer, and much more. The 2.4 release, which is still under development, works with 8.0 or higher. There are also an "unofficial" release for 8.0p2 and 8.1a2 that were not done by the author. Edit (October 26, 1999 09:43)
      BWidget
      A set of native Tk 8.x Widgets using Tcl8.x namespaces. The ToolKit is available under Unix/X11 and Windows. The BWidget(s) have a professional look&feel as in other well known Toolkits (Tix or Incr Widget) but the concept is radically different because everything is native so no platform compilation, no compiled extension library are needed. The code is 100 Pure Tcl/Tk. More 30 components : Notebook, PageManager, Tree, PanedWindow, ButtonBox, ScrollView, ComboBox, SpinBox, ListBox, SelectFont, SelectColor, ProgressBare ... Edit (September 06, 1999 09:58)
      Dash Patch for Tk
      This patch has many enhancements to the Tk and its canvas widget, including dashed lines, smoothed polygons, and performance enhancements. Edit (November 21, 1999 06:33)
      Embedded Tk (et)
      Author Richard Hipp, Version 8.0b5, Works with Tk 4.0, 4.1, 4.2, 8.0
      Download: et80b5.tar.gz
      Embedded Tk or ``ET'' is tool for making stand-alone executables out of a mixture of C or C++ and Tcl/Tk. Using ET you can invoke a short Tcl/Tk script in the middle of a C routine, or you can invoke a C routine in the middle of a Tcl/Tk script. ET also bundles external Tcl/Tk scripts (including the standard Tcl/Tk startup scripts) into the executable so that the executable can be run on another binary-compatible computer that doesn't have Tcl/Tk installed. Edit (August 19, 1999 15:35)
      Enhanced Tk Console (TkCon)
      Author Jeff Hobbs, Version 1.3, Works with Tk 4.1 through Tk 8.1
      Download: tkcon.tar.gz
      TkCon is a replacement for the standard console that comes with Tk (on Windows/Mac, but also works on Unix). The console itself provides many more features than the standard console. Edit (August 23, 1999 12:06)
      Frontier-Tk ScriptMeridian project
      This project seeks to integrate the Tk toolkit with the Frontier scripting language. Edit (August 19, 1999 15:36)
      Img image format extension
      This package enhances Tk, adding support for many other Image formats: BMP, XBM, XPM, GIF (with transparency), PNG, JPEG, TIFF and postscript. This is implemented as a shared library that can be dynamically loaded into Tcl/Tk. Edit (November 21, 1999 06:35)
      mclistbox - a multi-column listbox widget
      mclistbox is a multi-column listbox that is written in pure tcl and runs on all platforms that support tcl/tk 8.0 or higher. This widget requires no other extensions; it is completely standalone. Edit (August 19, 1999 15:37)
      MFC views C++ class for embedding Tk
      The idea of embedding Tk in MFC windows always seemed very enticing but information was sparse and contradictory - on a scale between "very easy" and "not yet possible". The only thing for it was to have a go and lo, it wasn't that hard after all. CTkView is a C++ class which can be used in MFC SDI or MDI applications. An instance of CTkView hosts an embedded Tk toplevel widget and performs some management chores for the widget so that it can size, update and react correctly to Windows events. Edit (August 19, 1999 15:38)
      Pad++
      Author Ben Bederson et al, Version 0.9p1, Works with 8.0
      Download: download.html
      Pad++ is a Tk widget that provides a Zoomable User Interface (ZUI) that supports real-time interactive zoomable graphics in a fashion similar to the Tk Canvas widget. Pad++ supports tens of thousands of objects which include text, images, graphics, portals, lenses, simple html (and more), including transparency and rotation. Edit (August 19, 1999 15:39)
      Progressbar
      Progressbar is a megawidget written in pure tcl (ie: no compiling required - runs on all platforms Macintosh, Unix, Windows). Its primary purpose is to show the progress of any action in percent. Edit (January 24, 2000 09:19)
      scwoop (Simple Composite Widget Object Oriented Package)
      Scwoop is a composite widget (also known as mega widget) extension to the great Tk widget library. Scwoop is entirely written in Tcl using the stooop (Simple Tcl Only Object Oriented Programming) extension. Edit (January 09, 2000 02:10)
      Supertext - tk text widget with unlimited undo
      Author Bryan Oakley, Version 1.0b1, Works with Tcl 8.0
      Download: supertext.tcl
      Supertext is a package that provides a tk text widget with full undo and the ability to execute procedures both before and after a text widget command has been processed. Supertext may be used as-is, or for the brave it may be used in place of the standard text widget. Edit (August 23, 1999 12:06)
      Tabbed Notebook Widget
      Author Richard Hipp, Version 1.0, Works with Tk 4.1 or later.
      Download: notebook.tcl
      This implements a tabbed notebook using a canvas widget and embedded frames. This is pure Tcl code - not a C extension. Edit (August 23, 1999 12:08)
      Tcl GD - graphics
      Author John Ellson and Spencer Thomas, Version 2.0, Works with 8.0 and higher
      Download: Gdtclft2.0.tar.gz
      Thomas Boutell's Gd package provides a convenient way to generate PNG images with a C program. If you prefer Tcl for CGI applications, you'll want the TCL GD extension. Edit (August 19, 1999 14:52)
      The Meta-GUI Tools
      The Meta-GUI tools provide a framework for quickly building full GUI applications. The GUI is rendered by a run-time engine based on a hierarchical set of definitions you provide. At the bottom of the hierarchy are abstract data types such as length, angle, string, etc., and these are used to progressively build up frames, dialogs, toolbars, menus, and operations. Edit (August 23, 1999 12:10)
      Tkpiechart Home Page
      Tkpiechart is a Tcl-only extension that allows the programmer to create and dynamically update 2D or 3D pie charts in a Tcl/Tk application. This uses the stooop package and builds pie charts on a Tk canvas. Edit (January 09, 2000 02:12)
      TkPrint
      TkPrint is an extension that allows you to print from a Tk widget. Edit (October 11, 1999 09:58)
      TkTable Home Page
      The TkTable widget. The table command creates a 2-dimensional grid of cells. The table can use a Tcl array variable or Tcl command for data storage and retrieval. Edit (November 18, 1999 09:25)
      TkTextMatrix (spreadsheet)
      Author John Arthur Tucker, Version 4.1, Works with Tk 4.1
      Download: download.htm, textmatrix4.1.tar.gz
      A Tcl/Tk spreadsheet widget, TkTextmatrix, which is implemented in C++ and is basically a Tk Canvas widget plus extra behavior for manipulating rows and columns of cell items many times faster than with a plain Tk Canvas. It actually inserts text nearly as fast as the Tk Text widget. If you work with or are interested in creating your own Tcl/Tk widgets in C++, you might want to take a look at the C++ widget library included with this distribution. Edit (August 23, 1999 12:14)
      ToGL - a Tk Open GL widget
      Togl is a Tk widget for OpenGL rendering. Togl is based on OGLTK, originally written by Benjamin Bederson at the University of New Mexico (who has since moved to the University of Maryland). Togl adds the new features:
      • color-index mode support including color allocation functions
      • support for requesting stencil, accumulation, alpha buffers, etc
      • multiple OpenGL drawing widgets
      • OpenGL extension testing from Tcl
      • simple, portable font support
      • overlay plane support
      Togl allows one to create and manage a special Tk/OpenGL widget with Tcl and render into it with a C program. That is, a typical Togl program will have Tcl code for managing the user interface and a C program for computations and OpenGL rendering. Edit (August 23, 1999 12:14)
      Tree Widget
      This implements a tree display in a canvas widget. It is similar in layout to that of the Windows explorer file viewer. This is pure Tcl code - not a C extension. Edit (September 29, 1999 14:37)
      Windows Extensions for Tcl/Tk (Michael Schwartz)
      This site has pointers to several extensions specific to the Windows platform. The extensions provide printing, a MAPI interface to send email, and an interface to manipulate .INI files, among other things. Edit (October 07, 1999 10:50)
      [incr Widgets] Home Page
      [incr Widgets] is a set of megawidgets (combo boxes, etc.) that are upon the [incr Tcl] object system and the [incr Tk] megawidget framework. This comes bundled with the [incr Tcl] distributions. Edit (September 05, 1999 16:08)
      combobox
      Author Bryan Oakley, Version 1.03, Works with 8.x
      Download: combobox.tcl
      combobox is a pure-tcl implementation of a combobox widget. It is entirely self contained and does not require any other OO or megawidget extension. It supports both editable and non-editable entries, and provides the ability to call a procedure anytime the value of the combobox changes. Edit (August 23, 1999 12:15)
      Rnotebook
      Author Daniel Roche, Version 1.0, Works with 8.0 or higher
      Download: index.html
      This implements a resizeable notebook widget in pure tcl/tk Edit (August 19, 1999 15:39)
      saMDI v1.0a1 Multi-Document Interface Extension
      A multi-document interface (MDI) extension for TCL/Tk 8.0. This is a common interface format in Microsoft Windows that lets a parent window contain multiple child windows. In effect you get a window manager inside a window! Uses and includes the STOOOP object-oriented extension by Jean-Luc Fontaine. saMDI v1.0a1 GPL Copyright 1998 Sam Tregar. Edit (August 23, 1999 12:07)
      Tix Support Site
      Author Ioi Lam, (adopted by Gregg Squires), Version 4.1, Works with Tcl 7.4 through Tcl 8.0
      Download, Tix4.1.0.006.tar.gz, Tix41p6.zip, win41p6bin.zip
      Tix has found a new home!
      Tix provides over 40 new Tk including the combo box, file selection dialogs, paned widget, notebook, hierarchical list, directory tree, and more. Edit (August 23, 1999 12:11)
      Tk Tree Widget (C++)
      Tk Tree widget for Tcl8.0.3. This version contains (optional) support for \[incr Tcl\] and \[incr Tk\] version 3.0.
      With the tree widget, you can display a tree in a Tk canvas. The nodes can be made up of any number of canvas items or even other Tk widgets. You create the objects that make up a node and the line that connects it to its parent and pass them to the tree widget. After this the tree widget manages the positions of the nodes and end points of the tree lines. Operations are available for inserting, moving and removing nodes and subtrees and for querrying the position of a node in the tree. The tree can be displayed horizontally or vertically. Edit (August 25, 1999 03:14)
      widget, simple megawidget package
      Author Jeffrey Hobbs, Version 0.9, Works with Tcl/Tk 8.0 or higher
      Download: widget-0.9.tar.gz
      This is a package of megawidgets (i.e., compound widgets) that work almost exactly like Tk widgets. You can also build your own new megawidgets. Includes: combobox, hierarchy, console, progressbar, tabnotebook, validating entry, pane geometry manager, baloon help. Edit (August 23, 1999 12:16)


      Top
      Home | Products | Customers | Partners | Services | Tcl Resources | Company
      Search | Site Map | Feedback | Contact Us | info@scriptics.com
      © 1998-2000 Scriptics Corporation. All rights reserved. Legal Notice | Privacy Statement
      tkHTML-4ee7aaa953d6cb59/tests/page3000075500000000000000000000000001151224263100161775ustar00nobodynobodytkHTML-4ee7aaa953d6cb59/tests/page3/image1000064400000000000000000000001611151224263100173420ustar00nobodynobodyGIF89aðÿÿÿ!ù,HŒ©Ëœ\ÎûªÅMkNyˆˆ™™'¨šXÛN0,Í4cÏa'|~øSBã†"Š’$ÊI‚²zI)Çú¢>µQîTÅT®;tkHTML-4ee7aaa953d6cb59/tests/page3/image10000064400000000000000000000117401151224263100174270ustar00nobodynobodyGIF87aä÷õ0@0666>>>>R>H`HLdLVrVZvZ`€`d„dfvfhˆhllln’nr–r||||¤|€€€€ˆ€‚š‚†²†À”œ”–––˜˜˜œ¬œžžž¢¢¢¬¬¬°°°²²²¶¾¶¸¸¸ººº¼¼¼ÂÂÂÈÈÈÊÊÊÐÐÐÒÒÒØØØÚÚÚàààèèèðððøøø,ä÷þ@‹pH´$ŠÈ¤rÉl:ŸÐ¨tJ­Z‰ÇeÁÂèz¿‰¯xL.›Ïè´zÍn»ßðxØà" ø<¾ ïûÿ€‚ƒ„…†‡ˆ‰Š‹Œ| u –— ˜›œžŸ ¡¢£¤¥¦§¨©¡•œšœ‘\²csq¹º¹]½_jÀ^»ÇÈbµ˜ ¸_µ³“¶bÐÉØq½ÛÝÝ à 'åÂá½Æ ãéçÙò¹µÕ“ÏdÒ’Ò˜øóÙˆAA ïÀëu‚††'šK·°`À‹jêEûÇ ‚?jÓ¤ÐãÉ1ï žCHN¡±†ã®TØÅet'sF³´×þÈ.úhÙórM'F—*#v#‚eAq#6çm©SœFsjôb $WYû†v)šµìœͪA^Ù†tð'£»xóš€gÁ½€"@×]?À&HPà‚ãÇ#KžL¹²å˘3kÞ̹³çÏ 1/Þ2ɋӨS«^ͺµë×°cËžM»¶íÛ¸s¿Þ––‹Àƒ N¼¸ñãÈ“+_μ¹óçУKG.¡wé騳kßν»wíÕCþþN¾¼ùóèɇß7^8‡ðß;çÀ!Eá÷ÓëßÏ_ÿzßÄÁ—}Ø—_r˜ }öçàƒ6÷ßuÃ5 | €aƒÆþY˜á†^Èa„$–á„´œ€ð…Ø@}Þç"bhâ8ò‡¢ŠÀ±˜!#r I£…Bæ¨ä’ßí¸Ÿ€LF)åtNêGß”Xf¹\•Zvéåƒ\~)æ˜åíØÁ™h¦©æšl¶éæ›pÆ)çœtÖiçxæù&Š&èé矀*è „jd&ªhw‡.êè£Ð5 餔'i¥˜Vz)p+¸àé§ †*ꨠ~0d¦¨z·i§+”Gc -*묡š +­¸æª«­±êꫬ¼þ*ì§¶Z’p§@ -˜G#³J>Û,ÒZY ±û Ë‚²<~@·&~û ¸û][ܦþÉšG®ºà–¸.ï¢g.qènË®¼í’¯~ûª{\½¾è^}÷x\¿Ý!¬o¾÷–ûï±Á¥Û£Œ¦`$ï18 |Po~/žJÜ•Èí+à•—ÉÁ±Ì²qï¾ߊ-§LsË"{ÌãÌø©ŒáËÅÍ;Àø ¹a‚)¸øcˆ/Ç{í†ö1XpÆW,\¼B2$}9{\ß…UCý³À6ïû4ÅÀ)øbÈ2k¤Õ:W`Ö!c\uÚ¯M0‡B G4p\ψt-&= ÆWóx­Ò€Ýb&maÓŠ{løÄx{,¤†Öxaç…3}ªÙØò…†·ø¡ˆf¸ÜR¬àþå’¹èW?œmÄö~¡Fnýù†Ÿ™dܹKŽaÆG®ú}4Ž^y—ÿž†{x;ˆÊ×x¸ôÄ©¹}G^1á6Fÿzîð}n¸û™×è½ú–cK‹¶Ø¡¾âª_<àïjûõÖw:Èý/k0jÚ<¼ß}ˆD^î¬g.:PFH¢Ï6þ  |Àƒ`üÚ79#%ï\ŽÄ¢s·ýá‹I ƒŽÍ‚Æ0ïô-8#O µ³ÃqÕp>]“Û¹sCàäÐ[CœN´D&‘‡º»ïÎ'F§‰ð²âv°˜"¦àˆÞéÕ°ÆHÆ2šñŒhL£§8ÆT¹1G¨Ãa þS°Â7ÚñF)kã÷è <αŽ| $ü¸;öNˆÔ!¥hÈD6G7TM«Ô¨‚ò,røsärLIH¢ )Тq$`ÉéQ“Ã¥wÎÊí’<—DÔQ™Uv‡•¶Î+¿ËLæÈ`fÁˆ8‘­•²Q1c§ÌéàrdëÙqvé^ÎG?ã˜Ô ½ºqljCBœãö¦·à´ëdk»Ï‘LÞI8Ï Xêd¤1âP³;ÖldŽ@'"ŒÉ/>òéœòZôª´mn{(pÎI±£ƒÆá$j> OPv+¡ Òž=Ké·?²D@BÒòº%÷n¤æbÜ@þhΡM™ ‚hq\ & €2ñÄÁ†¾ÂÒ”ýeÁwÐ~ZÏ‚?ò_JcgA~p¡.aáÎg± §Oj"AE‘©Ó¤Q0ƒ>å%P IÇb3?^LO.·“SåÌ8÷äN>Ë%’µS­&jkrŽ WŽÊ‘¬€¤e*ójQWúÕˆAìqhZ¨:Ù”«Ø‰ëvæXÅ^µ±vÒª $ÀÙÎzö³ ýìa¿˜XËš6:”5ëiW£ŽVµ¬m2]ËHºÊö¶Qýkm+kÙNvr’i¬äOi‹ÉkÆV¢¾½ E×Éj'µ¸envô*çfº·•.v¨ëæo¬»…­vÚ6þœ—½Ì`ͬÐtº9¤!BϪҡ.ʤ9ÊÑžòº ›ØÐèµPmakhԨƢ¿W æ"áZ¸Ö´ §…•§øìf0﮼ÅÕ',Y÷¸ =Õ@þ4œB%g4åÈh …\è´⪶T9„ñ&UCQC¶GÃ[žFuißÒŠ•™ zÛÄ,bË‘Ð{ICqḇ>…6HÁ’“±r‹¦ÇÚø¢;}QOy<\Ýfضå`éž:©~˜iNÝÝwÔy|7†™~符I«Wž-Æ.V.ÿØË²Ô0¥¤–í:3ÂËyk ,,ìbJÑÎ1t|­¾.ºÇ¯.aãÜ]þL‡7º˜¥ÓcµËhÔb8Ð`Ž­C'͆öհ欧¿Ì[ÜÆÖѶÎ5®sÛ]óZ¶¾>mr! \4 ÷ψÍtv‡›å¶ËÉþtv7MêY£ºÖ‚•tt¸ RËðÔ¾D¤›s 9Wja¾ækùFófõ…6i•¢“jc¯ÆL—¹±×kÚäš?8â|Ý®b!ƒr¼U,ÏÓ«ò k5Ám\YÄGK‹ z9•¦tãè+i{£ãåÙnÜ ¥ñM©‹Q‹Hâø¤¸ -Î䕹æ#,yöPšqê½ØgnÞئ\Ó•Ss3Ú²p¼ýœ`§yJµ9Y?’þ¶ÎB;ï_ó¶F;N#]Ì{–iqV}&<³œž|6¡Ÿ'NÜk‹7Uil‰¸í³x#{ÞÒä]åN"ºCÓîlt¸Y«mèø]BÖüj©Ìê7úÙw¿¯`ÉÞø6¹:Ö˜÷lâ+þë[Ë<Õ÷|ÛúÓ:½ôŠ=½b™›bŸñØ6­ßžmÖÛÆÙàÙüÌOmÈÇï³×ôÜ^]݃^K2ÛØq\ß ªnUþ*‰ÏnŸ>æ£ç|–¸NpÆ.ßzÛ·À ¾œ?Ÿ9 ϳ„ÏWϵc_ðÚÇRHK'3’ƒB/³‹¡Ÿœw}Ê*×p’cý3CLçª%êô3sþR7‡PÏc}^;œóµTt(arr#r€äöyØÆ$RäU³A DÆZ”'…Y•›•y^h|!ˆzŽ”ƒb˜HdX†‚t†hÈGj˜H¶w®gF°÷~²çvÑõ†´{Ù„­»wZ;è=¸%`8„¨ˆÍ1ˆÊÁ‡D¢„}Ä6ËaWÍÄ2<30ô8çç^ÒwKÔ÷nsr刃„àT`ÜTnì%ì45áç_ãG; 66Í7éwvþGa?Xˆ29,¦bGTÕL¼X7 ø*q‹úÇÈÅ5Ær¸:¨‹ý8ÜÃdPƒt˜³1¶ƒ7ev-BödåeˆŒ×Vf‹I—KGÔrA…Ófa‡ŠRµ2Mõ*ýcfpÖ‚ Tgk"ƒqFƒG¢víh…ôÆGq'ˆÈЍpyWxG{§E‰AĈ$'ŠÇU‘‘åŽÇ¥…nB…{è‘X’nry^ˆy$¹†´Ô†,ùF.ù’©rzt62C—„–f"Âq2™NWRS×<-×aF¢biÆ_ A=©‹$pgVã€G•ˆ£=<S¬"¨Ó”&¹•\)(Z]þ°#0–&ð?ö• b;î“q&•>R#Wbc9—tY—vy—x™—z¹—|Ù—~ù—€É—Û–#Чñ`&pŠi:þÖ#‡o$“nßÄ)xX™–y™°#0˜JØ›5¹”]♜™}Dš¢¹G¨I˜†˜šŽ²šù™Â´Y›¶y›¸™›º¹›¼Ù›¾ù›ÀœÂ9œÄYœ´9°išt…šÂ‘%ðœÐÒ9ÔYÖyؙڹÜÙÞùàù`Á‘œ~¸œ² F깞ìÙžîIFÈù™¬9PE´"ú¹Ÿü9*ñYšå™,̉ž êøéþ)j €ŸÚŸ¡:Fÿ©p3 ÀQŸ"jŸ.À¡UdŸ0Z¢&z¢ŸR¡óÙœ! ¢ú¡ú¡ú¡(Z£6ºŸ*›•øÙ£øÙ =Š ê¡7Z¤FzF9ªœzžz¤Nú¤8*äY‡øƒ¡)àPš¥ZªFI Ûb¥®™)S |v¦aZ)cz¡Lz¦˜’¦Ae¦bÂz+°¬WV˜¹-ÃÖ¥T:Epú%ÍèIÀ†™\JwZ¨Š…*¥ò©£"ig†ÌAJ ÙŽÕÆ¨º§§¹¦d©Úš„X©Í5ÎqOnši}ê%ž*©¡º”ê{8Õ¨Jþú¥œ:&àš ù©Ä!@Ïñªå…«è†8ÓúSޣЩú¦µ*&§uiG‘jVûuA&hƒq¶5/â?.Ô@9ã«]vi­Èº¢‹Ò¬BgRЪ«#Cah@<Ö.oC• óq{Va9< ÈŽÇ:ž²ê¥± ªRÒ-@RUöW7­áb©`ßJ¬+%9©ƒ9%Ô —9åꨎ.Uc7G>ÈÉ®îqoõ”.3³6‚‰0"™o®8C>>³zJ¦Uº¬~Ú‰H²¹'ª}õDŠfªÿª©æ)°Q²ªHK¤Ú2K%7«¦K»$Jë´MËO[|;«þû¨ƒbSÎ8(”ª…c (D›©8˧:ë%Y¨'$°…’mÛXr+(Q«¬S˦ZrªŸ–ªz«(||~û·d¸eº¶„[¸E›¶›š·‰%†›³Žû¸K¹j»)™¹š»¹œÛ¹žû¹ ºœ»¸ª[zº¨ëžh …”»(1Ùº^òº°«%²;»Xrz &²·"¨P¶kNW°%¦e9pÜÊ5ýç÷»“¥‘]õ^r"4b;RƼßŵàY ô–E†–Ó ;VW¢[¾æ{¾è›¾eI˜Ÿb/tæ>úºuÇA‹³­¡”ºøÛŸ*°ºxÛ ‰½úa¹Kn|þ#|´,&¼¤“›Àý±À´º£0Á\Á|ÁœÁ¼ÁÜÁüÁ Â"<Â$ìw‹ªkšžù»Â,Ì#͙ܵ -<Ã[zÂ}›ÂDJÃ:|¤6,¸8좺¡9¼ÃD¥þÊ¿(¼£-£ž2ÄEüÄïÙÇ«Ä2£@ÊÄPœÅí)Å’KŸ£"ÃZÆìÉÅj»£b|ÆüIÆ,'p§nüÆp|§jŒÀ<š¤Û¿u¼·wœÄy¬ÇH|à œ,ÀŸ&0ÈOZÈêYI”4Ç l"¬ºm>‹# kX—zÄÉÊÇ%òȆÉÌÉÅWÉð´Ç€ìÈŒ“¬$§<’ Üµæ!€þ”^‡XïEr–X^•H³Æ‘Êy30+ó°뉺›‹[ °ƒ‹€´@„6LÜä|9£ËÌtoìÇ5óJãM ;²Ç;¶@)«gÑŒ¯Ãl´œÉfÅ4DÕ:Ñ3‚×ëÌüDPQ™qné@ßË“uÌ“sRžc±Js/\Ìç‘ÍKöÎÐs°ëZG$È:ÃaÒ»Û¨®ëÌÉjƒÏü´z¶Jׯ¡üÇ>\ÊÓaÏj6@Õf/XÏÅ"DE‚$¿}”!Ñ RòÓ<Ý,a_EÍÊK"šÌƒž<|=]_B Lg{É£LÎèá̄ԹøDGÈÈLÊIýÓLÈÔ5=’þá̸tÌÓËT!JÝi«üψ›,€¹éûYŠÖiý¹k}¾\h¾P Ã}<%dÝÕuýw×v-ÊÍ×R²×€Í$‚=بìׇûI]¹ØŒÝØ_‹Ø9˜’=Ù”]Ù–}٘ٹ¿F|$Ç Ú¢™­BH£Az†Í$)3y—ÚSR»®­HŸ'uð\Û¶}Û¸Ûº½Û¼ÝÛ¾ýÛÀܼ ŒZí|Â}ÜÈÜʽÜÌÝÜ»=4sÛd²)Ò=&Ô]Ý_rÝØÝ%Öžð ªÞâ=Þä]Þæ}Þ¤Þ› ’`d±ðßòÍïÝPßú½ßø½ßþýßà>à^à~àžà ¾à Îàý-àA;tkHTML-4ee7aaa953d6cb59/tests/page3/image11000064400000000000000000000106051151224263100174270ustar00nobodynobodyGIF87aä÷õ0@0666>>>>R>H`HLdLVrVZvZ`€`d„dfvfhˆhllln’nr–r||||¤|€€€€ˆ€‚š‚†²†À”œ”–––˜˜˜œ¬œžžž   ¢¢¢¬¬¬®®®°°°²²²¶¾¶¸¸¸ººº¼¼¼¾¾¾ÀÀÀÂÂÂÈÈÈÊÊÊÌÌÌÎÎÎÐÐÐÒÒÒØØØÚÚÚÜÜÜàààèèèêêêðððøøø,ä÷þÀ‹pH¼$ŠÈ¤rÉl:ŸÐ¨tJ­Z‰ÇeáÂèz¿‰¯xL.›Ïè´zÍn»ßðxØà" ø<¾ ïûÿ€‚ƒ„…†‡ˆ‰Š‹Œ| u –— ˜›œžŸ ¡¢£¤¥¦§¨©¡•œšœ‘\²csq¹º¹]½_jÀ^»ÇÈbµ˜ ¸_µ³“¶bÐÉØq½ÛÝÝ## à .åÂá½Æ ãéçÙò¹µÕ“ÏdÒ’Ò˜øóÙˆAÁ ïÀëå‚݆†.šK·°`À‹jêEûÇ ‚?jÓ¤ÐãÉ1ï žCHN¡±†ã®TØÅet'sF³´×þÈ.úhÙórM'F—*#v#8‚eAq#6çm©SœFsjôb $WYû†v)šµìœͪA^Ù†tð'£»xóš€gÁ½€"@×]?À&HPƒãÇ#KžL¹²å˘3kÞ̹³çÏ 1/Þ2éÓ¨S«^ͺµë×°cËžM»¶íÛ¸s¿æ–Ö Àƒ N¼¸ñãÈ“+_μ¹óçУKG.¡wé騳kßν»wíÕCþþN¾¼ùóèɇß7^¸‡ðß;÷àFá÷ÓëßÏ_ÿzßÄÁ}Ø—_r˜ }öçàƒ6÷ßuÃ5 | €aƒÆþY˜á†^Èa„$–á„´œ€ð…Ø@}Þç¢bhâ8ò‡¢ŠÀ±˜¡#r I£…Bæ¨ä’ßí¸Ÿ€LF)åtNêGß”Xf¹\•Zvéåƒ\~)æ˜åíøÁ™h¦©æšl¶éæ›pÆ)çœtÖiçxæù&Š+èé矀*è „jd&ªhw‡.êè£Ð5 餔'i¥˜Vzi¦QÚpç †*ꨤ– ªCš¸) 3˜ê꫟¢ ƒ§°Ö:ª¬´Úªë®§z`ƒ ýÑ8+¯ÄÞ «¥! ×ê åÑø«yΛ#<êÀ³é ‹ì>ÂvÕz.“ã:X®µþÇmê­yç–×.ŽïZ®»é&ܺîÎË]¼&ò‹ž¿ä¸--ÝÒð­¾Ûa»ïÅ·bp ×à•Å),n½ÜÞk0~/ºWß}#÷n~/¦JÅ"W+à•PvÊ/ sÅÕ œ`p ¾Xrà ¤ÃÜ1~c83q§îÆ=Ê´‘¼×sÏ-÷®Í6–Ì¢ÔR-Ü»B2$}&]ß…]oh ÎsoÎB|! 9kèâ†aÍca—u×V7Ͷ×8cL°Æ ¹áÍwG"ÌW[ía†h·d†t[ùÞ…' eÒt iwæX£éš§ú¶×žûŒ9Ð5ªM£þêœÛhº}tãüâé™ç]øÀ“ìñ‘•;;æήwÐ’c˜üåu¯õò_?,0Šk¨»ˆ¨;OzNsÍBÜ…B¢Ÿ ’ô¡ŸäøÌÃwáíóÿ~ºôª<ârknäØóÃÛŒD=Ý}È|@²PÎЇ=Ú {sk Å”3¥O}5b áǪçjr]ú,#eÐï ðÅ?é8fÿB„,6Ÿ²!M†ÝÝp–†ÀÝ0†äÂáwh¸/ý±8ø ˜§CÄþ41‡KÔŽ…ÃCvE1:OÜO·+bgŠÁQW®ŠEÆ2šñŒ¼zÐѨ+©ëÌâ”þ§4·0Ú ‰L›£•Tµ*îñ7êãaD@òA‚ÌÉHD6ÈŒ$zy¸E G$Ȥ&7ÉÉNzò“  ¥(GIÊRšò”¨L%*aà¦T葃,$ B ‚ZÚò–¸Ì¥.wÉË^úò—À ¦0‡IÌb “Yè€2- Ì€ „ƒ$a@°ñšØÌ¦6·iFHà4AÀ)hRr– N5oP‚Pu‘Tí U ÞÉÍzÚóžõô&9_`rš–Š$$4«9€Ð]lg÷ÁNÝòª)²Ä)Þo œ ™Í|«²'ÍnŽSÔ›5U R}èn›œ¥Þl´€ãU–3úÞ/‡ù7kÇt ¬õn9ÎsÞÝoÊœæ(zÁi]r¢ßÓ¢<÷yÒm¾q§þ»Ô¢-xÁ7§>r{7ÝêGÝ: @Ðv]è_»6õºWðõ¯g¿¹ tC÷ºÛýîxÏ{n`°‚ÖıÜÓ”¤à½³ô\ogzG@ï-Æ;¾îä)|!µC$ž0Hìå3ÿøÎÛóß‘<4)?úìH óeBýOúˆ—™ôMR}콘(ÖÞõ´†½wNOû-É^¶ïŽè¿3y0V¬8¼'Ž @‚§Â1 ¨ó{ã,¿ùÄY–ègÎŽö±/é;'øĽáuÿ5öiPtAŸp’?ów`ü+¸?óñ¿âÐ9ö‡ß×|&ùGv&ÐÜÞÇþË÷€Ø|Û7XáG}­Gf¹—Å·8Š=õFÿöw} h‚Òg‚þW}ÅQ‚)(Ì×}Ý·Ò}Þ'ƒ0‚ (ƒ ¨ƒ'؃:¨}Ó§è·Ãç¸!Gâ7VS6#Ò'„˜QHƒ~+ˆCQ¸}/˜ƒÓgƒùç…÷wƒÍ'…;hƒ>¸ƒi¸…Cˆ·§ëÇ£·3b4ùq4OÈwæç…9ȇ}¸‡Ã‘‡Ù·‡€è…Î~Ó~÷w|h~Ó÷ˆà‰ˆ(‰Î÷ˆmè†Â§~“'‡³—z½Ç7X"E¨GØ›ˆ‚,È)£˜¥È§H%«¨ŠŸ(&­þˆ¯¸4ð…Â{…r&¾ø‹Â˜'·8¹¨3 Œ|7ŒË8ŒÎh'‘§‰¥7xÔˆ‹Ò8&žGw‹gwcrŒY¢yÙX˜Žºz_âXR‹ç‘ŠÏQŒQ‚ŽS¢ŽæÁŽç××(&òè‰ÛáŽLR2/ø|†x…ø|Ëw:H}*óB*dü¸$þ%ù…ø} IBx‘ ˜ƒÌW×LjóÇ‚E":쳂b‘LÌ'}-i‘Ýw‚:H~1ùˆ\èƒI’=jˆö‡±øÖ÷…UHŽèL)†é…3Ù…Y 2ÄãAÞô“ž‡éhXh‰9(‰zHƒþ_I‚$–Sˆ…ÈÇ‚,c‡6‚’çx_’ê1‹E““)é–^—¨Šu ”ÓRBb•÷zßøŒÄ˜yò|d—]Ò'†‰'Í(‚in„Y– *y™šy™¹™žImÕV¢9š¤Yš¦yš¨™šª¹š¬Ùš®ùš°›²ÉV z vÕ™Ÿù™º¹››Ù›¾y™ÀœÕ8œÄ9xÆyœ’”œÊÙHÌÙœ‡ôœÐ HÒ9{TÖ9G™™@;P‰  –²Š3;ê#p9ÎBÀ6Ü©@!rAäY"ǘiâJïÙÉs@kã= 3;6ß‹“y jþ˜ú š“ÆJ”°C7Â>òS:Ú’;-²6½£„L¹†ú¡ ¢":¢$Z¢&z¢!:‡Œ\–Gqä0d38¸ã7(1\Ó6P’ḣ<Úy‹¥¢|I‘Æ×!!SŸæ1¤Ç8¤HŠ)Jº¢LÚ¤”ò¤Ajb})¥B¥W9yQŠ¥YzbAws{6P¦fz¦hš¦jº¦lÚ¦nú¦p§r:§tZ§mVú[:z‘¦¸iOyw¤6¦Â¡ +õ§¯¨ jo„¨î$*’ª¨vd@º§Bzb‘êSCÅN@U?U©–:*Œ xqö¨À©%å©(õ©¤Zª¡þrªð–ª}ÚSóÔE¡Úª¹ÊP‡*«¦Š©z:˜¹×§ð¬‡%¬‚úzÆŠ¬lD«a:¨‘æ=Z­Öz­¸­K ¦]²£Ûˆ­®ñ­Ú¨¬*tªú–Ù8Žàºœgwæ(f™J¬ë×¥Y‰€!÷ê{䊪 J¯~i¯r)Š˜ûZ«ýÊ­Z‚—Ç‘¯`2°Ì~Z*¯\аß 賫8;Tù;Ö#Û9 K’ étieñJ™ÅJ±õjS!²ž“#@ä„«Øîà t¹ 5'铭̪²ÿŠé™;Ý£ XG#.vã Ó"Š$$ŸÈôþg©2;@k9’E»­Wš´Ì>ô#?ö±„x(²öá²ñq<'T¡”·ã8$µßY#29l ¯ÃвóŠ´Bù@RY]C6ˆÛ1›‡W"5÷‘6 ³¶C8s£ò2Ž[¹>Ò¸Ú ¥„+‘éÁ°Bº[•c ºe[¸ëè°'âºDø¹UZ´]¢°9i»ÜAº˜x®F›²«+‘†Œ *'Âë' ¦d›(ŽùŒ‘9¼qÒ¼~"»š ­^ )+¸û»Õ+&×xþº½cÒ½¶ºàë%â{°Ú[¾Zr¾ŽzY0›ð¿ò;¿ô[¿ó‹¼PÎJQ'xêkHØù¿“é¿|º+ZÀ<»L¼ÀrÀœ%ÁS’H£1¨œ)U3ŽšÁ˜2Á ‘êG:W[Â&|Â(œÂ*¼Â,ÜÂ.üÂ0Ã0 µ‚; 2|Ã8œÃ:¼Ã<ÜÃ,¼Cƒ´*B|HD\Ä€tÄH¼GÖžð ªÅR<ÅT\ÅV|Ťś ’`d±`ÆbÌ_ÜPÆj¼Æh¼ÆnüÆpÇr<Çt\Çv|ÇxœÇz¼Ç|ÌÇm,ÇA;tkHTML-4ee7aaa953d6cb59/tests/page3/image12000064400000000000000000000067731151224263100174430ustar00nobodynobodyGIF87aä÷õ0@0666>>>>R>H`HLdLVrVZvZ`€`d„dfvfhˆhllln’nr–r||||¤|€€€€ˆ€‚š‚†²†À”œ”–––˜˜˜œ¬œžžž   ¢¢¢¬¬¬®®®°°°²²²´´´¶¾¶¸¸¸ººº¼¼¼¾¾¾ÀÀÀÈÈÈÊÊÊÌÌÌÎÎÎÐÐÐÒÒÒØØØÚÚÚÜÜÜàààèèèêêêðððøøø,ä÷þ@‹pH´$ŠÈ¤rÉl:ŸÐ¨tJ­Z‰ÇeÁÂèz¿‰¯xL.›Ïè´zÍn»ßðxØà" ø<¾ ïûÿ€‚ƒ„…†‡ˆ‰Š‹Œ| u –— ˜›œžŸ ¡¢£¤¥¦§¨©¡•œšœ‘\²csq¹º¹]½_jÀ^»ÇÈbµ˜ ¸_µ³“¶bÐÉØq½ÛÝÝ## à -åÂá½Æ ãéçÙò¹µÕ“ÏdÒ’Ò˜øóÙˆAA ïÀëÕ‚††-šK·°`À‹jêEûÇ ‚?jÓ¤ÐãÉ1ï žCHN¡±†ã®TØÅet'sF³´×þÈ.úhÙórM'F—*#v#8‚eAq#6çm©SœFsjôb $WYû†v)šµìœͪA^Ù†tð'£»xóš€gÁ½€"@×]?À&HPà‚ãÇ#KžL¹²å˘3kÞ̹³çÏ 1/Þ2ÉÆŒÓ¨S«^ͺµë×°cËžM»¶íÛ¸s¿Þ––Àƒ N¼¸ñãÈ“+_μ¹óçУKG.¡wé騳kßν»wíÕCþþN¾¼ùóèɇß7^x‡ðß;ïÐáEá÷ÓëßÏ_ÿzßÄÁ÷}Ø—_r˜ }öçàƒ6÷ßuÃ5 | €aƒÆþY˜á†^Èa„$–á„´œ€ð…Ø@}Þçbbhâ8ò‡¢ŠÀ±˜a#r I£…Bæ¨ä’ßí¸Ÿ€LF)åtNêGß”Xf¹\•Zvéåƒ\~)æ˜åíèÁ™h¦©æšl¶éæ›pÆ)çœtÖiçxæù&Š*èé矀*è „jd&ªhw‡.êè£Ð5 餔'i¥˜Vz)¦5Øàé§ †*ꨤ–jCfÊܦ/È`ꫯ¢úB§°Ö**ª5Ô $³Úê«©²Òúë°6ÈjiH¹*Cy4æj<Þ€³ü5«kz¼»p§@´Þ}ˤ¸’«_þÚÒÂí Þ‚Û¹9»Ÿ¼Þ·i·æÑ®»$ꋞ¿ä¡[ܽìæËïvô x%”w¥{C>|Àó'0qWø"ÄöuÌœ¼ù½˜*q'¯ IßÈÂPß…ïÕ·¡/nÌ0pð¾ߊÁé\\ƒ%·ÌãÎøýŒaÐÄ]<\Æ+Êhà Fº,ò} >-ôpèÎ<õ}5§lupò \ ÀP^ €Ž ß…jgøBˆ%Ó›µÓ83ƒSC-À×8óX Ê"»3Ø=Æg3‡J ÇôŠBn˜àÛþwªaãùÙ5g¤Û“_Ý2ÏèÙ¸†`_9†m×8 Ëž_¶^ø¶þiGŽ!Ê­×mãØ‹ýbjãNxº“¬ ñ‘0?^c‹³ÓH¹ß–£;Û´+Ì:Ø<Š.»è+÷èúÚŠîa idîºçG6Ôn?½¼Î£¯àø³S_÷éªÇ?üÀȇ¯ÃåãžÊض!¶qO~-B¯€d¡ùð|ØW´ Ä==0r3!Ø7¬Yˆ}æóP’fwºŽð~üÛ–ÿ &º%í`Ú¡„d蜛™ †ï²Wÿ€ó¿è ®84ÄNû3Äå í…Ó¡ yÈ€áPˆO$bß5Åì$.8‹s⿪¨p1†_”Îs/aëŒh|“̘Æ6ºñWº— þ–¥ª:NIvXÜá zhÇ>æèfYô£ KH=òqˆtP!—¸Ç&&ò‘OjP !IIó,R]+ 2ÀÉNzò“  ¥(GIÊRšò”¨L¥*WÉJU‚àˆ¥,e©)ÎŽ$A ÞÈË^úò—Àü%,Q@Ì1pä%‹—Iáè2T%ðT4ƒIÍjZóšÃ& X`3™¶Ì##ùøLPyÑçĦ:×ÉÎ`j“2À7•)I\j2%€@>!ÀO~~ŠŸÓl§@JPR “ºò€7Á‰ŸzŽ3—)è§ý™Îtô¢mç0á y2´i·|è=%JÒ ų́JWþJMX"48 ýháBŠI&ÞÓTe©NwêFXÒ@i’€LùÈròô¨Hí%,OÀ¦:uô¤)3mêÌ]&õªX%,Gƒ¨Š³¦¼iVÇJÖRmu80WÉhϪ–õ­pýx”Öµ¾ ¨V«^¯zVáÔ5œl©[÷JØ£ö¦jì]Û£ö±*=,pþÚP©"ª™Í+d7[Pɾ€² ýêTÃ:XΚV žíLE{Yªfö´°egj[YÖ¯´±ÍmKçŠVÚ†6°`%§fuK\¥òÖ¯¾]-pG+Üâ:׸tM.Q Ç>÷ºZ=.bíŠWìz7»Ñå.u_`þÝïš×¬Ú¬t—ÙZÒ¾ö¼ðEoxÛÝøÚ7T³¯`ß{ßþæ—¾ã-oÏûßÚ.·½Íð} üÛÅî·ºÃU°y¬\¢¶/…§û`òF8ÃØÝ0{oË_WĽ°XM|âô~v½)f.†YÜâùØÂ2^1¯‹bË’Â;önm‹Y ™Ç.V-‡UŒÛ#wÈþ±‡ü\(ãÁ3¦ò““ cyÊZÞ²\ß0çÖÊe63lÑ૲lî°€ßüØ83¹ÄtÞ¬sÜä<×™Ëú½³‘ý¬g@XÎn&t\÷Œe+š°Œ–òœýÖHyÒ”&«¥];èþLëuÓîí´§á êzц¾qšO]ÖRg™Õ­N5™Û kR˺«®5V]íh]óõÖKæ3ž}T^÷™Ø†öˆ/hd³ÔØÃvöN¡-jiO[Ù1nô±­½Rjƒ™Û<õ6¦ÁÝYl{™Óß&÷³ÍMdt[ݨew”™ oŠ»ÙõÖ¨¼¯,i|ç{÷þwd÷kÇ{̸¦µÁ/ð…—áÁÖv´®Î†Süའ´°«}qlZ¼ã'¸ÂArˆ/ÛÝþ&9t3~hA§[åÖü8Ì«)ó™»S䈶ù5k®s_ò¼ç¼ü9Ð{Šs—¿{èàe¹ªGŽô•#WãçxÓÓ(ô©þ'ýé-ßøË­Nõ¢kýè\‡UÕÃn«±“]ì^úÖÏþ+³³]¾JŸuÎß~F·Ó]Tv¿;¨ò®wOñ½ï×{àï>xºþí‡g{âϾx²7>ìçzä­>ù©W¾é—Gz懾y w¾çŸ×yèm>ú™—æ§WyêI¾z·¾ã¯¿xì)>{‡×~á·7xî¾û÷>ß¿¯wðá=|uŸÜÇwò¹½U5a ËíõÚûŽ^¦:µ©PͺÚÁN}¹Ò@T]Õ~¿»_v ¼48B…úøÉvpô³êÉ¥Ï}êôZU?½Ù¯Fyº_ …Lú‡rü×ÄÄ.àò—mëWþ€å(ðÞ$€â·8*°¸40€Ò—º1‚$X‚&x‚(˜/ ­AGrçr•ƒÞ1‡$ƒ6˜4èH7¸ƒ-Ä€_ƃ@XC>ˆnAX„Ê‘ƒF˜„Ë„JØ„2„Òç„RÈ„RX…'eV¨„TÈ2‚¨ÑH^Ø-ax‚`X‚ä±…Û15à…ð¦†mø†c¨qh‚møh¨5ˆà†eâ‡QÒ‡aD}ˆ‡P¸‡ÓˆÒ!ˆ8ˆèÁˆàq†‡¨ƒÙ¡ˆÑ‰MˆL‚‰|(‰ç…•¨ƒc”4ÅÁ‰Àaðµ &`Ô¡‰ÃЍ(­þøŠ*À*ðŠÆÁ¨¸Š/ðмx¦è>ŸCŒž}–‡"!d>h$×#ÅÈ‹º˜Š¹¨ظªHˆ²èаxªØŠðåø¨¨ŠèXŽÀq‹©¨ŽëØ¥øîSA 䆸‰ËøÍè8³9¬sEÕŽéØM)Œ©‹ÃQŒ§˜IŽ/à‹¾(Œ¿ÈмH‹9ŒÞ-ãƒ$b# ™ŒóF„¡˜4Žs$ƒ3,3Úˆ‹¹è’¯ˆŽ*ŒèG§H&0“º(ŒÁÈ舋­ØŽ7I‘?© 2ò:.2"…8ƒ“ø‡$2+s8ƒ4Ÿ‹ y‘Á˜•[9î2“þÁØ•99“µ´‹»¸‚9F™“°8–`é•$#3O33øè”úH‰Ø±ÎÁ‘èˆçÁ—FcMÙyX’Þ˜è—æ˜"’üöƒ†ÙŒ¹ˆ6y#“¹%Ž9I•è…"ˆ…r&žù™𣙙ã¥ø™+(š°š¬é'® (¦ÙaY˜„…Y›A¸H£…¸™› 20Ø›@x›Âyƒów:Ž“œÊ¹œÌÙœÎùœÐÒ9ÔYÖyˉG#é0ØÙÞùàžâ9žÒ¹4zTœµÉ*èi…깞RØžîÙ„Öžð ªpŸø™Ÿú¹ŸüÙŸ¤`Ÿ› ’`d±z Ê-ÚPð ¡¡Z¡z¡š¡º¡Ú¡ú¡ ¢"*¢Š¡A;tkHTML-4ee7aaa953d6cb59/tests/page3/image13000064400000000000000000000117771151224263100174440ustar00nobodynobodyGIF87aä÷õ0@0666>>>>R>H`HLdLVrVZvZ`€`d„dfvfhˆhllln’nr–r||||¤|€€€€ˆ€‚š‚†²†À”œ”–––˜˜˜œ¬œžžž   ¢¢¢¬¬¬®®®°°°²²²¶¾¶¸¸¸ººº¼¼¼ÀÀÀÂÂÂÈÈÈÊÊÊÐÐÐÒÒÒØØØÚÚÚÜÜÜàààèèèðððøøø,ä÷þÀ‹pH¼$ŠÈ¤rÉl:ŸÐ¨tJ­Z‰ÇeáÂèz¿‰¯xL.›Ïè´zÍn»ßðxØà" ø<¾ ïûÿ€‚ƒ„…†‡ˆ‰Š‹Œ| u –— ˜›œžŸ ¡¢£¤¥¦§¨©¡•œšœ‘\²csq¹º¹]½_jÀ^»ÇÈbµ˜ ¸_µ³“¶bÐÉØq½ÛÝÝ## à +åÂá½Æ ãéçÙò¹µÕ“ÏdÒ’Ò˜øóÙˆAÁ ïÀ뵂݆†+šK·°`À‹jêEûÇ ‚?jÓ¤ÐãÉ1ï žCHN¡±†ã®TØÅet'sF³´×þÈ.úhÙórM'F—*#v#8‚eAq#6çm©SœFsjôb $WYû†v)šµìœͪA^Ù†tð'£»xóš€gÁ½€"@×]?À&HPƒãÇ#KžL¹²å˘3kÞ̹³çÏ 1/Þ2iFŒÓ¨S«^ͺµë×°cËžM»¶íÛ¸s¿æ–ÖŒÀƒ N¼¸ñãÈ“+_μ¹óçУKG.¡wé騳kßν»wíÕCþþN¾¼ùóèɇß7^¸‡ðß;÷à¡Eá÷ÓëßÏ_ÿzßÄÁ×}Ø—_r˜ }öçàƒ6÷ßuÃ5 | €aƒÆþY˜á†^Èa„$–á„´œ€ð…Ø@}Þç¢bhâ8ò‡¢ŠÀ±˜¡#r I£…Bæ¨ä’ßí¸Ÿ€LF)åtNêGß”Xf¹\•Zvéåƒ\~)æ˜åíøÁ™h¦©æšl¶éæ›pÆ)çœtÖiçxæù&Š*èé矀*è „jd&ªhw‡.êè£Ð5 餔'i¥˜Vz)2Ìàé§ †*ꨠŠ0d¦ŽnÚ ¤¶êj¨¦Ê ƒy4¶Ð髸暫©¶êê««¼Þúë°3ðjiH± Cy4òø²*Ic´üM;kzµ»p§€³Þ}ˤ¸’«_þÚÒÂm Þ‚Û¹9»Ÿ¼Þ·i·æÑ®»$ꋞ¿ä¡[ܽìæËc~/žJܕȡÃåAü®½È‡ïŠ/ºWß}#'/ºÚÇ Çï1¸1‡ô x%”Çpp/¿l¼ïÅ·"Ì,ã§ñÌg¬s€Ê\œÀÄŒŸŒ¶`$%ËÇ`ÒÂ} œ‹^X3AfØBˆ2Ë+¤É_+u}VgrÐf£ì,ÈHOm`Ó5?$ÔÁIýuÂL—\wñ¥=Ñß&¸µ‡?r}ªÔ‡cX *øá}4.ΣÀ %ÑX™9|‘7þù×Q¯ýv¶^¸µR!éu_n þÒ ®>õ‹5ŽÞ5ÅÛZ\°ËzXóê5¶¸zå¥ÿÝ"’µi¡ä idòQߌ.äïiX7âŸ;.ºÊLS_ýæ7‡žtñ6"û߆^ ù¶çþ⼫ë»{Ñc¤óèG޽øãäT§?5Hr’^ô&—¿é­}ØXw8#9ÏS»œ…”f¡ vÐmk`’ö–®I¬ ;m#ŽÄ°³Âþ´p99ã'ÁIGoCã×v^8/>Gh9œaýLx?ƒýˇâá‘Èdžcât ÅV±‰Wdáe1aKWèñâÇHÆ2šñŒ£âнf°,T¹qJª{bÅþ€s±7ÚQI9ƒâ÷X¢<αuä£ äÇÞÑñwDÊÆ\½…ÑoBÝ +UHû’9Z`~ö÷¢¥  u _Ò–=¬%’›¤—*IÄKiB$Ù&œ¬å‡iÆËÜ"s¹ÁìmÐx-€e¡†IÌbÊI–j[ð˜à™*˜åìfŸZµ¨V¢ôÓjD¼ÍåGÏ §8ÇIÎršóœèL§:×ÉÎvºÓˆ„¤ Èx2Ó28M¯7ŒÌ>‘Ì[$]†6úðóE>ó tÃІ:ô¡¸a÷¼èUußÚ‚¸öV”uíw»ÜÖ–—»Œµ/h]›]ʦ÷¿ÿ]/ÝÚÛY˜¾ÀN°sÜWêò6ž!P°„'œW+³Àž©†ÛÚÛ»÷¤ž©[=Œá‡øÄæë…IêÙo¢°©'Œa,ãw‹Æ&Æ-gYl`cÇ46V Zä 3tÈEž1’:äKwÇ8m±§“EèH€ÈRºr•·„eðXø¦SÍ锥³eçh9Ë]nRš±se'GÊa–ryÊ,¡5+éÌê±³tÚœâ͘ÇÖŽ³¸$Ž>qlö #çmôiûËÓítŸÉêÆƒ¿sáÙFæñ=_?Ñ?N‚F˜:¤-Ïuü®`‹ÊV5\?=áÿÀá?0Kòc_kç+\úÑ÷¸hÇ—€8€X€†M:¶w¶Ç[ŸRþ0†3BÄp!ò5#$?KS~Ÿä2zHW. zB'xšæbÐñsóÑ1ï€7z]7‚º§Îç(˜‚б‚!˜zÁFƒ¨bƒ Øv7§ƒ™ÂƒÃ&P„Fx„H˜„J¸„LØ„Nø„P…R8…TX…Mz7„Á1WØ…^¨^M§y>¸^\è_£‚\Ÿâ_”_jø…nøEYXb^ç[‹EXÝ…†ÅE\ŠU^o؇`†¨Gz9¸…ùuZYÊu]Ø¥]T4Z«Yލ\Å凔Ø*qqsø[Þ^u¨‡Æ[ã5‰•8Š™ˆ,HtD¸]ÀZˆX‡Ø…X¬ØŠ‚¥\ÁUXúþEЏÈ#B(‡.8\ˆYf˜‹¤x‰²—‰ÂxŒµEŒ 8‡+`dÎøŒÐµ¡Œcq@è(»ˆ‰½x•’ŸÜ8)Þ¸Œàøu˜åDöyèXYëˆFèhŠ7(ˆ#&qéau'‚uJ'u=(‚ƒøuõˆU'W§À¡vÂÆ‹ÿøiiyæ—™€ZÃ7…æly30crâ—3w:7<ér?cùdýˆƒó(h•7uqÇræl†s“Øw7‘„Cûf#¶„‚»$‘Ä1I£71·mæ'#OÓpsX{ÕØ”ôxhÒ:[ã<¡T3ÿV“õ6j?‚•¯³?þºt;ìçoƒ”%Ó=×ôm¦Viäæ8ÔlüX‘ )RÜ„lÀ”5V‘GãA•ó“Üvl,s=~™•ZIQ¼”—s£>…I—ÂcnpÙ”ñG‚Ù1nÔH!Sjz‰jtAƒ}dãj¶Ã™?yrÅ1mþc$˜ÙrtÙk¹vÔè-9™ ‰f©š0”¯É’’ùc³%öHiUä|)ùf+)»Ie½É$¿™uÉeq©±É›9ל`BÌéÃÉ^rÉ.`€×ÝéÞ žâyxäY€¹iœ/ŽZ2ŽO9‚,@wò9ŸôYŸg’™ˆ-xOïÔŸþùŸ : :N˜ÚþLÒ¸  Ú ºlEœËÄž‚~ÊGz¡w”¡úFÚ¡¨ò¡ Š)":¢”R¢& )(š¢Ž²¢–I˜šY=D ¢ÒwŠºç#x)=§ÄH%ãI $$Ùôr.òIƆJ·ÖQ8ê”þ(Lg"K>¢C:¶45Wónt˜ò!€iK#dŸbjŸÈ¤’qåLД:JS3Ó†@¨vo¬ƒMd¤òÖM¡–0¸º§|Ú§ì‚ŹŸ •O1°O %“ s*6ÓqÂO0‚•)×¥FY”>ó –Ú ¨Ûù,Mªî ›ÇÙ©8ò©º¹ž¢!¤ªžÃÑT¬Úª®úª°«Kþ•Pº&é)¨ï¥Vºº«¼Ú«¾ú«g`P¬ÄZ¬ï™bªñô‹Èø¬c$¬p'ð@­' ‹ù©£?HˆÐú­Ä"­Ô:ãz«¨è­àº®¹"®/(p­ÙŠ®n§®ìz¯¤"®ãQ®óúœ úYø°¡"­ï ñگʪŸézUÛ° ø "媭š æ° +¬&@x‡g‹ ß¸Îб÷*¬ ð(›²/ð±i±ÍJ²«±„ŠÀ²fê²¾³«±ñ$6+¡8K„:‹¯<ûk?«Ak¯Cû­E iG뤥š³K»®M«kO™/;µàZµþyµËµB«µLëV>K¯Ýʰb ­\+s^«°õжi‹Œk[¶þ²·Â8·mË­dˆ·rK¶{¸šµ~›‹zk¶}[¸† ¸ˆëi#«¸”x¸uKŽ" ¹¸(¹ Ë·Žk¹¤ˆ¹åˆ´ÿz±œ¹Œ;¹ïY¹£Kº½E·™+¸ K‡©ë‡ž»P«ªa»o8»©:¸R‹»n¨»Ûêºo »¾û…À[±¡K¸ÅÛ…Ç ²”{·ËËÍÛ²ÉÛ»Ñ+½¥Ûºúº{½6½7[½·ë½Ÿ¾@+¾JK¾f¾ k·¢«¾ß›½Ÿ[»¼;¾ð+aìK¿Ü{¿ž—¿Xk½ü›`þûµ¶›þ¾ü_ì¶gK¼Œ` ¬¹ÆØÀ R{x»½ÃÛ½ü\&«²){Ár©ÁÜ\Òšd, œ´p;ÂèE°¿3±Á,ÜÂÛ¯›Âè»Â3ì\îÊ.üŠÃ;LÂ5œ­‹°óû¿ö;Ä´%®Õ*æŠÄ´«ÄÌÄ—åÄ' ¯R¼»¯aVLÄ7*1<¿§º$\<¼elÆÁ‹Á œÆJrÆmL d5fcu|©­qǺ1Æ´K10³µdA&ÈxÜ„|d|ÜázùX&ÖÙËI‰ªÚÁÈTòÈuV›ÝÉ"9ɦ*–\’I›iºÌªµQ*DšÃa þ Ï$ÉîâÊ®,³ MN&`àʱ,N¶ü’4Š’žŒÊö4¢I¤A"J‹IË¿Ü˯¬Ô ËÕ\Í™µ|ÍÖÜ ÎàìÊØœË²ÜäŒÍ @αl›š¹4¾V“¦ ¶è‘Ê…³lþc;ÓLÎ&̯,N½ÍzÐþ<ËáÌÁ,б¼Ðè¼Îä„Ì”9“óhÙ©¿hìÇË\8òf£U¹ÍÐÑ*`ÍÐäËë<ÒÎýl#ÝËá„ÎÑ,=Ëç¬ÒýÒ¬lSw$ ÷˜ILÀõ[Ï|…¨ÿ´Iké,¾ÌÏè¬ÒzÊÔ)Ò¿\Ë,=ÒÑNà$wþ,ÍÍÜ|ÕSÒ9=£/7;e™ÌéÊÑÁÉS‡Éû±œ?wÑT|f œŽ¬ÉÜÖ³6Ï ן¬vÍ×jíÍ”?­À}×1Ÿ„‚v‰Mdc 'Š­'n Ô¯[0@Lx7L—ÝØm’Ù~BÖnüQkì^\ž¤]Ú¦}Ú¨-¡ aüŹ뼧ûÙ‰²¢²%´]ÛRRH£á¸-&93!ÛÛ_rÛÂG@Ý8ú—ÜʽÜÌÝÜÎýÜÐÝÒ=ÝÔ]ÝÖýܧ*^yÝÜÝÝÞýÝàÞâÝÜóGÅ­)æ}Þ“¢*ê )ìÝÞ©2 à ¯  ö}ßøßú½ßüM õ½ 7 f@kQà~àl@à]þàÞà>á^á~ážá¾áÞáþá â!.á;tkHTML-4ee7aaa953d6cb59/tests/page3/image14000064400000000000000000000070231151224263100174320ustar00nobodynobodyGIF87aä÷õ0@0666>>>>R>H`HLdLVrVZvZ`€`d„dfvfhˆhllln’nr–r||||¤|€€€€ˆ€‚š‚†²†À”œ”–––˜˜˜œ¬œžžž   ¢¢¢¬¬¬®®®°°°²²²´´´¶¾¶¸¸¸ººº¼¼¼¾¾¾ÀÀÀÈÈÈÊÊÊÌÌÌÎÎÎÐÐÐÒÒÒØØØÚÚÚÜÜÜàààèèèêêêðððøøø,ä÷þ@‹pH´$ŠÈ¤rÉl:ŸÐ¨tJ­Z‰ÇeÁÂèz¿‰¯xL.›Ïè´zÍn»ßðxØà" ø<¾ ïûÿ€‚ƒ„…†‡ˆ‰Š‹Œ| u –— ˜›œžŸ ¡¢£¤¥¦§¨©¡•œšœ‘\²csq¹º¹]½_jÀ^»ÇÈbµ˜ ¸_µ³“¶bÐÉØq½ÛÝÝ## à -åÂá½Æ ãéçÙò¹µÕ“ÏdÒ’Ò˜øóÙˆAA ïÀëÕ‚††-šK·°`À‹jêEûÇ ‚?jÓ¤ÐãÉ1ï žCHN¡±†ã®TØÅet'sF³´×þÈ.úhÙórM'F—*#v#8‚eAq#6çm©SœFsjôb $WYû†v)šµìœͪA^Ù†tð'£»xóš€gÁ½€"@×]?À&HPà‚ãÇ#KžL¹²å˘3kÞ̹³çÏ 1/Þ2ÉÆŒÓ¨S«^ͺµë×°cËžM»¶íÛ¸s¿Þ––Àƒ N¼¸ñãÈ“+_μ¹óçУKG.¡wé騳kßν»wíÕCþþN¾¼ùóèɇß7^x‡ðß;ïÐáEá÷ÓëßÏ_ÿzßÄÁ÷}Ø—_r˜ }öçàƒ6÷ßuÃ5 | €aƒÆþY˜á†^Èa„$–á„´œ€ð…Ø@}Þçbbhâ8ò‡¢ŠÀ±˜a#r I£…Bæ¨ä’ßí¸Ÿ€LF)åtNêGß”Xf¹\•Zvéåƒ\~)æ˜åíèÁ™h¦©æšl¶éæ›pÆ)çœtÖiçxæù&Š*èé矀*è „jd&ªhw‡.êè£Ð5 餔'i¥˜Vzi¦œJWƒ  †*ꨤ–jjC·é 2˜êê«£¢ú§°Özj}´Úªë®¤Êš+¯À†Šj 5XY ¥! ת åÑH¬yΛc´ýÑÈãyÇ·éiØ^ëÞ–îƒãî—­ªþÉÇ­yå².‰íò/zç·í ÝÒûn„óê×/»ÇÝ›ïÀJþ«o…/VX܆W"W¯pã—ppWÞ7âqóæ÷bªÄ5ŒñµV|ñŠÀy\ò&ï{ñ‘\2” SÌqpó(ä{28ä±âlàpq2þl$8ËÇàÏÂÕL4‹ ZœtÂ07ïÍ8cq}ú¼¡/RÍa¿<mµI³¼tLÓÌ£‚ ¾  Ü4¿Xc!š4pC÷(ä†q»øcÞ©:-·‡vÝb~sÓoÓL7ÑgÓ,¤†xÃwaæ9qpHñ…t·ø¡ˆ>î6ÐnN·ë•ß2þÒMœ.pëž|¤âEר"Ý4ùá¤ë¦ßüçµ÷8ùñïiX·ˆœÿ.»ò´¯Î:”ÙÞ{‚€c/<оp¡ç[ã±5ž}óÚÞþBîºo$@~˜úF2_÷é—«Ÿ…àf¿$iotŒ«ŸÖìS»ý¡/}íS_ÿ(9èeË~ˆsÜÍÎg@«íë[¶Û‡pè³îƒÙ1¼PØœªG…ßÙÛ úŸ©Œ…Ó!„t8Ÿ™P^!¤Åñ它-‰‡1Ä¡vdHÃo)1:HìO»3Åì@ ˆ“ᯂÅÅ.zñ‹` #°ø“+mËÌꔣD:¡É„kŒ£‰þªÖD9ÚñAt|#ïÈG<6¨Ž} ¤yò(BuíQˆäõ8dà‘Œ¤$'IÉJZò’˜Ì¤&7ÉÉNzò“Á $@ÊR–Rƒ#…C‚ˆñ•°Œ¥,gùÅQ¢à–¸% bpȶÍp•Áie¨J`*b ´L¦2—IK[¢€&àÀ-y™J7w½&¨Y*n–Š˜È4&3ÇIÎrÖÊ™4¦ÙKB ÑL P‚Ðsž%Àç »¯À6ô±­šì;/{¬ÍFõ³™Ml[zÚÔ®u…mhW{Û±Îu·mY»ªå÷¹mšîI¯{µß®ó›ýnvÇ[Ê‘Vw½Úî}öÞiη»ýÐ~ü¦?8¼µ-ïBÓ[á¿8¤q=pˆ'Wâ2æ´¹-NPŒç˜âçhÂCq†ãä$/¸Ço­q}§ü£+¿öË—9ò™Ó<æÜ¶ùÍMp”ë|çü…µ¨7þófâ<Ü/:k®ôX2½é¯|:Ô·{ô¡þ»|êJ­ú¼¥õ¥kÝá\ïºY¿.p±ÃRêfÚÓΫµ³]Wnû~Éê­]îc$»Ïñ®v½·<é|7UÜ_ªÁ~T†?¼€ý~ê»+þU‰|ä?ùÃWžð—|æù¾y¼w^îŸ{èÙ>ú´—Þì§{껾z¬·~ꯇzì›>{¥×¾è·ÿyîu¾{›÷~æ¿yðS>|’?äÇçxò-¾|ˆ7_áÏ?xô >}Wßׯwöß}V5aàÑoüÕ¿ø¬nU«]ºÝÇOþßH€¤J«úÁîøö“J§Ò)TOþwûË!ÕZ°=×þyë´S¶D€gþ€(xë€2€P»TwôÇ~äçL,àÈ€áÇjxˆ M8e‚…÷T1+Ђ1@i) 6xƒ8˜ƒ:¸ƒ¹ñ*Ðidmð•HDÈü×xE˜„Øq„p¤„NøLØKO8…Ì…Tx…-T€Hˆ…\ˆ‚—Ö…`nC†`h…dx†fx†a˜†Ü!<ˆõ†Ü"‡:‡8Hl¸3Po¸/`r臀H‡º!ˆ9è‡ß‘‡ÚÑ„Ø!X&%ŽøDÇሉ¨…Œ8™(“‰”¸xˆ‰R˜›¡Ø$‘È$©Øˆ£Ø€[ˆp$C¬C­þ&ð€JÁÁÂa&@«8¹˜‹Âá‹À¨ Àh‹¼øÀØŒ•8Œ”s.´h‰Þ¡ˆ¦(…!‚>t9A’=Âq‹ÒŒË¨‹Ê¨êØŽ»h‹ÖÍ˜Ž»è‹ð÷ø¹¸‹úxÀŒºÈýøŽÅaŽEr9H23ÚØÜ(‹Þ8Ã8´4æ8ûM9ºŒÃaޏ¸‘i/ðŒÏ8ÐØ‹ÍXŒ&Ið2›ƒ$úãB£ôŠXŠ :€s$Ã> ɨ& ʘŒÌXŒBÙ’Æa‘A¹ŽÓ(”Aé‹ÿˆ‹+ •Æa2»#“ i„¤øþp´1ôá5s2H9EI•ÒxŽ¸È–gIGŒ))”GÉŒÌèƒA)òx—Ky”ó3_—‹§‡ù)ŠŸèñx2)R4ùq·ˆ6I%ɘR²˜Š9™,‹šx™œ˜™ÙÁ™%bš♀¤‰.P(“X(gòš°ù'²I›ª9„Ù1°éƒ³é¼Ù›~ò›€r›±¦†XØÆù„„4‘–œTX5£1†Î©œ_9Ç©…Ä>Ú¹ÜÙÞùàžâ9žäYžæyžàÙF”ù2èÙžîùžðŸò9Ÿái/òcƹ*øy†ú¹ŸaØŸþÙ…Öžð ªp šE  º  Ú ¤` › ’`d±z¡ÊÚPð¡ ¢¢$Z¢&z¢(š¢*º¢,Ú¢.ú¢0£2*£#Š¢A;tkHTML-4ee7aaa953d6cb59/tests/page3/image2000064400000000000000000000001121151224263100173370ustar00nobodynobodyGIF89a ðÿÿÿ!ù, !Œ©» s‘ÍYÓ½ÙìbáH–£gžRú)`çrpüD;tkHTML-4ee7aaa953d6cb59/tests/page3/image3000064400000000000000000000012511151224263100173450ustar00nobodynobodyGIF89aö &&&(((,,,...222666888:::<<<>>>@@@BBBDDDHHHJJJLLLNNNTTTVTTVVVXXXZZZ\\\^^^```bbbdddhhhjjjlllnnnppprrrtttvvvxvvxxxzzz|||~~~€€€‚‚‚„„„†††ˆˆˆŠŠŠŽŽŽ’’’”””–––˜˜˜šššžžž   ¢¢¢¤¤¤¦¦¦²²²´´´¶¶¶¸¸¸º¸¸ººº¼¼¼ÀÀÀÄÄÄÆÆÆÈÈÈÊÊÊÌÌÌÒÒÒÔÔÔÖÖÖØÖÖØØØÜÜÜÞÞÞàààâââäääæææêêêìììîîîðððôôôøøø!ù^,ÿ€^‚ƒ„…ƒ]†‰†?DC0>*$*ŠŠ'<^FDƒ.4^ˆ”‚].P‚NY)2..<$.MŠ5R^Z:$R!‚C‚-[X.†F,T^QD? ,-)%.Õ‚.3+9^\U^L#-6^-„.&8=\TSOH*-´@^XH:´+ V¸ ùñ`“ 8øø€ã„#íbT @áF‘ "l¢"†/J¼4©Q¢P¸BƒŠŽ%9Ž4`’€… (`,4@Á.4ì`’¥ŠF¸ð1%É‹D0@ @K4¨æÃK .n$2â"D@É;7;tkHTML-4ee7aaa953d6cb59/tests/page3/image4000064400000000000000000000057601151224263100173570ustar00nobodynobodyGIF89a‡¿ò???¿¿¿ÿÿÿ!ù,‡¿ÿHºÜþ0ÊI«½8ëÍ»ÿ`(Ždižhª®lë¾p,Ïtmßx®ï|ïÿÀ pH,ȤrÉl:ŸÐ¨tJ­Z¯Ø¬vËíz¿à°xL.›Ïè´zÍn»ßðq@¯Ûïø¼~Ïïûÿ€}wq‡0ˆ&‹Œ)#”˜"†™ › “¡Ž¥¨Ÿ©–¬¯ а«³¯®¶§¹¥²¼¸¿ ’µÅtœÈ»Ì‡Št—ÏÁÔp„t¤×ÇÜmuÛßÎãjÚæÖég„âì ÞðdËó å÷aöú ëý^Þ$ o Á0ù*äòo¡C,r0- ÅwæJ(Qÿ! *F t)[†l2°n3•M„læh¦±e0ØT°³XĘLò°)åÐ:"-y‰¥²IÒÒ!àRAƔʌ:M)’Ø3Ž@-ìrGWÏ‹ͬ§€íLµ—òú´ˆ­"‘`må ;aì4›g!À}2¤£QˆÈ%—ªN¼×~òíï¯åfŠßZ*¬ØÒœ¶3:~K•”µ¼¶POn`x&KI¯'Ýý á®Ô’KiÂu×0Ź’–㵬Æ_{WWæLQ@ƤšKN0:g«²Å]‡~Ñ5tç#óSþ¥êWòcDSK޾=ÉîãßP-?ÄG$U%%G”5}üÿ¬¶_,ÇuÁ^}PÔÍ€Øq§_, Rà I¾!ð!øg×5· u 4XˆõÔ³Maê1¶ÒYòÄ”NKUtÊ*×ðt]8Å…ÛùÙxŸsèÈÖ\^ˆCÞ–!žqB¡Œ ¨¥UõàHЕ[Øc[²qR•/ŠUiÚ…›I‰SEí2æa¤œRŽ›V¶äŠMJ’’Hdø%‰Æ•‰d•„º¨'O†n¸Ÿ›w꘣ƒšågM VQ‚dª©4›v*Èxyæ'GBjW(bÝ‘¶Å‰‚Æêx±ºâ™ŸÀzë„ï`U^Šâª$>¥˜Xf¥£ÿHIÕ,UÈÚ8GTu@»kJPÙAjV§L;Í´Ó†h^€¨ö * #þ)FqUð¸™ê–Q ÁnÀn¼=úéKøÆëîÿâ)ÖII½-Ë J¿>ð›„Ñ.ØÂYy*š†¾¦ DZº­Rö  ›ì©peç°€°07.˜i”³¿nå§sa…ít&Â8ãp/3<Ìq¥ ”Æ>q2ü´Ë‘´A*ÁX.™•ÓËh5 Y¥:œs¡CM"uT#iˆhXŸk. ãêÃ2¢?M²Šp#) œ¶ÏUø¼ XR19!•P|ÒÈ׸y}~%zW5NøjÀ‰Ã½øf;9n•àÿ=æ¹üFë”ýµv¡èÒ–ól5嶈çŸsUnP–žÑé<ûX”K‘e™-qšÛ"â‡(ºX£¢Ìq§åÀ"ÖYP”C®aЫ$ë±PV±n`+'IˆÙÈî'°€¬ «Y*¼µ³l ìÙô‰Ú. µµ%[ë  ÖbÂÖ¨·%ÇWk»ÕÁ·ã-JÛÍW¸JÍ­ú” 6æÿ"wÀ-Bt È×çÆà¸;Ðla­»Ñfι¬ânXX]GŠwØÕfA‹ˆŠ)Q‡nð. ëWT0P'ï+Ëë„é:`»çÏ`IÈߣ@¾ÝÕ¯ |¾3Á¿ucpqì‚ú®%»EŽ‚G»aÇ–Bˆňô~x ¥5±.ï`ˆ–½`¨ä7F<^¨¸ˆýƃ¯˜Åþn"œ…·ƒÈ“E²@aä34y¥…ñ0ÜãÀ»O–0}°å‚J˜Y¾n hûeXùÞõp™'¦äÕrvÍ9³ ç+y¾A–r=Ñæßö9Š{æ±l{œá@“àÿÌfÎóŸ ­ŠE¡Ëmeô 䆷oÍÏ[¤¢}Q^r/‚Tÿ›ž˜}ªÌ­mU´9‘â~eBð§ ÐÿW‰iاgK‚rWË~"#2wB£Ñ8¶g^Hr8[4Ù7%àqQïG9M!‚:G)CQŠSÓm¥P¹Ç88uÅÇ?‚b‚è6A‡¡äCžáÁ ôW0aDD‡X’@‚$.T×ìw92>$¡;1:±£ibw+UCùÑR—s;NbFaè$$7}³q|{b)¦3‡PÑBå²v±cR´ƒ†ò¬Ã…-„£Cr X¸á†Â±'Kw æDˆ|h¼Ñ…¿ˆ­AÛP.»ƒuµ³%›µ†DØB’%¦µ†¯á› v…7<šô9CÔS9b dt<$$°èAäóÓSÕ£=ã8õÖ“‹!”=Æ“FðÁ!Þq‹Œá‹@µ,‡¶Ù±.B¼Øp^·=¼˜#=Q ï³ÙC-"À878[Ó#oR°eèÓ[wü eâ¦Ü«j$ÔM@?àdpy™ ¹ Ùù‘9‘Y‘y‘™‘É] ;tkHTML-4ee7aaa953d6cb59/tests/page3/image5000064400000000000000000000043711151224263100173550ustar00nobodynobodyGIF89aw¥ò???¿¿¿ÿÿÿ!ù,w¥ÿHºÜþ0ÊI«½8ëÍ»ÿ`(Ždižhª®lë¾p,Ïtmßx®ï|ïÿÀ pH,ȤrÉl:ŸÐ¨tJ­Z¯Ø¬vËíz¿à°xL˜Ïè´zÍn»ßð¸|N—ÈxW Pïûÿ€‚mwy‡'ˆ>ŠŒ!…<{”—“˜:†›Ÿ| :𣦖¦8’©£Ž¬8‹¯—’ž³5¨·Œ¥º¸¶½c¢À6µÃÁ²Æ5®É^ËÌ4¹ÏYÅÒ¸ÕY¼Ø2ÚÛPÂÞ3ÔáOÑä1ÎçJéê0æíCãð1õE×ø2ôþ|ìÛ÷+ ‹U}Ø/á‹Xy ,q¸Š5"ÃøâÿGü>¢ë&rÅŠ%U°KÉrÊ»–0Ë5ŒIÓ Éš8‹ ¬'ï<”Ì­`ÆÁÌœV†[èó"ƒ…=Bˆ5SÑ>}˜>݈tÂË€E§öÛ)–&²4PÛõ‚ÔY ĵ À#Tt>m( jÈa @¬±.AÁWÙ*PÚÖçÍQŠÙ¢Š¦˜€%IG÷.6.p`À‹ „•pã hY [¹µYÓeœácœçÌEÕ¢YPùóé ƒo©lˆlkCza[–ÇÀd¯å\{qïÌ¿#$µ°a÷î²¿Ëæ§ïíE´QÕ5RÞžy ÞÇêd©y§õû2Îîàñ§£ÿòÀÞç %`H˜€ àR÷“„ŸUÆŸ]8BpF°_‡`"_hâ Û¨âþ£UàIàÛùÁháG¥‘ÔPþ¤Æ“ˆ3ž÷ ¾õ´…ß-Tq8 >X €»A€ÞÏ •%^E u€5×bƒ)Hz^˜P‰¯€çfs1÷yi·ÑzúxWÕ‹ˆ±'ž²$ÉÛkT¡‚¦€…rUy½ÜãÊY®ñ†œˆñU'2¶evœu hY¯ÉžrSÞˆ!{¦²’á-Žxi§¡‚A?´©©Yíë®r:¨|d,Ìåjì±Æú…ì²ÿÌ6ëì³uÁða*|`* e$.‚Ô)k¬–Ébä§Þ! b¢°µDãrZA±q¹Dé Nê2N^†»˜>†ÍkT®2Ôi®û W¼’Ôu‡±×&†n–9Ìm,©6Ñb )®HÓª)\¬1KÓ’ÀñÇ1±iBÈ$—”± &q’•þ¦Ì‚Ç#0:†(Ëœ‚*мŌLêüBΑT ;A ­‡¢*Ô;Æ++Í‚Í)´Ì……#KÝBÖ,óxµQ1k­’Ñ'ûlÒa‹‚Ó;3íÐi«‚Õ5»½ÎvËÝÕsÇ=ÅË>ù­·ÈfƒPøàçðŒ׈ãÃöây7îÝ"P.ù9ÿ|£èõåê0>‚眓£x"d‡®ÎãôFn:æ‚õêádÞ5ì^ôæ´WC4»GQçxýµž»–ƒP<.†îÃ[ðzÍÂ7ßËáP/=«Öo0úõÒôî÷ÜÏr¼ã¡óá[=²+Qzú.d¯íE¼ÿAòg°}ößo’êe Êç?pÏ#Bþ ‚†`9è{†¾Ðœàâ2hA ƒ<™8œ/„88 ˆÂM´l!.ø=Êðû à ŸTB×õp‡ŒPa^ÄKñvEÄ^¿÷Ã$â!‡j¢Ç€:–­oŠa"ÿbˆÅ-‘w\ì"hØð‰Ñe6dŸÏØ…*bl‰lü ?Æ8Rá‹L£µ@F¸qb0#×È+hÑ-p,dæXÆ:*Ò&‰Ô!ù7GÚ‰’Œä ¯ˆI)Ò–ì$É>ŠR ¡lÊ)Ÿ˜J|r•IÐä# K'¼2)­¬%H©==ê’ ¹ÜÊ/æË!rr˜H%ðˆÌ&ÜCÁlf˜YÆIJ“¦\!-¯©“br“üæ+ž)N2P³œ´°&:×ÉÎvºóÀÑQZ~7+- nÎÙ¦b´€‹ÐóÇ$–tô9«“Ì+,iB( « ø±J³jè^æAÿ¤¿8‰<| [ÒÎ$¦fâ] hPªÂ•äAÀ›ÀŽHi4*íLBIËLÏû8hÃ$µ¨2˜ñSVøb Ý\#X%Õ2&è$TJã1uø¢'5‰ê'«y¢nó-Q)õ3 ]wÄ4ÑÔ\óØ(D&ñ“ )AaSË…ºùð*J¥èqÒzÅh«fÒªÈ$®„òÊ2z kZÏJUÀµSÕªÓFMªô)Fp2„ K±¿ò&±gÊS]h³Y~è¦ZTRó®Km´I žÔU¦4¶4S‘;Þã)ö@H³ï‘ feë¯Ú,Œ²XÁŒAE ܦ+£{-[&‹òÿPÊ5ßùݫ´Ïö‰´ƒ‚‘w0ÕÔ½ž´§Å 8ÄÝ^Á¨¼ÓIïOÏJœ]iŸ`3K¾² š~ÒŠ+ïõ[™ô$ õÇB ͥ컜WõK>ÌèòkÙr1ô5—©|Ú+ÓW9LZ,E,t,ŽÖfL6˜\~AUõöj:Ãâ[‚UÚª’˼añYŒ£Zyر`Jp²0P”û4W`¨Z¢ü â´ÀfÂpM‡/Ü ‡T7‚ÎYº;«òÂ8>}•ÕxÍ!MÀç¿ó ëK×kâ's”¾’Ñ–tã‹fI ¦Ë’•ìQ¢u¯ÞÚ8,ý%s˜ã œ-Y…£|Ω§Â›c ‘¾§3¡ó ß|áÅJ†J´0+uâõ^f͸’¨²±©YÆtiOTâtÉFÅÔóKÀäâÙütÇaübõpt•ÅnÕ`ºBX©Ç³k}!¶Óá’‘«ó“°~Ý%?pÚµ‡JQ£ÒøÅU¼Â×±=‹ªXcÙ,üÒÏ®7-ÞäJ\üú‹¯üS8A¥Ö6Ƈ2·¨JN4øeâÎÙŸc­Ô“÷N©Iß-~óÎF&EÍÂy!ç<ɯðL¸ÂÎð†;Ü ;tkHTML-4ee7aaa953d6cb59/tests/page3/image6000064400000000000000000000001171151224263100173500ustar00nobodynobodyGIF89a ñÿÿÿ8°p!ù,  ”i¡½ÁÜTÎjÌ:fê!Û5& J'fœ¾pè;tkHTML-4ee7aaa953d6cb59/tests/page3/image7000064400000000000000000000031151151224263100173520ustar00nobodynobodyGIF87a‘òò???¿¿¿ÿÿÿ,‘òþHºÜþ0ÊI«½8ëÍ»ÿ`(ŽdižhzBë¾p,«tí°î@Âvo:›ÀG åT­@qÙp± ”Gp2¯+DÆm·ØpEK#‹Ï 3eÚ}-Ôè3\ÁýZêq´§âç±jJ6,WjQ#S„…K‡ m2vUŒs&˜•'Ž=š›%l‘]Ÿ#¥ª“¢ Š;n².$±M—7­(¨w=@¸fG)I#§½PÁ ¤-R\t©t’x”¯Ô«^ÞÕÐmÉÎèi>çæëÌêÍžâBïoé5ìáòÛ¹ñô"ùêaà¦íŸwüîu3"` Bœ‡O`A{ûfÔþ¡F†ØúÁéêÁ¢q-óØÌ‚Vù$vÜø+/p 8¥$šÏ92Eb„ÀsÍŠê|8Eiˆ€ž ˜ºœ¨ðb`A†,Ò X‰UŸä<Åb§1§7‡ªÁëÈ¡èrºAˆ•¾;ÄZAIO h7Ý·&Ë~ÞÞ°[¥¬SÇ@/lI“²b$H·<5¼#,¯Ì—"ÛÅ*Ù@Ïu,ŠL¯·žjÿúêl:à‹ÁÖ&º´ŠÚ'Œ)è®j3ž_Vr‘Ûmq±ŽœÀŸ”¾Œ8ZaŒY©)ÝìTê”v6oèÂûÕÐÍ>5+¾|c¶œIf õôç2¶$¿^,¯þü‡þõWÙxóá7 €ö1}­ÑàV/,8Ð,©PÂ-Eó…el؆„z€r—ˆYŸ‰Â¡ÈœŠ'š¸ß/c3Èâw›Ô(Ç€Ža‰<¦x£D9 ˆy$L²èdVi唳%È–GX—FjùåŽ^ÂH¦˜fŠ&˜Rf“!¢ ç™VÂf;r®ÁŠc¾q¥P€¼™¢_½9Õ›y šç;é€\]N—¨›‹ŽÒÛR¦fxj :AQM‰µÔf%ñ ' Ü‰g[ÒXi§q²:f¬÷Ùé*f9Þ*kštrr寫èꢒœš*±]þ‹ìª$ªZ„³.»i®ÒÖ‡"´‡[m‹¶n ¨¶Þâ(l¸üµJîŠøˆ­M&yn¹0ºûî´æÎKo!ò¸îÀFH¬±Ö’ˆ¿RÊøK¾Šö€ „Ö]kpŸtasͽõþ÷̆Ì6û°Å{Z ÃÙî .ÇôÌ®¦ÀMÒ˾“ŠüÆm„R÷­ˆwb¢ÅÍÝù–±Æì:¡šj:G#•µ*Ö< zAõ{#*K2mE‡\+ÈO3X À¨bjÒ9ú黟€9JIY?GÆÞVV°ÜrÖ†þ1ZKÁÖÜi{ýOÛtï ·|Ð-¼ÔæuÙ9ÕYØ{BáXÝGø·^ «Íé«PþG-ßIä+yHÿiÓä(b]²0:%g–ÜnsKsçA*wQUäš&582Py!´¤2¯îñè&Snuà¸V=«ð§Ù¼kTï ½òÂauË)¿N¿Õ#»ùUÛŸ¼„èövÿž½DGO>ºD`~þÌÏBï-ø¿¯8„òg™¾ûïBË{ýMÇÏï?|$ü€)0Ëÿ 2¥À€ëS (À«¡@‚ äö6ˆùUp~áúàdÎ'BŠ‘«„%ÞñÖ‡Bþµ°~¨PO쥋 À°K?{‚tDÓ:Ca°|$Lnò4‚Ù/ˆÂY¡ˆ¸´‘|+³BYv¨·Ÿ>ZÂ{$¥9HBþчD¤Ô¥HÉ«‘øx$$—7I@°’o¼¤ §ç )’MðÃãÂGDFjbY˜X Ÿ4ŒeFkd,?)5?ÎÒ”µäã- ¹KBb 4äÞÎùK®D*:§&,%—Æä`.Ê´¥7ÃDÁhb• 3‰á®è¨nFS—¹Ôc/‰9͋͑—#Ò 6 ‰Å­ç&è¹ÔÉI4·-¯”f_ÖƒŒFá:ÁDŸ8/´ u2a?¨0h")¹Àq.Ó{ vt¨>'G‰‚¢t´è@¡ÉyQAž¬äÛ€ÕQ$;tkHTML-4ee7aaa953d6cb59/tests/page3/image8000064400000000000000000000015401151224263100173530ustar00nobodynobodyGIF87ag»ò???¿¿¿ÿÿÿ,g»þHºÜþ0ÊI«½8ëÍ»ÿ`(Ždižhª®lë¾p,Ïœ`ßxn4:è¶ÌØëìTÇâEÀk”ËaR¤ƒZ )pËÅ2¼Ö ˜5CÊH³¸ÒmçLõùŒ#i›r4AàÍzp|"Rr{^[l@Mƒ=zZn‡yˆ/•3‘”8xš2œ“7B[a£ S'¬›˜«‹)OEª LŸ$Uµ°_Yžž«J¶ ¡Tý·™ÈhÆ!Ï(Ä–-Ñ­ÉÅ˼ÍÜ.Ö&ÓßFÌÂåÕ便dèÊê+âºØÔëÛîóïìÙö7M~ÅþàçàP‡ Ìw¯¡¥ ^àd`HE&?d þ§]ºr‰NÄ‘d±Ž•LêÖ âŠ/+f´è£D{Vœi»„Sš¡†3õÙ3‹  ¯üÔIÁ D&Ù,e) É«Ašþ|i*Æ’/®Ùú…VÓ{žÊ’·uè²EÁÁM‰o®¾svÍëªDß¹¥²^ìVÍA:Öæ…¶FáÆR!ã•\—rË—1ïÕ,—ó5ÏAÇ=šô1Ó§QƒxLzÀMÕ0 ›Ö¢]Ö——0°ßÀ¹Læ;Ü.î9³%«œªñâs›Ç5$ntèp«{$No±ö»Ü+wšù]¯_#͗μ¡¢D]Süúƒ¶PìKºŽ¼Ê5éþÂî5"Ó';ȧÛâÆZyÍÅÒjøµáT>Wáuf7!uò” †j˜!sÕgâ‰@Ø'Yy+îæ‹Á˜œ‹¼Ñ؉âø–ŽÈè=¹£ZY¤‘U!9–’p“ˆe”S.¥b»¡Øˆf9Ø‘Ë-ˆ5×Q)Â"Bm©žaø†J’áÈ¡7`v˜ÊN Ê類lÒgˆÚ™ž" Œ>Öx*N`Ó"ŒZ~ðPiF2ñàRT‘ÞÉÀQð„ƒ&Á÷WLY¨Œ¥X<‘D§–$&x…î—VMYzi¥_¥å‰~ªÊ§¤Áæ 蜆20´Y­ÇîÙlŸÉÖ3¬§ÑBB(°,Ìš]#ÜÁ¥–9`Yå¸ä–kî¹è¦«îºì¶+C;tkHTML-4ee7aaa953d6cb59/tests/page3/image9000064400000000000000000000045131151224263100173570ustar00nobodynobodyGIF89aÇò???¿¿¿ÿÿÿ!ù,ÇÿHºÜþ0ÊI«½8ëÍ»ÿ`(Ždižhª®lë¾p,Ïtmߘ€ï|½ Pö©"rÉü(›Ðh% “Z¯ AËj‘­xL.o…ætyû¢µlŽ8n »7ösêÎÓt3€$~&|;Tb6Œ a@+‡8:ype …/U™–l›„£4… i¥,›jcŠš¬«2³µ{%·“7º®sº'º¨©’Á-£ž °’̘dÂǬ¼aÍ(§¡!׋ÔÎ Ý#‘Èæ!a¤h¡ŽxcœÖsàïìA~g¿®tárÖãÇçŸ*ƒÛÜåš§¾úº(„0àˆo¦>#8†ÿ F'pìx ÄGZÇ•ÜPO˜Åy:Ä×nÜKuÚ>„„™“%Í|)$òvÒgPð<@ú ñ(RÐ(xª¨êf,¤Ò>‘Å´Snüª²ú”Þ¯f‹¶ù*±m§»ºîˆw‘Ë£TmÊÉëP¯_wÿ^½(—Û¾nÐ%¼·æÛºÇâMœ#YÏ„‚–œ™¯âŸŸa~œYg`Ò¡³L†u@¢Þy.‹:õfÊ´m{KÇ—ß•ÈÝÖ­y7çÚ¹¯Ž»9;y.Û: •\6 ³‰'ÚrRï˜xCF¬} H:ÒYÈ^¼}p¨Ÿß¯?NzõÛËêq-ê]s;ÿX!ç ,tuâ›TTÇŸ°…r]Zì™tÇNƒÄÁÀq‡à>(@G\'WURo$ê× „HÈ£‘° ¦'\„ @Gl­Å[6vìè`‚(2_~qµ°NiE.ÇÄNªUƒ¤]-I–i‡}^Áå"C>y\{ ¸ÆÇ‘¹“5²¡¦š@€ge“`–ÅÕ‹eb¹€îSâo‚$‘[”¨bŸôHáÈ&罘|Sªàa+€døœXJZ‘TÝT™„–°ÔA!Š¢™WdGã|äÙrª8pÆ`ªG¼Zƒ¬•–ŠC­^ Ö´ÎЫª]¬´Ë®'àù‡°•uæ ÿX’OKëA¥²YT†GöÝ@ŒGÊE­§d«,ßÖÙ¨ä–Û¨›¶£î¹«²ºG¼³>#®cIЛ‘¹XÄËç»Ú toSItùî*ú~I¿,p¿(0ÜpœÕŽdq1&6±—¾*·ñ9A°kÔÇ E%ÉNâ;2Ê*$ŒÝÀŠÀ À ñ®ÕÌ 3Ë.Û€ÁðÜáÏ$Ï6¯Ê4ÊJcƒÇ OuÜ^¬uXÀZÝË\Ø]]ò¾_w½±Ø¯eöÄhS¬v²^7öÚ ·M¤«a']öÞºÚ‹Ü†Ñ °Ý~ß]fá§u8Ügó]¯à;Nvßz®•ÿœBÉ8Û’c:È›j˜ayÇýxU_à蛨ŒüF:äꮢÜõG{0ÔkiçŠñ¸éïëÈàë›×Íû8âH<å¦O~:ó[.}´•?o}4Õ;¯½Tˆ+Œ÷âÐs>ýö"u+®ãsŸ½âǾ>JàSÿ±Èo§_>Ôö_¼ñ³nMFÖþƒ™îÚ,_™Ï{†2 Ëè‡.ZP¸Ú x3W=ÐS6››Yæ¶3)ƒ 9ØÁq„!”€Ì¢6A,00E3;! Kà ’Ðp&´á S ꄇç«Á@2¯–Ȫ̟¼eDVi/¬Õ q0 ͦ…]ˆb•ÿ¢R>]ˆDŸ@ˆx.)Öç2™c¯â—±‹X&)ñá¯w2&¾$¯HpÄôe‰ŽI²cC‚'(Aaèv¤æ “DŠ?¯ …#áÀ l4Çdä[¤„4¹;EFÆO€c´Ø² –®‰i“—hÂÄ¥N©,’cŠž·)9(RßQ¾X'þ„NSÕ fÙ‡”Ýî@J%ì°²¨ß\è<’¥þ¦)©Bê'7¼¤” .×@…h8“æÊ6•¼HÉæw÷PæþzL`OTã7ç97¢Ò•ÃñØ&ï™&øå V@óg>ÈOŽ%® ,¨€Jù ˆä! u¢[jùÿÈZæ2»„¨BII³š× D6#zÄ&TR±©F´33š6ºåœÔ>’ºÌÞôf=JҒꡌŒèMM¹L~&ìWí)MúÓa)õa²祒úT‰ŠÀYÀj.ÀX¿6x” âW»JÖVÕªaôêY}JÔ‰Œµ¬ªlÄ[åIµ°U©ý§)æJWÍ…¯s¬ëֺжê°ôº 9˜WNþ•°…mêc!ËÖ¥Ùu«” Óe#Û À¾@L¹gg3«£‘@f›]éZPCo íLž…AkA Ø’–•PlÂb±@ÿù–#”ˆí'sØ?TÑo»çGÛÄãÿ׸Rb®+ÝFW®Ðõ`u§8Ëí‚ðºÅm.x÷šÝîbW¼àã†À‰Ëá’½"\|€'( ‰’Rá®®PsRIK*Ï…¯TÚ›¨þ¶æ¾ø}¯~¡wŠÆ¤u×Ù¯wzåÕQÁÖÕîylÞüf¸Ãæ.qCü] {XÄF@®pW–âsxÄfý0Œe(ãO&&1Ð~k†Þò8µ¨ímg×0‰ &Eí‘WŒ5%È30ò‘ñ9ã)—ÑÊÑÃrµŒc.—ØËs—¿ÅdL~KÊ\.³Pœ|Û ÍSfíÄà

      Embedding Tcl in C/C++ Applications

      Presented At:
      The Tcl2K Conference
      Austin, Texas
      9:00am, February 15, 2000
        Instructor:
      D. Richard Hipp
      drh@hwaci.com
      http://www.hwaci.com/drh/
      704.948.4565

      Copies of these notes, example source code,
      and other resources related to this tutorial
      are available online at http://www.hwaci.com/tcl2k/

      $Id: index.html,v 1.1.1.1 2002/01/27 17:44:00 cvs Exp $



      Tutorial Outline

      • Introduction
      • Building It Yourself
        • "Hello, World!" using Tcl
        • Tcl scripts as C strings
        • Adding new Tcl commands
        • A tour of the Tcl API
        • Tcl initialization scripts
        • Adding Tk
      • Tools Survey
      • Mktclapp
        • "Hello World" using mktclapp
        • Adding C code
        • Other Features
        • Invoking Tcl from C
        • Running mktclapp directly
        • Real-world examples
      • Summary



      Embedding Tcl in C/C++ Applications

      • You know how to program in Tcl/Tk
      • You know how to program in C/C++
      • This tutorial is about how to do both at the same time.



      Why Mix C With Tcl/Tk?

      • Use C for the things C is good at and Tcl for the things Tcl is good at.
      • Generate standalone executables.
        • Eliminate the need to install Tcl/Tk.
        • Prevent problems when the wrong version of Tcl/Tk is installed.
      • Prevent end users from changing the source code.
        • Keeps users from creating new bugs.
        • Protects proprietary code.
      • Office politics
      • Use Tcl/Tk as a portability layer for a large C program
      • Use Tcl as a testing interface



      Why Mix C With Tcl/Tk?

      "Use C for the things C is good at and use Tcl/Tk for the things Tcl/Tk is good at."

      C is good at:
      • Speed
      • Complex data structures
      • Computation
      • Interacting with hardware
      • Byte-by-byte data analysis
        Tcl/Tk is good at:
      • Building a user interface
      • Manipulation of strings
      • Portability
      • Opening sockets
      • Handling events


      Programming Models

      Mainstream Tcl Programming Model:

       

      Embedded Tcl Programming Model:  

      • Add bits of C code to a large Tcl program
       
      • Add bits of Tcl code to a large C program
      • Main Tcl script loads extensions written in C
       
      • Main C procedure invokes the Tcl interpreter
      • Tcl/Tk is a programming language
       
      • Tcl/Tk is a C library

      Most of the Tcl2K conference is about
       

      This tutorial is about


      "Hello, World!" Using The Tcl Library

      #include <tcl.h>       Always include <tcl.h>
      int main(int argc, char **argv){
        Tcl_Interp *interp;
        interp = Tcl_CreateInterp();       Create a new Tcl interpreter
        Tcl_Eval(interp, "puts {Hello, World!}");       Execute a Tcl command.
        return 0;
      }


      Compiling "Hello, World!"

      Unix:

      $ gcc hello.c -ltcl -lm -ldl
      $ ./a.out
      Hello, World!

      Windows using Cygwin:

      C:> gcc hello.c -ltcl80 -lm
      C:> a.exe
      Hello, World!

      Windows using Mingw32:

      C:> gcc -mno-cygwin hello.c -ltcl82 -lm
      Also works with VC++



      Where Does -ltcl Come From On Unix?

      Build it yourself using these steps:

      • Get tcl8.2.2.tar.gz from Scriptics
      • zcat tcl8.2.2.tar.gz | tar vx
      • cd tcl8.2.2/unix
      • ./configure --disable-shared
      • make
      • Move libtcl8.2.a to your lib directory.
      • Copy ../generic/tcl.h into /usr/include.



      What Other Libraries Are Required For Unix?

      • The sequence of -l options after -ltcl varies from system to system
      • Observe what libraries the TCL makefile inserts when it is building tclsh
      • Examples in this talk are for RedHat Linux 6.0 for Intel



      How To Compile Under Unix Without Installing Tcl

      Specify the *.a file directly:

        $ gcc -I../tcl8.2.2/generic hello.c \ 
            ../tcl8.2.2/unix/libtcl8.2.a -lm -ldl
        $ strip a.out
        $ ./a.out
        Hello, World!

      Or, tell the C compiler where to look for *.a files:

        $ gcc -I../tcl8.2.2/generic hello.c \ 
            -L../tcl8.2.2/unix -ltcl -lm -ldl
        $ strip a.out
        $ ./a.out
        Hello, World!
      The -I../tcl8.2.2 argument tells the compiler where to find <tcl.h>.



      What's "Cygwin"?

      • An implementation of GCC/G++ and all development tools for Windows95/98/NT/2000
      • Available for free download at
        http://sourceware.cygnus.com/cygwin/
      • Also available shrink-wrapped at your local software retailer or online at
        http://www.cygnus.com/cygwin/index.html
      • Programs compiled using Cygwin require a special DLL (cygwin1.dll) that provides a POSIX system API
      • Cygwin1.dll cannot be shipped with proprietary programs without purchasing a license from Cygnus.
      • Mingw32 is the same compiler as Cygwin, but generates binaries that do not use cygwin1.dll



      Where Does -ltcl82 Come From On Windows?

      Build it like this:

      • Get tcl82.lib and tcl82.dll from Scriptics.
      • echo EXPORTS >tcl82.def
      • nm tcl82.lib | grep 'T _' | sed 's/.* T _//' >>tcl82.def
      • dlltool --def tcl82.def --dllname tcl82.dll --output-lib libtcl82.a
      • Move libtcl82.a to the lib directory and tcl82.dll to the bin directory.



      Where Does Your Code Go?

      #include <tcl.h>
       
      int main(int argc, char **argv){
        Tcl_Interp *interp;
        interp = Tcl_CreateInterp();
        /* Your application code goes here */       Insert C code here to do whatever it is your program is suppose to do
        return 0;
      }


      Building A Simple TCLSH

      #include <tcl.h>
       
      int main(int argc, char **argv){
        Tcl_Interp *interp;
        char *z;
        char zLine[2000];
        interp = Tcl_CreateInterp();
        while( fgets(zLine,sizeof(zLine),stdin) ){       Get one line of input
          Tcl_Eval(interp, zLine);       Execute the input as Tcl.
          z = Tcl_GetStringResult(interp);
          if( z[0] ){
            printf("¸üÿ¿PX¶\n", z);
          }
            Print result if not empty
        }
        return 0;
      }

      What if user types more than 2000 characters?



      Building A Simple TCLSH

      Use TCL to handle input. Allows input lines of unlimited length.

      #include <tcl.h>
       
      /* Tcl code to implement the
      ** input loop */
      static char zLoop[] = 
        "while {![eof stdin]} {\n"
        "  set line [gets stdin]\n"       Get one line of input
        "  set result [eval $line]\n"       Execute input as Tcl
        "  if {$result!=\"\"} {puts $result}\n"       Print result
        "}\n"
      ;
       

      int main(int argc, char **argv){
        Tcl_Interp *interp;
        interp = Tcl_CreateInterp();
        Tcl_Eval(interp, zLoop);       Run the Tcl input loop
        return 0;
      }

      But what about commands that span multiple lines of input?



      Better Handling Of Command-Line Input

      The file "input.tcl"

      set line {}
      while {![eof stdin]} {
        if {$line!=""} {
          puts -nonewline "> "
        } else {
          puts -nonewline "% "
        }
        flush stdout
            Prompt for user input. The prompt is normally "%" but changes to ">" if the current line is a continuation.
        append line [gets stdin]
        if {[info complete $line]} {
          if {[catch {uplevel #0 $line} result]} {       If the command is complete, execute it.
            puts stderr "Error: $result"
          } elseif {$result!=""} {
            puts $result
          }
          set line {}
        } else {
          append line \n
        }
            If the command is incomplete, append a newline and get another line of text.
      }


      Better Handling Of Command-Line Input

      The file "input.c"

      #include <tcl.h>
       
      int main(int argc, char **argv){
        Tcl_Interp *interp;
        interp = Tcl_CreateInterp();
        Tcl_Eval(interp, "source input.tcl");       Read and execute the input loop
        return 0;
      }

      But now the program is not standalone!



      Converting Scripts Into C Strings

      static char zInputLoop[] = 
        "set line {}\n"
        "while {![eof stdin]} {\n"
        "  if {$line!=\"\"} {\n"
        "    puts -nonewline \"> \"\n"
        "  } else {\n"
        "    puts -nonewline \"% \"\n"
        "  }\n"
        "  flush stdout\n"
        "  append line [gets stdin]\n"
        "  if {[info complete $line]} {\n"
        "    if {[catch {uplevel #0 $line} result]} {\n"
        "      puts stderr \"Error: $result\"\n"
        "    } elseif {$result!=\"\"} {\n"
        "      puts $result\n"
        "    }\n"
        "    set line {}\n"
        "  } else {\n"
        "    append line \\n\n"
        "  }\n"
        "}\n"
      ;


      Compile Tcl Scripts Into C Programs

      #include <tcl.h>

      static char zInputLoop[] = 
        /* Actual code omitted */
      ;
            Copy and paste the converted Tcl script here

      int main(int argc, char **argv){
        Tcl_Interp *interp;
        interp = Tcl_CreateInterp();
        Tcl_Eval(interp, zInputLoop);       Execute the Tcl code
        return 0;
      }


      Converting Scripts To Strings
      Using SED Or TCLSH

      sed -e 's/\\/\\\\/g' \        Convert \ into \\
        -e 's/"/\\"/g' \        Convert " into \"
        -e 's/^/  "/' \        Add " to start of each line
        -e 's/$/\\n"/' input.tcl       Add \n" to end of each line

       

       

      while {![eof stdin]} {
        set line [gets stdin]
        regsub -all {\} $line {&&} line       Convert \ into \\
        regsub -all {"} $line {\"} line       Convert " into \"
        puts "\"$line\\n\""       Add " in front and \n" at the end
      }


      Converting Scripts Into C Strings

      You may want to save space by removing comments and extra whitespace from scripts.

      static char zInputLoop[] = 
        "set line {}\n"
        "while {![eof stdin]} {\n"
        "if {$line!=\"\"} {\n"
        "puts -nonewline \"> \"\n"
        "} else {\n"
        "puts -nonewline \"% \"\n"
        "}\n"
        "flush stdout\n"
        "append line [gets stdin]\n"
        "if {[info complete $line]} {\n"
        "if {[catch {uplevel #0 $line} result]} {\n"
        "puts stderr \"Error: $result\"\n"
        "} elseif {$result!=\"\"} {\n"
        "puts $result\n"
        "}\n"
        "set line {}\n"
        "} else {\n"
        "append line \\n\n"
        "}\n"
        "}\n"
      ;


      Converting Scripts To Strings

      sed -e 's/\\/\\\\/g' \ 
        -e 's/"/\\"/g' \ 
        -e '/^ *#/d' \        Delete lines that begin with #
        -e '/^ *$/d' \        Delete blank lines
        -e 's/^ */  "/' \        Delete leading spaces
        -e 's/$/\\n"/' input.tcl
       

       

       
      while {![eof stdin]} {
        set line [gets stdin]
        set line [string trimleft $line]       Remove leading space
        if {$line==""} continue       Delete blank lines
        if {[string index $line 0]=="#"} {
          continue
        }
            Delete lines starting with #
        regsub -all {\} $line {&&} line
        regsub -all {"} $line {\"} line
        puts "\"$line\\n\""
      }


      Removing Comments Or Leading Space
      Will Break Some Tcl Scripts!

      image create bitmap smiley -data {
      #define smile_width 15
      #define smile_height 15
            These lines begin with # but are not comment
      static unsigned char smile_bits[] = {
         0xc0, 0x01, 0x30, 0x06, 0x0c, 0x18,
         0x04, 0x10, 0x22, 0x22, 0x52, 0x25,
         0x01, 0x40, 0x01, 0x40, 0x01, 0x40,
         0x12, 0x24, 0xe2, 0x23, 0x04, 0x10,
         0x0c, 0x18, 0x30, 0x06, 0xc0, 0x01};
      }
       

       
      text .t
      pack .t
      .t insert end [string trim {
      She walks in beauty, like the night
           Of cloudless climes and starry skies;
      And all that's best of dark and bright
           Meet in her aspect and her eyes;
            Indentation is deleted on lines 2 and 4
      }] 
       

      Problems like these are rare



      Adding A "continue" Command

      set line {}
      while {![eof stdin]} {
        if {$line!=""} {
          puts -nonewline "> "
        } else {
          puts -nonewline "% "
        }
        flush stdout
        append line [gets stdin]
        if {[info complete $line]} {
          if {[lindex $line 0]=="continue"} {
            break;
            Break out of the loop if the command is "continue"
          } elseif {[catch {uplevel #0 $line} result]} {
            puts stderr "Error: $result"
          } elseif {$result!=""} {
            puts $result
          }
          set line {}
        } else {
          append line \n
        }
      }


      Stop For Tcl Input At Various Points
      In A C Program

      #include <tcl.h>
       
      static char zInputLoop[] = 
        /* Tcl Input loop as a C string */
      ;
       
      int main(int argc, char **argv){
        Tcl_Interp *interp;
        interp = Tcl_CreateInterp();
        /* Application C code */       Do some computation
        Tcl_Eval(interp, zInputLoop);       Stop for some Tcl input
        /* More application C code */       Do more computation
        Tcl_Eval(interp, zInputLoop);       Stop for more Tcl input
        /* Finish up the application */       Finish the computation
        return 0;
      }


      Using Tcl For Testing

      #include <tcl.h>
       
      static char zInputLoop[] = 
        /* Tcl Input loop as a C string */
      ;
       
      int main(int argc, char **argv){
      #ifdef TESTING
        Tcl_Interp *interp;
            Create interpreter only if TESTING is defined
        interp = Tcl_CreateInterp();
      #endif
        /* Application C code */
      #ifdef TESTING
        Tcl_Eval(interp, zInputLoop);
      #endif
            Accept command-line input only if TESTING is defined
        /* More application C code */
      #ifdef TESTING
        Tcl_Eval(interp, zInputLoop);
      #endif
        /* Finish up the application */
        return 0;
      }


      Creating A New Tcl Command In C

      #include <tcl.h>
       
      int NewCmd(
        void *clientData,
        Tcl_Interp *interp,
        int argc,
        char **argv
            The Tcl command is implemented as a C function with four arguments.
      ){
        printf("Hello, World!\n");
        return TCL_OK;       Returns TCL_OK or TCL_ERROR
      }
       
      static char zInputLoop[] = 
        /* Tcl code omitted... */
      ;
       
      int main(int argc, char **argv){
        Tcl_Interp *interp;
        interp = Tcl_CreateInterp();
        Tcl_CreateCommand(interp, "helloworld",
                          NewCmd, 0, 0);
            Tell the interpreter which C function to call when the "helloworld" Tcl command is executed
        Tcl_Eval(interp, zInputLoop);
        return 0;
      }


      Linkage From Tcl To C

      • 3rd parameter of Tcl_CreateCommand() is a pointer to the C subroutine that implements the command.
      • 4th parameter to Tcl_CreateCommand() becomes the 1st parameter to the C routine whenever the Tcl command is executed.
      • 1st parameter to Tcl_CreateCommand() must be a valid Tcl interpreter. The same pointer appears as the second parameter to the C routine whenever the Tcl command is executed.



      Linkage From Tcl To C

      • 5th parameter of Tcl_CreateCommand() is a pointer to the C subroutine that is called when the Tcl command is deleted.
      • 4th parameter to Tcl_CreateCommand() becomes the 1st parameter to the C routine.



      When To Use A Delete Proc

      Examples of where the delete proc is used in standard Tcl/Tk:

      button .b -text Hello
      pack .b
      rename .b {}       Deleting the .b command causes the button to be destroyed

       
      image create photo smiley \ 
          -file smiley.gif
      rename smiley {}       Deleting the smiley command destroys the image and reclaims the memory used to hold the image

      • Always use a delete proc if the clientData is a pointer to malloced memory or some other resource that needs freeing
      • Delete procs are never used in the Tcl core but are used extensively in Tk



      Linkage From Tcl To C

      The argc and argv parameters work just like in main()

      helloworld one {two three} four       argc = 4
      argv[0] = "helloworld"
      argv[1] = "one"
      argv[2] = "two three"
      argv[3] = "four"
      argv[4] = NULL


      A Short-Cut

      In a program with many new Tcl commands implemented in C, it becomes tedious to type the same four parameters over and over again. So we define a short-cut.

      #define TCLARGS \ 
          void *clientData, \ 
          Tcl_Interp *interp, \ 
          int argc, \ 
          char *argv
            Define TCLARGS once in a header file
       
       
       
      int NewCmd(TCLARGS){       Use the TCLARGS macro to define new C functions that implement Tcl commands.
         /* implementation... */
      }

      For brevity, we will use the TCLARGS macro during the rest of this talk.



      Returning A Value From C Back To Tcl

      int NewCmd(TCLARGS){       Note that the C function returns an "int"
        return TCL_OK;       Return value is TCL_OK or TCL_ERROR
      }

      • TCL_OK and TCL_ERROR are defined in <tcl.h>
      • Other valid return values TCL_RETURN, TCL_BREAK and TCL_CONTINUE are rarely used
      • Common mistake: forgetting to return TCL_OK



      Returning A Value From C Back To Tcl

      int NewCmd(TCLARGS){
        Tcl_SetResult(interp,"Hello!",TCL_STATIC);       Set the result to "Hello!"
        return TCL_OK;
      }

      • Result should be the text of an error message if you return TCL_ERROR.
      • 3rd argument to Tcl_SetResult() can be TCL_STATIC, TCL_DYNAMIC, TCL_VOLATILE, or a function pointer.
      • Also consider using Tcl_AppendResult().
      • Direct access to interp->result is deprecated.
      • See the man pages for details.



      The Tcl_Obj Interface

      • A new way to write Tcl commands in C code
      • First introduced in Tcl8.0
      • Can be much faster, especially for lists or numeric values.
      • Able to handle arbitrary binary data.
      • More difficult to program.



      The Tcl_Obj Interface

      int NewObjCmd(
        void *clientData,
        Tcl_Interp *interp,
        int objc,
        Tcl_Obj *const* objv       4th parameter is an array Tcl_Objs, not an array of strings
      ){
        /* Implementation... */
        return TCL_OK;
      }
       
      static char zInputLoop[] = 
        /* Tcl code omitted... */
      ;
       
      int main(int argc, char **argv){
        Tcl_Interp *interp;
        interp = Tcl_CreateInterp();
        Tcl_CreateObjCommand(interp, "newcmd",
                             NewObjCmd, 0, 0);
            Use a different function to register the command
        Tcl_Eval(interp, zInputLoop);
        return 0;
      }


      The Tcl_Obj Interface

      • There are countless access methods for reading information from and placing information in Tcl_Objs. Always use the access methods.
      • Details provided at Lee Bernhard's talk this afternoon.
      • Definitely use Tcl_Objs if you are writing a new Tcl extension.
      • Tcl_Objs address some of the weaknesses of Tcl relative to C/C++.
        • Tcl_Objs are faster
        • Tcl_Objs work with binary data
        But C/C++ is faster still and better for working with binary data.
      • When mixing C/C++ with Tcl/Tk the benefits of Tcl_Objs are less important. Using Tcl_Objs in this context may not be worth the extra trouble.
      • This talk will focus on the string interface.



      Nickel Tour Of The Tcl API

      Memory allocation functions

      Tcl_Alloc
      Tcl_Free
      Tcl_Realloc

      Functions useful in the implementation of new Tcl commands

      Tcl_AppendElement
      Tcl_AppendResult
      Tcl_GetBoolean
      Tcl_GetDouble
      Tcl_GetInt
      Tcl_GetStringResult
      Tcl_ResetResult
      Tcl_SetResult

      Functions for controlling the Tcl interpreter

      Tcl_CreateCommand
      Tcl_CreateInterp
      Tcl_CreateObjCommand
      Tcl_DeleteCommand
      Tcl_DeleteInterp
      Tcl_Exit



      Nickel Tour Of The Tcl API

      I/O functions

      Tcl_Close
      Tcl_Eof
      Tcl_Flush
      Tcl_GetChannel
      Tcl_GetChannelMode
      Tcl_GetChannelName
      Tcl_Gets
      Tcl_OpenCommandChannel
      Tcl_OpenFileChannel
      Tcl_OpenTcpClient
      Tcl_OpenTcpServer
      Tcl_Read
      Tcl_Seek
      Tcl_Tell
      Tcl_Ungets
      Tcl_Write
      Tcl_WriteChars

      Names and meanings of system error codes

      Tcl_ErrnoId
      Tcl_ErrnoMsg
      Tcl_GetErrno
      Tcl_SetErrno
      Tcl_SignalId
      Tcl_SignalMsg



      Nickel Tour Of The Tcl API

      General Operating System Calls

      Tcl_Access
      Tcl_Chdir
      Tcl_GetCwd
      Tcl_GetHostName
      Tcl_GetNameOfExecutable
      Tcl_Sleep
      Tcl_Stat

      String Manipulation And Comparison

      Tcl_Concat
      Tcl_Merge
      Tcl_SplitList
      Tcl_StringCaseMatch
      Tcl_StringMatch

      Dynamically Resizable Strings

      Tcl_DStringAppend
      Tcl_DStringAppendElement
      Tcl_DStringEndSublist
      Tcl_DStringInit
      Tcl_DStringLength
      Tcl_DStringResult
      Tcl_DStringSetLength
      Tcl_DStringStartSublist
      Tcl_DStringValue



      Nickel Tour Of The Tcl API

      Event Handlers

      Tcl_CancelIdleCall
      Tcl_CreateChannelHandler
      Tcl_CreateTimerHandler
      Tcl_DeleteChannelHandler
      Tcl_DeleteTimerHandler
      Tcl_DoOneEvent
      Tcl_DoWhenIdle

      Functions For Reading And Writing Tcl Variables

      Tcl_GetVar
      Tcl_GetVar2
      Tcl_LinkVar
      Tcl_SetVar
      Tcl_SetVar2
      Tcl_TraceVar
      Tcl_TraceVar2
      Tcl_UnlinkVar
      Tcl_UnsetVar
      Tcl_UnsetVar2
      Tcl_UntraceVar
      Tcl_UntraceVar2
      Tcl_UpdateLinkedVar

      Functions For Executing Tcl Code

      Tcl_Eval
      Tcl_EvalFile
      Tcl_EvalObj
      Tcl_GlobalEval
      Tcl_GlobalEvalObj
      Tcl_VarEval



      Nickel Tour Of The Tcl API

      Functions For Dealing With Unicode

      Tcl_NumUtfChars
      Tcl_UniCharAtIndex
      Tcl_UniCharIsAlnum
      Tcl_UniCharIsAlpha
      Tcl_UniCharIsControl
      Tcl_UniCharIsDigit
      Tcl_UniCharIsGraph
      Tcl_UniCharIsLower
      Tcl_UniCharIsPrint
      Tcl_UniCharIsPunct
      Tcl_UniCharIsSpace
      Tcl_UniCharIsUpper
      Tcl_UniCharIsWordChar
      Tcl_UniCharLen
      Tcl_UniCharNcmp
      Tcl_UniCharToLower
      Tcl_UniCharToTitle
      Tcl_UniCharToUpper
      Tcl_UniCharToUtf
      Tcl_UniCharToUtfDString
      Tcl_UtfAtIndex
      Tcl_UtfBackslash
      Tcl_UtfCharComplete
      Tcl_UtfFindFirst
      Tcl_UtfFindLast
      Tcl_UtfNcasecmp
      Tcl_UtfNcmp
      Tcl_UtfNext
      Tcl_UtfPrev
      Tcl_UtfToLower
      Tcl_UtfToTitle
      Tcl_UtfToUniChar
      Tcl_UtfToUniCharDString
      Tcl_UtfToUpper

      Functions For Dealing With Tcl_Objs

      Too numerous to list...



      Documentation Of The Tcl API

      • Tcl comes with excellent man pages
      • "Use the source, Luke"
      • See tclDecl.h for a list of API functions
      • The header comments on the implementation of API functions usually gives a good description of what the function does and how it should be used.
      • Most API functions are used within Tcl and Tk. Use grep to locate examples.



      Initialization Scripts

      • Run the mini TCLSH implemented above and execute the parray command
      • It doesn't work! What's wrong?

      • parray is really a Tcl proc that is read in when the interpreter is initialized.

      • parray (and several other commands) are stored in a handful of "Initialization Scripts"

      • All the initialization scripts are stored in the "Tcl Library" - a directory on the host computer.

      Invoke the Tcl_Init() function to locate and read the Tcl initialization scripts.



      The Tcl_Init() Function

      #include <tcl.h>
       
      static char zInputLoop[] = 
        /* Tcl code omitted... */
      ;
       
      int main(int argc, char **argv){
        Tcl_Interp *interp;
        interp = Tcl_CreateInterp();
        Tcl_Init(interp);       Locate and read the initialization scripts
        /* Call Tcl_CreateCommand()? */
        Tcl_Eval(interp, zInputLoop);
        return 0;
      }

      But Tcl_Init() can fail. We need to check its return value...



      The Tcl_Init() Function

      #include <tcl.h>
       
      static char zInputLoop[] = 
        /* Tcl code omitted... */
      ;
       
      int main(int argc, char **argv){
        Tcl_Interp *interp;
        interp = Tcl_CreateInterp();
        if( Tcl_Init(interp)!=TCL_OK ){
          fprintf(stderr,"Tcl_Init() failed: ¸üÿ¿PX¶",
             Tcl_GetStringResult(interp));
        }
            Print error message if Tcl_Init() fails
        /* Call Tcl_CreateCommand()? */
        Tcl_Eval(interp, zInputLoop);
        return 0;
      }

      But now the program is not standalone.



      How Tcl_Init() Works

      • Computes the value of variable tcl_libPath.
      • Invokes the procedure named "tclInit"
      • A default tclInit procedure is built into Tcl. You can define an alternative tclInit procedure prior to calling Tcl_Init().



      The Default initTcl Procedure

      set errors {}
      set dirs {}
      if {[info exists tcl_library]} {
        lappend dirs $tcl_library
      } else {
        if {[info exists env(TCL_LIBRARY)]} {
          lappend dirs $env(TCL_LIBRARY)
        }
        lappend dirs $tclDefaultLibrary
        unset tclDefaultLibrary
        set dirs [concat $dirs $tcl_libPath]
      }
      foreach i $dirs {
        set tcl_library $i
        set tclfile [file join $i init.tcl]
        if {[file exists $tclfile]} {
          if {![catch {uplevel #0 [list source $tclfile]} msg]} {
            return
          } else {
            append errors "$tclfile: $msg\n$errorInfo\n"
          }
        }
      }
      error "Can't find a usable init.tcl ..."


      The Default Initialization Sequence

      • The tclInit procedure locates and sources the init.tcl script. The directory that contains init.tcl is stored in the tcl_library variable.
      • The init.tcl script creates an unknown procedure. The unknown procedure will run whenever Tcl encounters an unknown command.
      • The unknown procedure consults the file tclIndex in the tcl_library directory to see if the command is defined by one of the initialization scripts.
      • The unknown procedure sources any needed initialization scripts and retries the command.
      Commands defined in the initialization scripts are loaded on demand.



      Standalone Initialization Techniques

      Manually execute all initialization scripts

      • Convert all initialization scripts into C strings and put them in the executable.
      • Call Tcl_Eval() on each initialization script and omit the call to Tcl_Init()
      • Or, redefine tclInit so that it does not attempt to source init.tcl then call Tcl_Eval() on each initialization script after Tcl_Init() returns.
      This approach is not recommended



      Standalone Initialization Techniques

      Redefining the builtin source command

      • Convert all initialization scripts into C strings and put them in the executable.
      • Create a new source command that calls Tcl_Eval() on the appropriate built-in string instead of reading from the disk.
      • Read from disk if the named file is not one that is built in.



      Redefining source

      static char zInitTcl[] = "...";
      static char zParrayTcl[] = "...";
            Scripts init.tcl and parray.tcl

      int NewSourceCmd(TCLARGS){
        if( !strcmp(argv[1],"/builtin/init.tcl") )
          return Tcl_Eval(interp, zInitTcl);
        if( !strcmp(argv[1],"/builtin/parray.tcl") )
          return Tcl_Eval(interp, zParrayTcl);
            Call Tcl_Eval() on builtin strings if the names match
        return Tcl_EvalFile(interp, argv[1]);       Call Tcl_EvalFile() if no match
      }
       
      int main(int argc, char **argv){
        Tcl_Interp *interp;
        setenv("TCL_LIBRARY","/builtin");       Causes tclInit to look for init.tcl in /builtin
        interp = Tcl_CreateInterp();
        Tcl_CreateCommand(interp, "source",
                          NewSourceCmd, 0, 0);
            Redefine source
        Tcl_Init(interp);
        Tcl_Eval(interp, zInputLoop);
        return 0;
      }


      Redefining source

      • This approach works for all versions of Tcl and Tk.
      • Also need to redefine the "file exists" Tcl command since it too is used by tclInit.
      • To verify that the program is really standalone, remove the call to Tcl_EvalFile().



      Standalone Initialization Techniques

      Use the Tcl*InsertProc() functions

      • Three routines that overload basic file I/O operations:
        • TclStatInsertProc()
        • TclAccessInsertProc()
        • TclOpenFileChannelInsertProc()
      • Allows us to implement a virtual filesystem that overlays the real filesystem.
      • The virtual filesystem contains all the initialization scripts as compiled-in strings. The initialization scripts look like they are resident on disk even though they are built in.
      • These functions first appeared in Tcl8.0.3. Presumably to support TclPro Wrapper.
      • The only documentation is comments on the code. See the Tcl source file generic/tclIOUtil.c



      The TclStatInsertProc() Function

      • Sole argument is a pointer to a function whose interface is the same as stat()
      • Functions are stacked. Tcl tries each stat function on the list, beginning with the most recently inserted, until one succeeds.



      The TclStatInsertProc() Function

      #include <tclInt.h>       Rather than <tcl.h>!

      static int
      BltinFileStat(char *path,struct stat *buf){
        char *zData;
        int nData;
        zData = FindBuiltinFile(path, 0, &nData);       Check if path is a builtin
        if( zData==0 ){
          return -1;
        }
            Fail if path is not a builtin
        memset(buf, 0, sizeof(*buf));
        buf->st_mode = 0400;
        buf->st_size = nData;
        return 0;       Success if it is builtin
      }
       
      int main(int argc, char **argv){
        Tcl_Interp *interp;
        TclStatInsertProc(BltinFileStat);       Register new stat function
        interp = Tcl_CreateInterp();
        Tcl_Init(interp);
        Tcl_Eval(interp, zInputLoop);
        return 0;
      }


      The TclAccessInsertProc() Function

      #include <tclInt.h>       Rather than <tcl.h>!

      /* BltinFileStat() not shown... */
       
      static int
      BltinFileAccess(char *path, int mode){
        char *zData;
        if( mode & 3 ) return -1;       All builtins are read-only
        zData = FindBuiltinFile(path, 0, &nData);       Check if path is a builtin
        if( zData==0 ) return -1;       Fail if path is not a builtin
        return 0;       Success if it is builtin
      }
       
      int main(int argc, char **argv){
        Tcl_Interp *interp;
        TclStatInsertProc(BltinFileStat);
        TclAccessInsertProc(BltinFileAccess);
            Register new stat and access functions
        interp = Tcl_CreateInterp();
        Tcl_Init(interp);
        Tcl_Eval(interp, zInputLoop);
        return 0;
      }


      The TclOpenFileChannelInsertProc() Function

      static Tcl_Channel BuiltinFileOpen(
        Tcl_Interp *interp,   /* The TCL interpreter doing the open */
        char *zFilename,      /* Name of the file to open */
        char *modeString,     /* Mode string for the open (ignored) */
        int permissions       /* Permissions for a newly created file (ignored) */
      ){
        char *zData;
        BuiltinFileStruct *p;
        int nData;
        char zName[50];
        Tcl_Channel chan;
        static int count = 1;
       
        zData = FindBuiltinFile(zFilename, 1, &nData);
        if( zData==0 ) return NULL;
        p = (BuiltinFileStruct*)Tcl_Alloc( sizeof(BuiltinFileStruct) );
        if( p==0 ) return NULL;
        p->zData = zData;
        p->nData = nData;
        p->cursor = 0;
        sprintf(zName,"etbi_bffffc7c_8049b04",((int)BuiltinFileOpen)>>12,count++);
        chan = Tcl_CreateChannel(&builtinChannelType, zName, 
                                 (ClientData)p, TCL_READABLE);
        return chan;
      }


      The TclOpenFileChannelInsertProc() Function

      static Tcl_ChannelType builtinChannelType = {
        "builtin",          /* Type name. */
        NULL,               /* Always non-blocking.*/
        BuiltinFileClose,   /* Close proc. */
        BuiltinFileInput,   /* Input proc. */
        BuiltinFileOutput,  /* Output proc. */
        BuiltinFileSeek,    /* Seek proc. */
        NULL,               /* Set option proc. */
        NULL,               /* Get option proc. */
        BuiltinFileWatch,   /* Watch for events on console. */
        BuiltinFileHandle,  /* Get a handle from the device. */
      };

      For additional information see:

      • The man page for Tcl_CreateChannel()
      • Tk source code file generic/tkConsole.c



      Initializing Tk

      • All the same initialization script issues as Tcl
      • Tk initialization scripts are in a different directory than the Tcl initialization scripts - the "Tk Library"
      • Call Tk_Init() after Tcl_Init()
      • Must have an event loop or Tk will not work!



      Implementing An Event Loop

      button .b -text Hello -command exit
      pack .b
            Create a Tk interface

      bind . <Destroy> {
        if {![winfo exists .]} exit
      }
            Close the application when the main window is destroyed

      while 1 {vwait forever}       The event loop


      "Hello, World!" Using Tk

      #include <tk.h>
       
      static char zHello[] =        The application code
        "button .b "
          "-text {Hello, World} "
          "-command exit\n"
        "pack .b\n";
       
      static char zEventLoop[] =       The event loop
        "bind . <Destroy> {\n"
        "  if {![winfo exists .]} exit\n"
        "}\n"
        "while 1 {vwait forever}\n";
       

      int main(int argc, char **argv){
        Tcl_Interp *interp;
        interp = Tcl_CreateInterp();
        Tcl_Init(interp);
        Tk_Init(interp);
            We really should check the return values of the init functions...
        Tcl_Eval(interp, zHello);
        Tcl_Eval(interp, zEventLoop);       The event loop never returns
        /*NOTREACHED*/
      }


      Compiling "Hello, World!" For Tk

      Unix:

        $ gcc hello.c -ltk -L/usr/X11R6/lib \ 
              -lX11 -ltcl -lm -ldl
        $ ./a.out

      Windows using Cygwin:

        C:> gcc hello.c -mwindows -ltk80 -ltcl80 -lm
        C:> a.exe

      Windows using Mingw32:

        C:> gcc -mno-cygwin hello.c -mwindows \ 
                 -ltk82 -ltcl82 -lm
        C:> a.exe



      Making The Program Standalone

      To make a Tcl application standalone you have to convert the following initialization scripts to C strings and compile them into the executable:

        auto.tcl
        history.tcl
        init.tcl
        ldAout.tcl
        package.tcl
        parray.tcl
        safe.tcl
        tclIndex
        word.tcl

      To make a Tk application standalone requires these additional initialization scripts from the Tk Library:

        bgerror.tcl
        button.tcl
        clrpick.tcl
        comdlg.tcl
        console.tcl
        dialog.tcl
        entry.tcl
        focus.tcl
        listbox.tcl
        menu.tcl
        msgbox.tcl
        optMenu.tcl
        palette.tcl
        safetk.tcl
        scale.tcl
        scrlbar.tcl
        tclIndex
        tearoff.tcl
        text.tcl
        tk.tcl
        tkfbox.tcl
        xmfbox.tcl

      Total of about 13K lines and 400K bytes of text or 9K lines and 250K bytes if you strip comments and leading spaces



      A Review Of The Features We Want

      1. Combine C/C++ with Tcl/Tk into a single executable.
      1. The executable should be standalone. It must not depend on files not normally found on the system.
      1. It should be difficult for end users to alter the program (and introduce bugs).



      Available Programming Aids

      Several tools are available. The chart below shows which tools help achieve which objectives.

      Features The Tool Helps To Achieve
      Tool Name Mix C and Tcl Standalone Hide Source
      SWIG    
      TclPro Wrapper  
      FreeWrap  
      Wrap    
      mktclapp



      SWIG

      • Creates an interface between an existing C/C++ library and a high-level programming language. Support for:
        • Tcl/Tk
        • Perl
        • Python
        • Java
        • Eiffel
        • Guile
      • No changes required to C/C++ code. Can be used with legacy libraries.
      • Generates an extension, not a standalone binary
      • The tutorial on SWIG was yesterday afternoon.
      • http://www.swig.org/



      Wrapper Programs

      • Convert a pure Tcl/Tk program into a standalone binary
      • Several wrapper programs are available:
        • TclPro Wrapper - http://www.scriptics.com/
        • FreeWrap - http://www.albany.net/~dlabelle/freewrap/freewrap.html
        • Wrap - http://members1.chello.nl/~j.nijtmans/wrap.html
      • No C compiler required!
      • TclPro will convert Tcl script into bytecode so that it cannot be easily read by the end user. FreeWrap encrypts the scripts.
      • FreeWrap uses compression on its executable. Wrap uses compression on both the executable and on the bundled script files.
      • Usually include extensions like winico and/or BLT



      mktclapp

      • Mix C/C++ with Tcl/Tk into a standalone binary
      • mktclapp generates an application initialization file that contains Tcl scripts as strings and makes all necessary calls to Tcl_Init, Tcl_CreateCommand, Tcl*InsertProc, etc.
      • Features to make it easier to write new Tcl command in C
      • xmktclapp.tcl provides a GUI interface to mktclapp
      • http://www.hwaci.com/sw/mktclapp/



      "Hello, World!" Using Mktclapp

      • Download mktclapp.c and xmktclapp.tcl from http://www.hwaci.com/sw/mktclapp/
      • Compile mktclapp:
          cc -o mktclapp mktclapp.c
          
      • Create "Hello, World!" as a Tcl script in file hw.tcl:
          button .b -text {Hello, World!} -command exit
          pack .b
          
      • Launch xmktclapp:
          wish xmktclapp.tcl
          



      "Hello, World!" Using Mktclapp

      • Set "Command Line Input?" to "None"
      • Set "Standalone?" to "Yes"
      • Enter "hw.mta" for the Configuration File
      • Enter "hw.c" for the Output C File



      "Hello, World!" Using Mktclapp

      • Go to the "Tcl Scripts" page
      • Press "Insert" and add hw.tcl to the list of Tcl scripts
      • Change the "Startup Script" to be hw.tcl.
      • Select File/Build and File/Exit



      "Hello, World!" Using Mktclapp

      • Mktclapp generates hw.c. Compile it something like this:
          cc hw.c -ltk -L/usr/X11R6/lib -lX11 -ltcl -lm -ldl
          
      • Or, if using Cygwin:
          gcc hw.c -mwindows -ltk80 -ltcl80 -lm
          
      • Or, if using Mingw32:
          gcc -mno-cygwin hw.c -mwindows -ltk82 -ltcl82 -lm
          
      • And you're done!



      Adding C Code To Your Program

      Put the new C code in a new source file named "add.c"

      #include "hw.h"       Generated by mktclapp
      int ET_COMMAND_add(ET_TCLARGS){       ET_TCLARGS is a macro defined in hw.h
        int a, b;
        char zResult[30];
        a = atoi(argv[1]);
        b = atoi(argv[2]);
        sprintf(zResult, "-1073742724", a+b);
        Tcl_SetResult(interp, zResult, TCL_VOLATILE);
        return TCL_OK;
      }


      Adding C Code To Your Program

      • Go to the "C/C++ Modules" page of xmktclapp.tcl
      • Press "Insert" and add add.c to the list of C/C++ modules

      • Select File/Build and File/Exit



      Adding C Code To Your Program

      • Compile as follows:
          cc add.c hw.c -ltk -L/usr/X11R6/lib -ltcl -lm -ldl
          
      • Or construct a Makefile that compiles add.c into add.o and hw.c into hw.o and then links them.
      • Compile the same way for Windows except use the usual Windows libraries and options...
      Don't have to worry with Tcl_CreateCommand() - Mktclapp takes care of that automatically.



      Checking Parameters In The add Command

      Modify add.c to insure the add command is called with exactly two integer arguments

      #include "hw.h"
       
      int ET_COMMAND_add(ET_TCLARGS){
        int a, b;
        char zResult[30];
        if( argc!=3 ){
          Tcl_AppendResult(interp,
            "wrong # args: should be: \"",
            argv[0], " VALUE VALUE\"", 0);
          return TCL_ERROR;
        }
            Report an error if there are not exactly 2 arguments
        if( Tcl_GetInt(interp, argv[1], &a)!=TCL_OK ){
          return TCL_ERROR;
        }
            Report an error if the first argument is not an integer
        if( Tcl_GetInt(interp, argv[2], &b)!=TCL_OK ){
          return TCL_ERROR;
        }
            Do the same for the second argument
        sprintf(zResult, "-1073742724", a+b);
        Tcl_SetResult(interp, zResult, TCL_VOLATILE);
        return TCL_OK;
      }


      Using The Tcl_Obj Interface

      In the file objadd.c put this code:

      #include "hw.h"

      int ET_OBJCOMMAND_add2(ET_OBJARGS){
        int a, b;
            Use "ET_OBJCOMMAND" instead of "ET_COMMAND" and "ET_OBJARGS" instead of "ET_TCLARGS"
        if( objc!=3 ){
          Tcl_WrongNumArgs(interp, 1, objv,
            "number number");
          return TCL_ERROR;
        }
            A special routine for "wrong # args" error
        if( Tcl_GetIntFromObj(interp, objv[1], &a) ){       Instead of Tcl_GetInt
          return TCL_ERROR;
        }
        if( Tcl_GetIntFromObj(interp, objv[2], &b) ){
          return TCL_ERROR;
        }
        Tcl_SetIntObj(Tcl_GetObjResult(interp), a+b);       Result stored as integer, not a string
        return TCL_OK;
      }


      Speed Of Tcl_Obj Versus "char*" Interfaces

      • Compile both add and add2 into the same executable.
      • Compare their speeds:
           time {add 123456 654321} 10000
          26 microseconds per iteration
           time {add2 123456 654321} 10000
          4 microseconds per iteration
          
      • The Tcl_Obj version is 650 faster!
      • Replace the addition with a "real" computation that takes 10 milliseconds.
      • Now the Tcl_Obj version is only 0.2 faster!
      In many real-world problems, the Tcl_Obj interface has no noticeable speed advantage over the string interface.



      More About Built-in Tcl Scripts

      • Comments and leading white-space are removed from the script by default. Use the "Don't Strip Comments" button to change this.
      • The file name must exactly match the name that is used by the source command.



      Locations Of Libraries

      • Tells mktclapp where to look for script libraries.
      • All Tcl scripts in the indicated directories are compiled into the appinit.c file.
      • Comments and extra white-space are removed. There is no way to turn this off.



      Built-in Binary Data Files

      • Arbitrary files become part of the virtual filesystem
      • No comment or white-space removal is attempted
      • Useful for images or other binary data



      New Commands In Namespaces

      Two underscores (__) are replaced by two colons (::) in command names, thus giving the ability to define new commands in a namespace

      #include <hw.h>

      int ET_COMMAND_adder__add(ET_TCLARGS){
        int a, b;
            Creates the Tcl command called "adder::add"
        char *zResult[30];
        if( argc!=3 ){
          Tcl_AppendResult(interp,
            "wrong # args: should be: \"",
            argv[0], " VALUE VALUE\"", 0);
          return TCL_ERROR;
        }
        if( Tcl_GetInt(interp, argv[1], &a)!=TCL_OK ){
          return TCL_ERROR;
        }
        if( Tcl_GetInt(interp, argv[1], &b)!=TCL_OK ){
          return TCL_ERROR;
        }
        sprintf(zResult, "-1073742724", a+b);
        Tcl_SetResult(interp, zResult, TCL_VOLATILE);
        return TCL_OK;
      }


      Adding Your Own main()

      int main(int argc, char **argv){
        /* Application specific initialization */
        Et_Init(argc, argv);       Never returns!
        /*NOTREACHED*/
        return 0;
      }

      The "Autofork" feature is disabled if you supply your own main()



      Initializing The Tcl Interpreter

      #include <tcl.h>
       
      int counter = 0;
       
      int main(int argc, char **argv){
         Et_Init(argc, argv);
         /*NOTREACHED*/
         return 0;
      }
       
      int Et_AppInit(Tcl_Interp *interp){
        if( Blt_Init(Interp) ){
          return TCL_ERROR;
        }
            Example: Initialize an extension
        Tcl_LinkVar(interp, "counter", &counter,
                    TCL_LINK_INT);
            Or link a C variable to a Tcl variable
        return TCL_OK;       Return TCL_OK if successful
      }


      Writing Your Own Event Loop

      #include <tcl.h>
      void Et_CustomMainLoop(Tcl_Interp *interp){       Replaces the default event loop
        return;       Ex: Return without handling any events.
      }
       
      int main(int argc, char **argv){
        Et_Init(argc, argv);       This now returns after initializing Tcl
        /* Application code here */
        return 0;
      }


      Writing Your Own Event Loop

      #include <tcl.h>
       
      void Et_CustomMainLoop(Tcl_Interp *interp){
        for(;;){
          Tcl_DoOneEvent(TCL_ALL_EVENTS|TCL_DONT_WAIT);
          /* Other processing... */
        }
            Intermix processing and event handling
      }
       
      int main(int argc, char **argv){
        Et_Init(argc, argv);       Never returns
        /*NOTREACHED*/
        return 0;
      }


      Mktclapp Initialization Sequence

      • Initialization starts when the Et_Init() function is called either by client code or by the main() that mktclapp generates
      • Create the main Tcl interpreter
      • Construct the virtual filesystem overlay by redefining the source command and by using the Tcl*InsertProc() functions
      • Call Et_PreInit() if the client defines it
      • Call Tcl_Init() and Tk_Init()
      • Call Tcl_CreateCommand() and Tcl_CreateObjCommand() for every ET_COMMAND_* and ET_OBJCOMMAND_* function in the client code
      • Call Et_AppInit() if the client defines it
      • Run the main Tcl script if there is one
      • Call Et_CustomMainLoop() if defined by client code or else run the built-in event loop



      Invoking Tcl From C

      • Use one of the built-in evaluation functions:
        • Tcl_Eval()
        • Tcl_VarEval()
        • Tcl_EvalFile()
        • Tcl_GlobalEval()
        • Tcl_EvalObj()
        • Tcl_GlobalEvalObj()
      • Mktclapp provides evaluation functions with variable argument lists as in printf():
        • Et_EvalF()
        • Et_GlobalEvalF()
      • Mktclapp provides a global variable Et_Interp which is a pointer to the main interpreter



      Invoking Tcl From C

      Example: A C function that pops up an error message dialog box

      #include "appinit.h"
       
      void ErrMsg(char *zMsg){
        Tcl_SetVar(Et_Interp, "zMsg", zMsg, TCL_GLOBAL_ONLY);
        Tcl_GlobalEval(Et_Interp, 
          "tk_messageBox -icon error -msg $zMsg -type ok");
        Tcl_UnsetVar(Et_Interp, "zMsg", TCL_GLOBAL_ONLY);
      }


      Invoking Tcl From C

      The same C function implemented using Et_EvalF() instead of Tcl_GlobalEval()

      #include "appinit.h"
       
      void ErrMsg(char *zMsg){
        Et_EvalF(Et_Interp, 
          "tk_messageBox -icon error -msg {¸üÿ¿PX¶} -type ok",
          zMsg);
      }

      • Suppose the function is called as follows:
        ErrMsg("Syntax error near \"}\"");
      • The command that gets executed is:
            tk_messageBox -icon error -msg \ 
                {Syntax error near "}"} -type ok
          
      • But this is an ill-formed Tcl command!



      Invoking Tcl From C

      Use the "" format to generate a quoted string

      #include "appinit.h"
       
      void ErrMsg(char *zMsg){
        Et_EvalF(Et_Interp, 
          "tk_messageBox -icon error -msg \"%\" -type ok",
          zMsg);
      }

      • The puts a backslash before all characters that are special to Tcl
      • The Tcl command becomes:
            tk_messageBox -icon error -msg \ 
                "Syntax error near \"\}\"" -type ok
          



      Other Functions Provided By Mktclapp

      • void Et_ResultF(Tcl_Interp*, ...);
      • char *Et_DStringAppendF(Tcl_DString*, ...);
      • int Et_AppendObjF(Tcl_Obj*, ...);
      • char *mprintf(const char *format, ...);
        char *vmprintf(const char *format, va_list);
      • void Et_NewBuiltinFile(char *filename, char *data, int amt);



      Operating Mktclapp From The Command Line

      • Generate the appinit.h header file like this:
        mktclapp -header >appinit.h
      • Generate the appinit.c file like this:
        mktclapp -f appinit.mta >appinit.c
      • The *.mta file is just a list of command-line options
      • Enter
        mktclapp -help
        to get a list of available options
      • Look at MTA files generated by xmktclapp.tcl for examples



      Format Of An MTA File

      # Configuration file generated by xmktclapp
      # Hand editing is not recommended
      #
            Comments begin with one #
      ## Autofork No
      ## CFile:add.c 1
      ## CFile:objadd.c 1
      ## CmdLine Console
      ## ConfigFile hw.mta
      ## Data:check.gif 1
      ## MainScript hw.tcl
      ## Mode Tcl/Tk
      ## NoSource No
      ## OutputFile hw.c
      ## Shroud No
      ## Standalone Yes
      ## TclFile:hw.tcl 1
      ## TclLib /usr/lib/tcl8.0
      ## TkLib /usr/lib/tk8.0
            Lines beginning with two #s are used by xmktclapp.tcl and ignored by mktclapp
      -console
      -main-script "hw.tcl"
      -tcl-library "/usr/lib/tcl8.0"
      -tk-library "/usr/lib/tk8.0"
      "add.c"
      "objadd.c"
      -i "check.gif"
      -strip-tcl "hw.tcl"
            All other lines are read by mktclapp and ignored by xmktclapp.tcl


      Summary

      • Use Tcl for the things Tcl is good at and use C/C++ for the things that C/C++ is good at
      • Use wrapper programs to make pure Tcl programs standalone
      • Use mktclapp to combine Tcl/Tk with C/C++ into a standalone



      tkHTML-4ee7aaa953d6cb59/tests/page4000075500000000000000000000000001151224263100162005ustar00nobodynobodytkHTML-4ee7aaa953d6cb59/tests/page4/image1000064400000000000000000000000521151224263100173420ustar00nobodynobodyGIF89að!ù,;tkHTML-4ee7aaa953d6cb59/tests/page4/image2000064400000000000000000000340071151224263100173520ustar00nobodynobodyGIF89aÔ<Õ*!!!!)))))1Z11111R999BBBR9RRRcZ”cccsssss„„„„”””œœœ¥{­­­µµµ½­­½½½Æ”ÆÆÆÎ)ÎÎÎÖÖÖÞ­!ÞÞÖÞÞÞçççïïï÷µ÷Ö)÷÷÷ÿÿÿtsutsu!ÿ NETSCAPE2.0!ùP?,Ô<þH° Áƒ*\Ȱ¡Ã‡#JœH±¢Å‹3jÜȱ£Ç CŠI²¤É“(Sª\ɲ¥Ë—0cÊœI³¦Í›8sêÜɳ§ÏŸ@ƒ J´¨Ñ£H“*]Ê´©Ó§P£JJµ*Ê (0`+Ö¬ŠK¶lCY(àʶkµjU<0K·®Ý¦hÕ¶õÊ·­Ú*î L8çV­\½ðÊuqâ¶æžL¹²Ék3v˹­cÌ–C‹móÞÓ›ÿE¼•´ë×° šîKû1g*$Èí»·ï³m7¦Ý·… r,îú»¹s²z9×ÖìW… ²¶}ν;ÔÌÔ7þ§°0öìÑ„õξ=Qµãm¦ 8{ZÖÜëßÏóüÎÇU^™yÆßÒÄÚxâ œt‰­—à„ž”Ù|.‡ZxmqUᇠz„ƒ¶§a€†¨âŠE—!‰0n¶‹4ÖÈPVÓ}& €‡-¸c~6)$ÚÑ]ƒÒÁ…£ƒoíYd‚ô¤dM9ä•-IžW9È%`‘¡••Ž|íT™%P š%$Ä&–pNTä[õ=@€–¡uÜ|Z`§¶¦›j~ô&B‡Æ©hCZªÀç~ÂW¢>Z‚Z‘h&š…z”¨AVŽd]˜^”Û©º)ðÒ¨¥*tj”þছ@¼*P}ª&$k§¡Je}r1´«@¶VyÜu`Édr¹BTäTŠ\‰@ké™|J€ä€ƒrªVÖe«@˪Ь@‡~&‘Oô¤ªÆi+[¸s…j lž;›lZ0®Iø¢©¯Ahª@ÁD¢œÉë@[Л D1C£{æ¿ð[Âÿ¦0¡-éhÃh~ÀÚb tìñÇø¨ØÀ4‘ŒÐ æ(÷+á¡.V¢hbÇo® ô\‚£Ø"„²Ÿ!?”²Ò «ôt² !,›À]zh"àê™3tt¬/-r—0.ÎVôKLÝ´³kµŒmþÏ`17𤦬‚Œ\vëðÍ/®žÒiðfÐ ·Ý¦ä—Íxã%íp³»JW­X¤ðâdÔ9¹j™ž:êÍ‚›Ý@˜i…›Z(gëê±çª5A(¦4VhÂ^'Äd 4k\;ø¢\1­u¶_Ûãºü5óJyn¡ÇŽ™¹¹«®ôÜÃßìp ÀÁCt~à `¶ J€¦Ô÷4µ‡žæA<óÖßž72PqlYä$g1Á) mœz@ÏžW~Iì€ÞrÜÇ\6°Ñ1¬t<Áv&UÕícÄâWä"v¦ XPƒnKØ¥¨gë±Scž Ã0¥iï þ{›aÇ\ˆB¾ÐˆeÛñ°5Ù0na,,AÌvÂŽ [<$[ Õ“ºFä-w‚ÔVŽW»Ø`dàŠn\¦2%O&6+ÈßÊÖ5®õ isƒ!¿ÔD´°‘ðLFœ!‹XÁ~}pƒ\S!™Ø3í9/hh9“öþ¸U[rCáÓôB„Á-‰í“#¶f¿Kñ’qóâï¸È4ï„éû£Ÿ–—C%ÒêrþÈÕh¹Ç:þï“2Ô™*{9 =L!Z‘àà°F‡a&+¥´[ž„2m…ç1‰#AFöC_þ/QU|^â(¨Ç’ܤUÊXÆ¿…Åz0¼à"s¼öÁ³aþƒœ/ò¼Cf²Ë“åÉÒÁp\7DYùTBêÒa=À‘‡ª¡} g ûž÷ÌXõ‰44È‚¸`Þªih\0GØÏÚ¥t›Ø›D֢̭@ n`!À_$YœS§I9ÑæKÐMcêq= ¥\Í9¹r2’äZçAP&¶Æ’kˆb"©’eÕ¦q°…%l(_–ƒ> 4æA§z1’Æ0qK‹¦@¬wE‹‚ [(¼[¬ãC®UWL+á&ß”Ã(Ô p-« yw&™Î3b´éÁt´4Ìšqfeä¿ó J-R=d *CAöë†1tªjß”Ð4ê“­%PþUWóÊyVm‰e‹%û\@—I¦h¤:Öäj؆®U­¶œ+›&™6à^g«Äu™ÑæÕ’6­Š~:¥_“-¢ž´±=<Ö±üŠ[’-¸Ð5«»rÓ"®D‹5IãN ßú~@[ÃÑQÃ#(œÀõp=Ën¨Xã²é%]mð(Úœ9­±ƒT<“kÎÛFµ¡ð­ÄHºÍÞ >…=¤L‹¦9)†´ W[éa"X`7äJ½5ã"z¸–µ-&ý‰,ÆJ;äUgh[œ–Z©w®¤ŠÚ·ƒ/½E¾'ˆ²”£,_ø–2M(ê¯Mþû¿¦LBƒ•$S…ÜÐ>žÓ©!|­þAP–+Èù˜Âm³°rñ*´î†tijóŒ§^6ÏùˆFmq§g,^™bÿjÚ íZÚù‰Ç©Í\âÆF".-Èîf¡…F\ÑåØ}\‘`š0ß)›ZÊiñÚO;êßÿJf¤üª¬D2>.Ø›3sSÁ -ä…óÁhµsLOL°Œ"d•Ž­âzüì.¥å2ÄT%—ó0jÚO“™Žhl¶ÏŒH©a·RyàÆµ\!ý/Zv$u¥éh:%šûRY\¬9•ŒL¯tŒ¾§Î·©é¨Ã(áKˆ÷LÒ2ô\˜ xGN‘ÏI$v$qøAV‡‘éa$àÁ¸E$>@aÊú¹”þ9À£ü&µY Z7õ!ÖÔWä0§ïgÈ$]ÎÇ,Qf^s˜gªCn™¬cMïœëGv<﹩¡ÌåÊCªlÑ~ô'—ZéS~yÓM¤eª{ý7H¿:ÖANå‰çëh{tJv‘×·íòåL‘“öº¿&Shi{¾ß.vùÚÉÞ(2ÔíNxËèZIÏ:ß—Î>ý\Ç’[ OyÊ€oˆ|ϼØé;_|º’K£2×à+Oz»ˆÞ~JüÞå«´T2ÏÜèKOû±€õ©W=çå[k}ìó‡<Ôf_ûâO,{ý}î5o_ß­C’*“ñ§ÑóÙó`>zxï|B==èÔSoä½õ ½ÑªÔÍÉt M]üð× ù 9õÛŸ¡\îÿ¼ÿþeN%f~÷·~•tÔâØGâV0c èjœ1st—€hà‘|9S)éÇe3¸‚116E€•Â/ÓFû7y !ù´?, ½5þH° Áƒ*\Ȱ¡Ã‡#JœH±¢Å‹3jÜÈQ  ˆ Ò@Ç“(Sª\ɲ¥Ë—0cB,‰@A‘# 0 `„2ƒ J´¨Ñ£H'x ÀÎDF)€€ $$Ýʵ«×¯`‘°ú´¬Ù <¶­Û·pã¾5À`ªÔ»PGÚ-pSä‚r L¸ðEgËÚ@—b¨ KžL¹²Û žNÝl³ 8 زéÓ¨S£0:ob»Q1K¨PA‚cªªsëÞÍÛàmœœ]—•M»Âƒßz+_μ0k¼‰¡PKôqQDnν»÷¤ Zþ»¾xªìÐŽwâþξ½û• G.óõôµ¿ßÏ¿¿Ä¦éÝDžY± 6Içß‚ 6È@|P„H ž^Р–ðd6ÞBG›IC•X[ ©H‹ Æ(£@pØáJ pàˆ#}‘¦P72@‘V°’%(9ã“ P>VÐWpLIåVФ_BL–`äPL: &—P¦ÙŸnÉe#eéæèXß8Ž)T™$F¡VjÊmÎÙ¡›…9ç"¢ˆP˜zŧ ”Ρ¡tŠg@¡˜~PTxÙÐ%‚X[¤iX©`Фþ<Ú¬@eEë@¶‚檆¦¢ ¯@³ÚVé±I€§†Öy›˜vø¡ PÚA2¤è„Œ¦jc•Û 4)8~à*¬Lfå# âúâì"+¯P ,Ë쇴}ëa—Œ]Úa°«Þûaf„ûjž ié&Œ„ΉA¸|6,­« {£¾7¢øÀ–œÆ[½^T쬾Êr°%4«Áä*± i ZÊÙ #˜· $«u Ù,.h,Tj°$‡Ôƒ Zس½\‡•¬m,R½Q£÷´ÂJMÀgŠÚµ´Ëâˆâ̆f»ZÉ)YŒ©V0»¥Çm{]Ñ–“i7þB:Zs‡‘mœ£@mÞüq’ ÑI£âK"@ßaì¡ÑE)jxATZÁk÷‡MÀçbàùZŽ p„¦‹ä÷á{7¼  ¯“L𫳨hS¸¶Ánÿ«Àk·Œ£Õb]ÝÙhåIÛñPνä С‘ c0,ö:~}ÆÆKËÐç ¾ÐÜÊš¶QHÏ-‰ Fèaf < Âgž/Û:©þóÜgTpœ4Œuÿ{ʆr™WŒÓŒ$Ø;*¡*x* “¼'¸ù dz¾)œ£lF9¬8%4ÐSßàfWïÕÌ:Fà ¶#C\ae K™Ùv0ÃÙ`E„þ-ÃJdxˆ¢QŒ 6Ò §àÀàpg3DÛæ>£ÀpkB@éQÔžh=Q…%8â@´ä“™©eÖq}øE`Åh9´Í±âCÁ}€5ëKÕªÂf%º¬¥‹ HHW§ñï:rúP°Fƒ€¯Mˆf°€pä*ÞÕí}sìÄ«¶0“˜Ö˜÷£aaŒ-ܲ‘¯E8 ™G@Qå÷ù+†é&!K 9Á¹0ÐR!aI¤2–+—WdåARÙ$pHKNåŤF"ÉS­"ȦŽ'E ÅoBCìPrn‰Ì&¹²1Rò`B°Ç?±&;ŽNÆ”¥$Íñþ¼ ›ɯ*VPLŽ<ããnTIò]ÒqÛºŒ0h&Oz/’£\æ4mä©í ôùתXIQ…åopT’à´bÇqKaòä'{éÊ‹ŠqwÒe’’«öA¥ò›P¹¥ÅI–À޳lñ°J'Ñ dW+…Z8iÕF@œHmzÒ”$ »ÜÇÚ©#vA¼*äÕ*Ä9Ôõpl2•ãH€"Ä¡ÚÄ`8©ˆ:5™Ü¢CÙ÷¯šb ,È6Š™“qï{)ËÅDà 3¥s¦ù´ä*¨.U]:MÎ`³yT_V3UÒšPRíPËö‘DºcR——+ä ”Q9Òþ© @ÖÐT—ŸEª¿úÚD˜>´oF“ªdK`Ó¶ ³Ä…^ji¦Í|-’124!±‚5ž¬J´îmTgªÍ夭3щ`I§ºkfZí„ðÏ °“gsjC§Y€ã%›9.(]Ô±—o©$ZdŠ S'jé›ZjØ/çFàÒò¢&ñ¬Kó;Må%ÇM qœ0™d’“^щ³ÝÐôp;a„0Z:U›öKÈz¨¾Ÿ¼èºLý:d6«zcj‚˜ÕÆ@vŽ3Þ *¥ªpÚê&#éëDZjùÒ–¿'4ÆaBÑ^aÚRåÍ !úm°giÅÁÁŽ¿ç¤þhKGÔ‹†÷E$¾,]%a2다ŒÓ¨‰Ü×ÌÃ6‰Iuâ·”4¿Ášî¶Ž¦½å@1¥V¼JŠs7 Æ7GÒ: Dˆ•/ ÕG@ªªÀB@ê\ :£á‹ë6T8ùó®Mþ•ÜJ9FLéiRïÅr|;9ÍaÍ:°Ñï7‰;\BOH±e^huZì¥~ruÛ¡i¬ô)¾Óº•ÊmZp±u#öÂØqÒ¾Z¹…•]n~H º[Šè>µ 5V×ÄÈ4¦œý¶‡nj÷‰ BvB8]Çð….* ÍNÀðúÔ§2ÀÁðVãÅ)á‹Ö˜$F¥¼ÄËÒZh|þUšÅ]¼×¿z²I•i¯Ž[%6€•m—¿¸wµ e£7ê!œþÛÚczrKÉÜèhZ›ÒSæù·uG‰:±ÑÞwAÆJ³ÑøíhÕ«-J–>(„#‚Vצs —ÀÂîðRÏ&4k©xm°KŸdÜÖAkÙ´Z¯r}j“?çÔÒMJ¸Äf‘±kËìgoÎ9!,/Ö0 ÆwÛXgkÃw,1ØÆøÝÑ|™ù‹•“ê÷°}ÍùÕè_¸µú±Âñ˜æku¢&æG¡þKó%}DrX›¹«íÈoøfUüÐ\('\ëƒf4FàAa'züþ¦ø†¼ûù¾E“ÂQ9¦%äGˆN¨/º¼zÓ&<ˆÏ‘ô·$<ÈŸÚCüþ;ü˧v€Â1v· úæVö^óÒ€Hp£ÆþWlwH R6ctøBXjX‚çÁ ¢R>‚K ø‚A0h‚ÈGj'¨q#¾ç.ïƒ@Ø @Pj5hƒm‡ƒ!€ò?èq„à„T¸Ø1ƒ8ˆ„IH¤ö|;X…`†€…HøpYøpt´dbø†p˜*N8ƒ£V€JXjEã:/ò‡€‡áA*¢†‡Éw‡þ4h„! 5Óq2²‰TN1%€xˆˆ‰¨ˆ~â,|h*£ì'‰¤ˆ,Sò!˜˜‡Šh„¤!ürC³V£Xж(§8n¬“‰­h„öR(Òa%"hq-·xŒ‚º¸‹›hj؉î$ðFOŒÖ¨&”(Zä'—ˆ‰Þ¿8k„'‚×xŽ3²}qMÜX ŽâØ$PbŽèxý#±:ØÐh({XŽ‚ÉÀ}Q{þØÑÒBÏ·SX™¬¡rR. Tò¡ù‘½£Át ÙióÕ’*‰¬a=ˆ‘~b ’t2CÒ±!ùx?,Á7þ8°A‚*\Ȱ¡Ã‡#JœH±¢Å‹3jÜȱ£Ç '6H1²BÈ“(Sª\ɲ¥Ë—0cR, …I™8sêÜɳ§ÏŸ- 8x¨Ñ£H“*]ÊTaŠM£JJµªU‡ „Ú,𵂂¿Z¸yµ¬Ù³hÓF̺U P6 û´¨Ú»xóêMZ×íP¸$ýŽ»·°áÈQŽD!p$T¸kÆML¹²åË  nÜ×±]Ì C‹¾;ðÍÒ´Ž^ͺµT¡ESD†½ÙµíÛ¸söMxäWÀŸs N|#ÍÆc³Ú]\¼¹óçQ ½ºuèS3þØu°W²)½þ‹WØlyê »œÙ;zŽê¯Ëç¹5pPOñ˶¯8¿ÙÔi _ù½GVDå·Ð~ ‚ç‚óEˆS| È`dý1È`€úMf¡ry• l ˜•~ ^4Xж8•€éegÁgêQG!y>$ ~€á‡aXdטŽm‡P~¿­Vr`ÉH”C>Ü)éâ•.ôŒGâWAgNÀbþ¡W¤–Z–ˆ‚Ž}iŸVú¡$~#y`œ3"Dæ~±yY×—rh„c†IÖŽbb©hHÝ¡‡(’ÅÙãŒ9FJ×€z>e¨š)håÕš:f—‰ã¦“ºù׌™)þuvŠ¢vžØé¢¸zTÞoY8+’)XèS´Îyk¦qjjRy´²åÕ¨˜¦yf³ÃÚ¹¤†jeìWÀT`›°ÒúX|ÂÖÄc®èf´+§$¡©]ˆîǘòjh¦º+î¼îh+W—ÎZj¹ ÙJ"½>ÚË-¦œ )µž¦Çj¥éV,Ò`y&Ä%A ø„y<¾üÉÕa³E’„p”B:0‰È¾©Ÿ¸{õî‘6• ¡¶5,çÇ[,4D5²›¦Ë ›f±Qâè¥xæÄköxÐËÖNª5Ïc ‰t¯ÂëòÌ´šTéÒC§ÑÆÞ>L`βý¶ß§»eïQ_]õ²ÎúÚÖì&Û§Ã}ñ‰ï¹ášû_`w«öã±m5Øþñ*ê¬'k8åz3j倊õ9Ìkž4Þ“SÎ+µc"*våÇž%”z²¨˜íDÓ^ûífê.ûïÀ/üðÄoüñÈ'¯üòÌ7ïüóÐG/ýôÔWoýõØg¯ýöÜwïý÷à‡/þøä—oþù觯þúì·ïþûðÇ/ÿüô×oÿýøç¯ÿþü÷ïÿÿ  HÀr/ !ùx?,ÄþØÀB*\Ȱ¡Ã‡#JœH±¢Å‹3jÜȱ£Ç CŠI±AŠ R$$ɲ¥Ë—0cÊœI³¦ÍŒR4°ó¦ÏŸ@ƒ J´(K“)Œ*]Ê´©Ó§P%D¡²gÁ +y6h€Òʨ`ÊKlÁ“=s T)ð,Ö:ËÊK·®ÝpÓÆM¹7§W¯w L¸,Ò¶pæ]˶°ãÇ#ß< çW¤;1KÞ̹³gŒ–¯ ]ùäçÓ¨SwÎÙsqi½YUËžM»¬kÖæñ÷.·¯÷Þžf}Žæý7’A(ô×QNp%˜B/!¥ \ .„àm (áb:ô \É„ …0M¸aCvH’p•øR‚:˜ U æÇ!G¸ ô!Køy¸à†1z„Uö—£í¸De!‰ T‹$%éÓ ɤnGÁ•Uv+º¶Ð‹#ÚÄ¥FPÚˆUKMÈÐVÖX\®Y&’`26çVg]n‰1”àhg*'›•e¶g[Ð*hŽáz`‚ûMÅ–¢ZÈ•AÏ]Š©Mêéfy‚&Ê(qŽÚ)äŽzÁˆ(q÷ªçwþž’j©«lЧAVA¸'¥m1J¨qÏIÙ¯ Qé'‡VÙŸ)¨®µ8䇩´ ^Í66¤’ 2Id{.ªÊ×Iy=©Û´¥Eî²RžCÄr c­mˆPºÜ¢"˜}ñÛ˜ ¡k§®všëÚºI™ÊŠŠÍ8íŒã"´diÙ~õp™èò{/ÅF&ô ¾øÊ›àeR™ðºïZ”´üÆõqÁæ+ÁÏ) ñ…äªdî?ÎL§qe('¿+õŒ ƒ/ %ÏÍm]§ï·i±-oÜ2[L÷iôŽ0³h°Ã¿8áNk ³Às6¼,Ç«J¥É]/Öî‹@ÿ›mB[ÿÌ/þÐÜæ<©½qm³FÙ¶°‘\¯Ö`Ÿ{óâ@*NÅ\©dB—ïõëÒ×ò òš™‹M±Å3*®öVîÊû´Öò‘Ýç¸nbº¢¤4Ø þhçh†kE\êÓbk;¤ézÜøx™1œvÁTÿL%oP í»¤7ÉlÝTc¹y^Õê”êÓ÷þ¸Uâ¥ky(áò}w¥÷„Îir¶m+ønÌôrœÔ¶"V®¹W`®ÞwD’JÌÜþ4®•ŒB³^͇ªõhçpÜS”ÀT”µ„-/E_3 R²BAf(zfëUäsAîË4 S˜îÌô »å {òŠÍUúWÀºn/,êö~¡”•D;þ,ûÙ—¼4¡ï¨ïmFœÍš'@îEN}+çr7±guŽv´ëŽñœÅc©ntALÉ€(µ©íKˆ8# ;·Â2íjdgÑàÍ:¨ÝP7 z ½tƄ팧»žƒÊÓA*ö‰ajZZ ä¾Î•)‡\dABÇE•½i}Ç:’ÐèŰx1+‰ ºÒ–t#´É-Y¯Sˆ ØÉ=-Ïd¼)%ñ2v°óÑç’8;Iw˜…:³•(Ž 3¥Nv¶Ã‚qp*º#Þ&¦<>б\/Z]‡Þ¹âa/k +$ûÀ·Fñ”á[’ÐT„§ÊìãÛvg08ÙÌ™”ã¶8f0Ís…¢þTVk´ÔÎZ1•óŒX…²¸#Rä}½šÝøLÄyN>DòÖ †P ¢rxü\%S¦ÄYA¨ÑŠ-yÖŒ‰bf A?Ò„ r¥K¥Q²Ìzô£D˜]½6ð9õåÅ•w–D8v α A* ù¶êRmM2m;ðkƱ λ°$à´ùFœk°AB›~û2ÖˆÖb«n“Â,Ë3£R—§ê¼ü0`,+tð9³U³¦eöõÙªeÊÞùvì¤9âìó+‡,7wŒK:…ðÞ8Qx~õésÐÑŸ7ȳzQÚÀ=þ¿¾p7uçà»{lþtzeÑÍ[=ˆ™ôDÙ7"¯ü;5SÔK5÷›t;Qtš€ŽöOßù7[|±¤•n½ä „¤¨]QÉ)Ö_„55pÕBn¤SrÂåf–€ÞU]à•¨¢KÚ)âiGL[¹Ø]N³M¨ã|nÈ”U<.ˆ$xÕÆ–Ne•TY‹ (ZŽ 7‘„ ÚEÕ~Câ†åm¸Y`bn!õáU ñ—_“àqdf‰ ŽÄÞ}#ªã€Î çXjbö¡]erÄP °õ8fbY–f!Z±YdEÁEÞ€0ˆ#—"q¦Þ|®æ)©qvJ‡èw¦òY–{pÛåøi‹®q˜ÜUòÕ&á«*žÔ܈rúëvoU׃=Â(%q¯àJ™òäZž] ©b´2Õz$¼Išz\áîE6†WXa•ËèHjŽ+.D86æ.ºôÖkoJŠÞ«ï¾üö«o¾þ,ðÀ¯[ðH!ùú?,Û(Ç þHP … lpP¡A„#´±â‰ZÜÈ‘àÄŽ %"Ĩ1¤I†+~4É€…)*„ s!ÍŽ4Kn|I3Š-Y6¸”ãО4eåÈSiÁœK;6pô§Â—((r„Ú±*äQ® [°*Ò:ÉRKkÑp+ÊÓ'Å©3jÌÙ ¥E¼µæM8®B††ã.Tl˜ JÅŽnœ{fVª†ýæu˜¸0cȈ¸…‹°dâ”( GÌY©h˜•iþÔ*»ç_Ùª=ÖÖŠµ©…ŸJ«RµlswážVåZvH3álâ.}‚í]EôË×k;¬ûíð˜9þ;m [:Ö¹3af„Š´»à§ÈSîýõ2w ¯ñóŒ7تð„BZs!dZfÉ÷x0QDÔ~ÑÅ´ t°}7 €fÅP`*Q(_k¸-XœLÿÕawꥇ_~Ùé6 ‹ЏVJ€¥XV| .èu^ãT<.!s°5àÞ`¹év \*ˆŽùÅöâd¿ñ…¢‡}åxœ|F*("uÕÖ\DNÄ™‰QªÈdLG)¤ì5iYBh>–V†*VX×H#¥‰^˜ØyU`€#eé‹R –¤ JapÉ:¥¬+^G‘p•­ן,=*銚—r‘Vg\vÊB_…Õizå¡Í8é–ßf .…‚õ¤ÑT Y mÀ&ë֬𒫢·ÑŽkc¼G^—˜´â‹m†áVG š¾Çï­’xè\v™ªVW¹–u'™{6±ZÉUñØ]ÒÆ§v!ù?,Å<þH°`A2 HÁ°¡Ã‡#JœH±¢Å‹3jÜȱ£Ç CŠI²¤I"0Ȳ¥Kƒ"d0I³¦Í›8sêÜɳ§ÏŠ (0xI”hÌ?“*]Ê´©Ó§P?’Z´*A™Q³jÝʵ«×¯)FPXiõe %Àª]˶­Û·1 -Ë’Á¸xóêÝË×äˆt FÑ·°áÈù¢ 0 0€$KžL¹òSÆt![Þ̹³g‘˜«jþLº´éÓª2 |ºµë׈Q6;¶íÛ¸ÙŽ˜Û’BîßÀƒ?Å@Ö`„´Â“+_n35ÌÚÌ£KŸžq·qêØ³koè|`¤ÛÃþ‹ON‚÷ãñèÓãîºú÷ð=ƒ Ë ¾ýû–gûÆÏ¿_ ¹ç߀ª‚,Tà‚ rÅ@ F(¡SìgÒB¦€Â†vèᇖ âˆ$–hâ‰% âŠ,¶èâ‹0®8ÂŒ ÌH£#Ôh£Ž7îˆ#9þ(¤DöhdE"y$L¹¤“JFÙd’Sã•Xf‰â–\–â—j(æ[`PS†‚Øåšlf馌ORI#Ð ‚xÖygzö¹çvú™' |þ9蟂 ¨¡Šz¨ž‹>J¨¤xFšè¤—ÖX¥”C¾ù&›k‚ù¡˜ ¶•x4e¨¡š ¢ ¢«þ^¾*k¬´zêæp&y䌙6:)£¿Vê«¡‡ û+¤Èl²Æ;l³ÌB»,»æhëµ.’ë¶³r‹¢¨’:&[5Ú„&«Þ¦K" )bÛ¢œðÞhl¯ÀæÙÁ½øæ«ï¾üöëï¿,ðÀLp½—úYgœ ㊭‰Þ‚ª­¨«Š‹¦¸:±kykÃSRЬÁ$wÁÉ(§¬rÊ´ìòË0Ç,óÌ4×lóÍ8ç¬sÎ+÷¬rÉýª0¢8]´»0†:êÅgÞ¤`šÒ ë¬YMm”¼:{,ÐþúŒò'ƒ2Ø4[вÙ ­öÙl§ÝöÚnÇ ÷Üo×-·Ýtß­wþÞ|ãݶÌcíõ©\ã«5°œÆä§#N-ë—¿u®‡':Þî›ïÊ$½õÞuÏbžÁ;—nú騧^ºè£ûìyÍë§ÑÔÖˆtå%N &Çæ"×4ºk+"æÕj©È¯wºØË¯l3ÚC÷ôÓK½õ.cÿwõ/_ß}ößoï=øâ“}Ì^3öÉ…×+ûXc´Š\n .Ó4‘0‚Ó«²ºåÇXã‘´ˆ•¼|j}¬CÙÌòF½ñÏ|Úk ù¸ÁðI°|¼ #¸½–%í žâ¤ù±Hj»ß¸jòT¥ªP ‘-£IihZ«S Ø:Ñ©¯‡þ@bè„8qˆÍœ‰¨Ä &ñˆEtb™¸Ä ¢l‡÷ŠÝ¥lX»ÝNb®º_˜TE“ ˜icó߬N4?«q1SÂ"¾>HÇ:ÚñŽxÌ£?¸× Y‰r£oÇ.ˆåÎK ŠÜÓnB ýŽT`¢U·.ç)Å!I‹{’£{8DŸ©î“  ¥(Ǻ'öq‡‡;ÞÕ˜t;Ëé.‘ªÂ_M"!þ-\kd£ U$È¢=ë}„J'«¸Çbó˜È\óüH„Õ«Z7Úe!·ôJXbŒŒ6a@‚ps±n*ò› )Õ-à N¦Åò›ÞL':שÎv²óîŒgäæ9NÞysåãħ<÷¹B·€ 1š@ZÀ‘M¨BA2›ú,ô¡ÍÈ|ЈZô¢ì©åE7jÑòä; éCÙ#Šô¤²NA PQ”º´?$Èq^JSÿÇ%­©NÓ£Ò–°t§@Elвš U;1mÉhŽÊÔå„F4‘iªTóT«,uªXmÍbã˜Ádõ«¥ù‹c€–‚õ¬‡‘ËXWŠ´ºõ0b)ÎZ¯bÖ·Ú,S1Ï\WÞõ¯] Š^÷Ê’˜Ô°ˆõÉR"WÂ5!¥J¬dÍEd€`W×!ùú?,Ê<þH°`Á4¤XȰ¡Ã‡#JœH±¢Å‹3jÜȱ£Ç C^¡a‚Á“(Sª\ɲ¥Ë—0_&I³¦Í›8sêÜÉS$ˆ b J´¨Q—@ô\Ê´©Ó§P£füô¨Õ«X³H Pª×¯`Êëð§Ö³hÓžœ@¶­Û·pãjÔPU­Ý»D¹ÊÝË·¯_¯fñ ¬2éßÈ+þh’°cdžKžLyrãǘÕF®Ì¹³ç·—Y&Ä ¡dæÓk•~^ͺõÓÐ)E8Dr §ÈvͰ¿oN|·ßâÄ¥Ö.¨DUÝuW"<9 Âè'j8ݵwç àÃþ‡ïÞ°¤xñ¨_¯;Åyðª–dÏ~æØ÷IEÐW/U¿ÊæÙ¥°²™”ÀBÆ t` dœ{±õ“€ñAh›w9·Ÿzl•µ!‡éí·Ð†å}H_‡ áWaN@Ñ÷Û~(B5 J(š6R€„-dš$]] Dx>.gׂrFׇ1.ôä†Qf¤ß‰#Šè£‰0:Ô"{K‘8åzäA¥d„µ š 9ha¾éž„ ¶ €-˜Y™MJ6¦– qÉ'Föxe}[r¹y$òtèzl}IæWÎI×ávtî( @:Þ™BPލ])leg„›>VeŸ‹I ¨”þ\>8×{Ú-z›¢T2ô(ˆ<é{²š¹Vt aÀ¨qh§žzšZ*²£fêæ™j˪bŠ:”-N®êÕ-B#ŒP(°Ò7¨MÝžV¥ ž(|z¬ðÊ $œ÷B¤ŽÈr* z„­zmbŠŽ ß¶ºšw¢} !'œ{ûœ+Cß 8߉¥9 \YÁ%×ÐOâáñm?ü±yâ©Rme²Û!Iv–Ù˜ÌÇ.Žu‡]*Ü—†&œ¥‰(Šð-–  æ§"îÊ¡q"ŒµÔR+ýáÅì=Øh¢'ŠÙ¥®G«×sG¸QðA;MÚhïlÐz„1éóbã²×Uݓފ+þ¯¾2Ø¥Õõi°âÁŠ:-·ÓÎå¿æR¼·À QÛR³ÖŠšPÏÝWØbs}õÐ{·Wh­X*ޱ—¸Ž°5ãvƒþ8Ä.z®èØ͘—Öá~yL´k熦Î:¤ˆ»a¶ŽîúìòaM|i};Þ8ð]nh0ÞÛTöîÜWîûb¸FŠëòrwk°ù°³'4ö_—ÛºûyËžÀ€sx´B$~÷ê5¹Ý}nßSŒá$5]u+s ù(½Ðu}òc”ˆ¨+ë!.}ñcZìn"¹ÿ,€‰©ßŸ\EÁ†ˆeDóÒøg´Ð1iuÖkXõFƯa‰D—»G;ºÄþ@ ¢‡HÄ"ñˆHL¢‰8¸±ø {ÎëÜm¨©á肉âñÈE+"$z5ÄRºÀH>¡ÙÄv A^t—Ñø%¹LW’4¤‰^úá÷ÈÇ>ú1‰øÝ¢Tg" ªÏ‹ÌS!"®£ pEkŸKc« Š1bÊ Ô«j²½tè "ðOµHf9æÜf úIbC‘ýñ•°Œ%é–tÕOl†S!”ÐÇËE¡,d¨ÓR&½#óåp’†\2 ‡(œˆÀ ýRÉu®òÉ5¡OÁ™u:¸6Š D–à g,ßÃBæò€ÔR£Ì7®(M,] ¬"üÖ3x†Ñ\¹þ&¥ˆƒ`•›ZÐý•#¦éˆG R4½W—ƒ&­†ÎrVPxD‘Ëä1°GŽŠS‰´K.“YE_ÎŒõc ‰n™-J‚ûV¶OõȆ*ƒ$"™¹´œ¤SÁS.%шjÊh·:Én¨Rƒ|U¥šÈ„zÊ£"”"U1b¼Ä@¢À[éB;V즫CÄhFHK%š5ˆñZoWç;DU¾dbgÃbO–Ó®ÞJ^%m4M抯ÁoCà[ ÿ¶>Àµ0…#£Ÿ {8¸ ÒÀ‡-Ü\‹<óŽèv¬)^ uª;vôÔ€N{lZ3SŠ-*yS€o–µ ²< ZZ¢ˆ²{ƒìU%¯UWc{Â^ÈÆ£r2ÇC+&®QxKˆ­zÙ¸x¦Ð!•þ‡ %µåVØ·-Êðröæ:ÃY/>î€çâ½j&ÁŽS… È\×9Ø5/|’¦Ô$)åćÕWU›cÍCäÇ© r“DNƒõ6‚k¯j–jD‰¬×ÈmH¥|Sl—ˆmÁÏiϳTüȇ„ 1Ú{,½ÒH©×sH ©T¼ˆœX<ýb‚:kx¸%1…ólZº¹ÎR:î³™ë‘ÐÄ(^&¡îŒ-´]¥2•Ö1NI ÊòÜÈÅòÕ¹;LwZÓ°–2‘¥Œê!>H¿›ŽjB³v'Ó' )gûdF¦PMj5i¸À‡« ×à A¼ìŒqiÿ$¡x³þ=.m+ë¹#Ü|ÉÙ†²ré´Ü*r{ˆ½÷‚ý9^G.²”òMe­â[5o˜Ÿ]½ó{“Œ$GÞ2?Sçø,÷Ùt~óÈ+ìt ‹x¸[½º…=â¿:&晹zCKð®`9ȯÞ÷zåÓÞ€×|ʨ-}sÙLüÏ _ºg,þÛÎ’|Úúo1€m† —ðŽß}»ç‹œØë»S×ÌinB²¿ÝòS6G9­Z"Òà»áh¹=íiˇ²èJ×»“Hƒ§Süâº"ùqWmçá–çï‰1äU%‘¬1Ë@ìJWõê†8¨ý|E›ôÎ[¾ô⪓.ÄÆ«ž2µxâ¯þÞwùŒ8ð†Ï³…;Ë}Æs$å»W Ø)6ù¹¯öý²\µeŒj­¤™Ì"­jýݲ\¥p<üOgÙggÓF{°§—~¨!yèøQž¡,QÕ\?’ùwb%&|—xÊ5aäñwvö1×Vm !{è§€i9®ô€.eQFJ3ÂQƒK,CjI=eæe1!¥&Âa25(8ùGJÍ#el?èƒög1?x‚%hgRg!µxËåw Hr[(rÁ.kñg¥‘‚*øûgQ/؆}ä„hæ/×e !2 öBh'&+ ‚JUž$%rØc‹¶z«¸J_òFGÁŒ]'«V‘™­:¬ÃÀ ¬´J¬Êª¬Tq¬ÎŠ&Ë­žÚ¬ÏZ­;"XÒš­¼A¯j­7’Ú®Ûzlûè­;;tkHTML-4ee7aaa953d6cb59/tests/page4/image3000064400000000000000000000425261151224263100173600ustar00nobodynobodyGIF87a,A÷  !!!"""###$$$%%%&&&'''((()))***+++,,,---...///000111222333444555666777888999:::;;;<<<===>>>???@@@AAABBBCCCDDDEEEFFFGGGHHHIIIJJJKKKLLLMMMNNNOOOPPPQQQRRRSSSTTTUUUVVVWWWXXXYYYZZZ[[[\\\]]]^^^___```aaabbbcccdddeeefffggghhhiiijjjkkklllmmmnnnooopppqqqrrrssstttuuuvvvwwwxxxyyyzzz{{{|||}}}~~~€€€‚‚‚ƒƒƒ„„„………†††‡‡‡ˆˆˆ‰‰‰ŠŠŠ‹‹‹ŒŒŒŽŽŽ‘‘‘’’’“““”””•••–––———˜˜˜™™™ššš›››œœœžžžŸŸŸ   ¡¡¡¢¢¢£££¤¤¤¥¥¥¦¦¦§§§¨¨¨©©©ªªª«««¬¬¬­­­®®®¯¯¯°°°±±±²²²³³³´´´µµµ¶¶¶···¸¸¸¹¹¹ººº»»»¼¼¼½½½¾¾¾¿¿¿ÀÀÀÁÁÁÂÂÂÃÃÃÄÄÄÅÅÅÆÆÆÇÇÇÈÈÈÉÉÉÊÊÊËËËÌÌÌÍÍÍÎÎÎÏÏÏÐÐÐÑÑÑÒÒÒÓÓÓÔÔÔÕÕÕÖÖÖ×××ØØØÙÙÙÚÚÚÛÛÛÜÜÜÝÝÝÞÞÞßßßàààáááâââãããäääåååæææçççèèèéééêêêëëëìììíííîîîïïïðððñññòòòóóóôôôõõõööö÷÷÷øøøùùùúúúûûûüüüýýýþþþÿÿÿ,,AþÿéÛ÷"ÿÎ5K'°Ý?~ñýëg‹/"Üȱ£Ç Cn̘±`>}ùùËÑß>}ýDÊœI³¦Í›8sêÜIóÞ=}üîÔÄ„BŠ>âþ…ƒØK~úHbäIU¤Ô‹üêåHjLüöŬJ¶¬Ù³hÑúÃÇ6Ÿ¿ÈT4´„qþ潓ø°_¿«oÓ’üïÞÛ{'îÇo¬àÇ#K¦ú•`>Lüük†D€•nöâÅ늒ð䜄F|ø¢ßÀ§cËž="½A‘³e‹J‚#Åâå;÷îµiÚ3¿ûGOÙ´˜éüùýë¹õëØiþJPߣˆÆþ]"&l‹!°ê½csßñì #““£‡cõåkÑ1üÿÒ&V=Œ¡TÊSÓŠ(ÂÐb†GˆRN<íØCTv>M”À‡ 4ÁN>÷؃ÏWþe¨âŠg¹GOAõüËG„ƒ "¤0ã ¼`Ë9×cÑU,X0"@qÏ/pÊ=õÐsDiå•:Åø>Åc |³L„¸2Œ-u@À(èpŽ{û VPÓÁf`ïÑ$Ý_™R€ ÷4ÒÄpŒ3N9îÔƒ•%”'–jHd|“†„Ò––™C±`S‡j ÂÊ/~d0Â#ݬƒN;oí÷{þÞ„g¥5혟yàs‰HÁŒ4×”#aÅJ鬯Fjå£FÒÒJTâ㸣HL±J-º‚ps;î¸u_T!KN¶„ÊlèsŠ´K0Èh£Nb-³Ôã"¶,ó ¤pÉ:íŒ#K ‡¼s­$ÿ£KNøã H ˆ+²“7ðèŸÐÇÍÑÍÏú̳þY¼?M¤_>ìä,ÝðáB °‚¥4CÌ „ Ç6í°Ñ>€SÇ®×xÍç?Fóà1jœ£˜‚ 4×À³hka}äwM¼÷c}ëÍQcŒÞyرÎ#@0ÁLðE&·lóÉ  AL¢ë85Ðèw‚ÎnØÜt€B?Í ÁÂhp² +Æ4³=ÛÔÏK¶_u¡‡”ût» Ö{ÎŽ‹«Œt ÜÀªC<  V¸Ä,´Á‹% À`G:ìa" ä/€^ûÞèÎÑ ìcg`ÁÈ  K”ÂÅ G¹`âýÔO*ô¨‡=ö“"„í¯‡þýëGâ;™øƒ#P3 á†P` Vð€= "» VpŠq#B©’†Œã—°¼$,\2‰Pò‘„Y„Kœó‡ ÆT žò²ðFx"ÇÇ:瞉à£"¡Ç9ºq‰œc"aäÇ7ÞÁ¹W ä-`¡Ž>ðq‘¨f¬Ú‡DÒ–ÀYä†vÈ_òá1‰È‘n:9Ž*cRî„'1<üQÑÄãUÙŠ%ÿ±Ã*ÍòkDDæFè1‚}àA *¤xZ! e "@D8àvHD?ÆiÖÊ8¾°ÒH¼PþФÀƒ/þz?\é;yÔà×øFô8…E$B­†7ÐaŸÌ—ªH:±„)DÑG=$ò“rœ«+é‡>¶W;}êcĈ„Q p„a *c5Ëh *Ëi l”™·œÍò‡A‰DòñŒRâŸXFAì18É-ô =ìq)ƒñÔªÙÊ#àƒtŒ" @Áðð0 &%Œ1 Bth†<Ô±–d’§ëZΫúq‹+PàR8 v` 6Êc ©ˆiµ!@ë„ÀE âª7ÐÑ”{ÄD¤ûÇ?JÌÁÀ%ö!šyȑԨþÇJì!ʇ°¤Xñ¨È?rá„Ø -ðÀ 6Qspn,Òé×Ý*UÓý„QǽLýåS×ĤDÄ$È0ì ƒa`A!´!ý„t"óàKUmD¬z„û8(P fÈ! Ø‚ê+‚^1T8Ö »8;*4¤ž8eðp p€ŠIbƒ4 Ðv¸c"Š%’ukf舘¬¡Kdv‹HÙøQ¸à¥ø‡:ì€'(8½90 sL¤%t žPÀ±‡ Ì ÉøÇ3&±‚œ÷ä,ëFSë„ ýhÇAtZSê¦Òº±‡þlû1 ´€Ã@Ç8XÁ„Áÿ‡–ÞY˜Æè™{ýA%HX»©N c88@úJP 1x  Ћhì `Â0à1Žt(·?í­D¼‡ D!ïF*|ÑIÐ ”p<Ρ{´OÁóÜ´NñGø æ!LjD`߀G0DqAßÐÆ:ü0ì`c¨†?fø–¦(j+ïX¸¡n€"à˜>àˆx¬CvÇíé™÷ô"Ž‘ãEžVI2AÇ܋ųœŠ¡qØb݈Eà†l´#N‘-=Ú‘p)~Fj¯ÈþB8ع’À‚nЇ=Pb¥ˆÄ€$¬P(€ l\‰i,I“wÜsÀG<@a&ä!½@ƒV° w”#îÀ$`C4þãÄ?$‘¼….ªq( « âøE \À ~äB_ˆ€¶àŒd,ƒäÀÃüøa%Ä|Ë>Ü241` óP%º…?£l € bŽtÀpù“%šW…ÌÀêØaóÃÖ¬Ë{úÇ< b‰ 8¡ï°Å®°†Rã¸À"Ì1C¤/nq®©Â$ä‚öÈOþñŠÀ ÂhÃ0þÀGdbº°E+¼pœ`‹(C4[ò`ãq§b]áÑ"¸ƒ>Ú)d '`΀ զŠ Ú€é…kf¤SýÐ àû0 C03ÀŽ §ð ÷|ÿ`¤ð`À°²pXÐ ‹  µ Þ àíÐ ðÕÐ2„üÀxü€tày ÈWP@Ž€ ª°PÁð ã[õi?{~Á !~ "pï0R‚?ázû#z{"øð (`å°’@+p Ȱ jð<` Ö@ íÀ{eÀ0ð­ðþï0,…tJuó—r!а° |P°‘` ¡À ¹Ð ¯ Pô 7 €«@ ÆÀ bxv%t\G?ºàPðt@P€G  x* É0 æP»´u/±=`¡  ö0 EP8@ — ¯p á`ë ŸpPZ€ :V ypPs\p ` Áà 0¿ ŒÐp àð è ôÐTý ¼|àÏO @sH Î@ 0 Î@ï0†35:㋜ÀŽà(@ ïóðÀc†gXp{‚Ï€8@ êp WpþV˜à ˜°@¿à ÓÀH@»À*G×Àé¡“!pñ6-@‘°P”À« ¼° Û`Àë }u€© Ò`üâtRkÁñ "0ë1CÐ@LÀ4màް°²€ ú’¹IŸ¥%¼pfðˆðÀ6°G`C°8@@PÔÐã0 ¸à VPÐiЖÀ ˜@ ²pF€ìà$`ð Áà ÞÀIåðÖ@DpÜàM€M@âP EÀAP Ã` ïОT†åþF%ó3¯¢Qòó ú@ ?ÐZ ìð†l±›#[ÁFý%º‹|²x‰¡ö@° ù h`au-CР° Pžà ̰ .ÀÍ@i ÛÐ â÷C6Lî%1{©2@¼|˜‘Ó¡PP Øà ¼ €[P Æ` äÐþÁIý°mù°à ó Y€Àx0 W$€ Ê  ²  î þ¢õîPHþ0%[Òo°p´e M@80SàjÐ ¼11¡·@ þ~€PnPŒŒ° ´€ ð÷ ‰p0´@ ǰ yñé ð ß K Ѓ [°‚¶p ™‡ ² âÐ#Å9aq)¹V¦4@§D€ · ! ´ Ó` ìPA—Fóc!ÿ¢xòsH‰aÄ0 p %@’pÀ“@ ÀÀìè Uªê° Ep[` Ù  âàùTŸù!#º3ý( Ÿ0 p±à }𚀠·Ð Ú ä@ ò ©°  ÀP¢° Þp®Uï@[³gÿP Ôòþ¶p,&À™ˆ–zæP@°G¥à Æç` ˆ0o°Ìð*ø ñ jÈ7íÀ îÃIÚ*?Ѻ×@ а[  èp ›Âw }`ƒ@  SªÝp5`g` ²P´‰„€ð³À#P7@p s`@âp áêÀ“ð7LY,']€³%œ$?þÐ `Êp‹0ðáãgD ðC8µ?<˜ºDã*q.i Àêp gà±ð—p аpØð W00@ °€ ŸM0É PšÐ Ïþ0 2³IÀC,%’»ŠÕ@çÀ6`~OP]Ÿ` Õ `Èp u ݰ fpм@¦æÐc!L( ”¥Ì@?0`“ uP`p;0 §Ù´²0 ÐPÐÐup Ñ–aÛP.P ¶@ †€ ˜ ¤p ©  ŽP {À[`=à> îpMP~ €‹  ¨Ð.€ ØP ŒÐ 0˜ð ²@ ×ð» ZPÎÀ;0P˜À„ ;;Îð X@C P ¤ °³ ß ~,þã kRrHô zÁìpà0!ôP  óð A@0 Äp Ý€ôÐÂdkA¾ ¦Àõ^Ÿu«bakm¤c?@ʼn° ^0 –`‹ 0fbÐwÀ©  ÐÆÐмp ÒP0E.ÑPoä½ gu° ôÐ Ò µ`›0YJÿ„N& ‰À mL Ť°@˜0¡CµOü@hÇ@Šàd Œ`„° Ð’( spP›P¦ð"ì€ _½ø¢¶ß ðÄÀþ mÐ8@0GÐ7  d €°ÿ  <@!}P€ÀwŒ •0W Âp i]…ð · è@À öðHpà‘P ƒ0Š P£` zÀœp p0w6ÐD NPfph€i°×] R 5@ipñ0 ÛÐ YP) «ð¥ÕÈæQ!†1f°ðÁ0'Lûìp Ïp ³züP–à„àµ@›† Ž ?l  P€’0 ·ðë AI ¥0 Éà‡ç êþp]ñ0DËÆ2« ä é€ ¹° éxëÔð màÛ Àæ l`s Þ  j@¤ƒýð"Å„ €£U– ‘`€ŒÀ ‘`ÒvІÀ2€xðP ‚pÒ€ Œ°+ âpë#ýÀ Ò€aS4€ .n£ðqÐ `e0lð„ @ w€‰ ª` ð_gð‰ £œ àúp a* ‘À‚P_mÜð. Up Ó Äà ±° ¡ ‚0i@KGPEpþJÀ^@w@ƒ`CaP€µ  w0 ?T€apn@Žàqõ ò ÐÝ0 “ðÉP _Ð.€#зðÔ`;ÀÝ`0V€P „0 À€Ë ¼À€€0cÛI`ÀP PFPH@ZðmÀz B®Ø(‘ï°³,PaÀZ€Ÿ0€©° ¬  ¼@ ÑPÈÀ4à Êð3a ¿ Ép% E°´`ý#ðP ç09à'P•`à…`”à yÀ-P­@ 0 ÿþ „€@ÐzP Ò` 0ðvСšðp&¦Ù†jp  %Ð:``å €ÙJ sЉ ¡à É@0º¡€ ŽPtà™€ Øà# â09p!P– Ä‰` ™° k8 ¶Ð`Ò èà€ÈbæÉ#‘;ó@[ü–P 8°© ˜pE J UÐQ0S`дæÐR@Ò 0pmàRð(pj` ²à ìðŽà¢bð—‡ ”à …P õe000™þ¹Û@ v°GPù}^QSÀ+˜^qã½/!cùàÌC°0prà¥@;°ç\RðƒPÐëð -€PaÇ’-lÎ 9#•<žèS ´Lj”¤K¢’¥Â€Ö±;($ú—lŽ ÀX4¬Ø$qӦݿ) 6½{c‚‚)Mš@‘‚åM@Wú7H†]ê¼a³HS­`Èv˜€·KÕ¸J)èˆQ↘4Äü›¥EA-ö‚$È“©Z­JX°UlV¶¨Ñ³ÈÐ @‚ 1‚$‰Ò%NŸÆ¹¤€…^¸lð!ˆd€ÕZ˜aXð … ÚèæŽÐagjQF\b¹å—Y`©å”Þè@a‚FÒ©ç‹x‘ç•oæùÇœwÌñ‡Ÿ|ʉ¥Z1ä .@ :ù ôød‘@Á$RŽ¡’’&*@z–É%™‘†¦–[LYåU:™d”.hau®‘'Ÿ~ìéÇ@“Ïf“:¼øá€¬)† @\`tÀÀ[Àþá…X ‚”pSZQ¥š|à™†õTy‚„2pB <É$”^–¹¦Nà`TàDŸI†X`ø ƒ‚`Ä‘. À B<ÉæŸL؃ž>…" 0Â8ÃŽ>AdލÈÇ•(€Š9ÌX#Nr¡†NˆcE’çH™}‰æn…‘Â>P9ü¨„eªù&@øáV®8àegÁ€€ž@€ `pêÉ&а"‰*Ò †˜>¢ $~p‚‰`ð€€i&%€G i„PTiÅT&ICv¡ T\ÃÛ8F)þÖñ 9Ä  ›ô€NÜbÜH.<@Z$ã 8Kœ0…(¼á®¸Â”0-@áH°{pŠd£ñØ>d2½cü(‡1nˆ ê@Ä € ¼`.0Á ¦ð`å0…L" #àÐà‡[0ü`†3ÀÁ d´BF`Á*€h¡¸¨?ÎñøâvpF9¨Ðl€ qЀ€Ô  *ðÀ 2°ˆ °?A4h8ƒÁV€aðG8™ƒ7´á ‘ØÄ#*Á |¤Ÿø‡ p1K˜eª°.’þ±Œi¬C«€…ªÀ (€:Ã$z1ŽlÃ…1öPÌ+È™j€è zˆ$5É0®pF  €20F3®Ð>ÀP@ò,ÐNÈâO(ðA-Ø D0BpP„tþ8!R± eHòø†*HQ‰2ð    ˆYô j(À ¶a3€˜¦à[¸à(0€€A%Hƒ'`Ñ‹h”ã"ã!ÚAzCÒp |xBpÁ¦0†.ha wèC`j$ã øÀnÀ@¸€ ’àþ„,Ô!¤ F>ÂŽquÃ’xL0£˜BêPŽÜÉ" O°€@€¼à qh„)¢Ñ q€C¹Ã´}4"€Bì@‡B€b½pÆ,À tháÀ ЈKlø€öÀ€\lC œ˜&XP³@a p0Ä+†±Š\„ãá†/.h #P‚$qðÁŸÐÁŽ L  ¨E,>-¨@ˆkȇ:¤Á &8@2x‚(-€JÆ8Þ`8€›5{ lÀ½tâh0ÀE7Á,xTUøÃI2g þYô¢Õ`‡7 q‹S¬ "¸@p@I€áLØè*ºÓ ÿ8†S€ç!`7@B± RÜ"Ù>ö! 2ûãò`‡9® \ô;‡.´  á _ØBÔ€V1„¬<$„ BpºhND sà†9t D<âÁˆF8Ê¡g¬BWB  4ƒœE0ªq jP#ß0G<ô‘Žkd£ÇH1¦¡ŽJèÀ"ø˜DðBü”˜…2¾  a»ˆìð€ˆ±Fô*˜ÂÀoØb &éª0†-˜a„X„""á‰WôÂï¸Ç>ú±w¾ïÝóˆÇ<ÌQ eÈðE7øp0a dCôpˆIPBPÃ7XáƒÈ€ jÀ œ€ƒ0þ žÒ†4Ú@‚ ä j -%L1‹r¼CéÐ…-Ü0…_4£y *hQ i<£»x)(ч:Á Ÿ'„+h1‡ á¨`ïá‡=hBÒ ‡+°ˆ}4" Â#‘ M€ݰÆP%üC>ÐÃ2F„p€6 ‡sPx‚2ˆƒB…Xxs‡w@ \ „0(†k°, ‡c6 >JX…c¸†e(„„Cðƒ phx/X3`Xyx$`ƒ+Hƒ>ˆB(„E@„Eà[8„€xˆ†8è)`þ-€x06X2£SÐDÈ#0ƒ;„>©…iðl‡mIÈJ(<:è8 8hh ¸€/`­„AøƒE8A˜„Ùû…m€‡{è»I½³‡rømH‚p„u`„ €#P8E„Rp…Y¸Hcaƒ-P@¦{„Dè7(-ˆ†i€ƒ€8 h!h- ?Wè…jø‡qh}(I€s>3(Ø^Ù€`€H€X…l˜x€ >ÐOhÆ|ƒ0u€@)X„BH1þ:؇_h X<ø‡R / †\˜‚p-H‚@Hh¨‚%+‘à€80pƒ9Nx…\ÀyX‡jˆ‡]ˆ„)¸ƒu…5€ ` È‚2€_˜[(ƒˆ9à Pj „x€=@ÄP€T°H  ðàxFp7HЄU(†T Іpøƒ"ˆ%0.(ƒa€KP‚ ø€ à~ø)@€ê£0èE˜Wx…¦Úv˜nø„9°pЇd0`¨ `¢?BPJ…Wf‡x ‡Iì;yØy°þ¨‡v@‡mv'XÁ8ðƒAè„V ¦j¨…8Q¸†CÈ€5H˜K¸„K „E¨ƒ X€ià#  žPÃÐ#‚¬-P`^˜…CÐH€p@ç!'öLVCШ‡S¨wäƒ=`è²4‡m( x€8ÐP 0sP7à { „˜ñ‚(.3 ˆo°‚ 0€0'è¢x¸&Pƒ6p®1ghQèf …¸¢š2æ¹€ðEXe¨ƒð(H1B’9¸=‚…y˜þXÏ ‚HˆYê„Q`…\{àqX„)`Ž4à‚-`€#hiˆ(è‚(Eˆ>øœFˆ€p2à/ˆ¼E¸UHfÀU`‚° sH† €(&˜ˆ‚G(KXT`…aˆ†sˆyè‡sø‡p †^t€‡|(ú z`…Àl0†9K>ðƒD€…aht8sðƒ4ZHB L@¦ H „BHp„kÈ ¸"°‚( € zÏ€(8ÐÉL. ‚ šù€("`‚-Àw€4þ €ø‡^¸¼9Rð…oè|(+@C „ÌT€'ø‡ZØD‚Œc7À @†nP÷Y‚& É„kÀƒ$˜‚¨ଜé" FH‚,H5Àƒ\P6¡8€˜qJ€H/0ÔL(šAmàƒ8DØ·l€PÀ‡E˜Yw †7Ø…JH¾_qH€{ˆ„2¨ P.˜ŸH€T8€$Àƒ(PPØZø‚&€"0ž `P#@œ5„HF2€"Ð168¨PÒ NPª`P5hœ‡þ} mƒhÐ5ˆ…i ‡rá}ˆŽÈ€`<à€`ƒ>H„U jp‡vÈTp€(dXP9(„Là._Ø…^ÈVÀ‚ƒk0$øƒ2è6ð‚%è &;Üè€1¸†‡{¨‡gh#€€ x9x8F_JT(J‡W‚—ȃ:ðJ…rø…~¸„#€`:h.(€D¨Nè†H@‚àl8É„…k8 0ð‚<ðè‚i(…@€5 (ƒ,(&K€šé"T‰$ØTN"&x;À_0XÀPþ€À‚PØ…FÀðqÈ”JƒH€¸m؆BØZÈwX!*¸„MX…Vø\ ‡Hh3Ї˜Ü€ ø‚,€¨w¸$(Ø7 °dX†,h¨‚5 *È3PʉY4pÐP\h|†1¸€œ ÿãP8[@g‡tx ~p_:0F8\88€0ƒS°wЇ.`€LHC8 ‚=H„Q°¡z¨‡¸†hMè†G` ˆJ°T†h¸m˜j „àWxH``0ˆ5Xƒ,ð2øCØ*þ‘ €¸‚=†Qlà†_pX€&¸ƒ3-0€2X‡cP €xcuƒ;0LØ~È„X|!H7¸x€fÐApP°8€] GA`à-` hnЃ€83xƒ?È‚°E#(*x×`€;`¯»2<˜ƒAH?¨,xÙ©¹UØ…;83¨†,x‰L „” …3 rªƒyØ+€ hI€‚P ƒ<ˆ€‡f˜ƒX€/ °qà†;ð#@ÃÙ€ („oÈ!ˆ€ þ6è>ˆèM$H`€ !šA€›ð…à)˜ †{°ƒp6 …ÛŠ†o€‡ù€ª0‚ 0…xøvx‡a(m  6€søP€­qp…#0€¸DØa‡{È»xxƒxr8'H€ „Ga°r‡oˆ‡g¸<-@^H8€8ƒ…hXЈ#°z‚"Ø0‚.pb:ð€ ‚:ÙÀt°„ }Ð…%(`ƒ9I€v„[²@(Ø‚í#à{¸6à†]8ƒLàL¸¼pƒw¯£þ%€à‚m(@@¨.°3 P~`‡\ˆ (*øƒhp p €ƒ<€7ƒ9؃àbø?8XèAà€È FP‚h„¸„%xkøƒVa+€(8W‚ HÈ€&×€H„j8Mˆ7H„˜CLcH„P€! 6È‚h\p…?Øš|;@„HÐYZBØ#ˆ 8ƒ^ÐJ˜†- ° Ð{¸R€@€˜^€ƒ € Àcø‡|`‡Dpçþu&X+(Eø‡Ø|€ ƒ=hv»k1è…n€¬ Ø€* „,0€&`C•(¸ h@؃ €ðWæGh8€æƒ{ „+`ÝI€h@‡|¸(¹´‚?¸\¸†q8†A(à¤Ô¡4à ƒ@[˜ç¾~kHÐlH`€08LàYr|õüý 'À M½–:‚`Ä<¼ãk•0ú„±ÃØ@§×.8D¾Ùg¬ŒˆXÂÇ)ŠbÐ*µ‹\–ªðá‘P€¦=ddKÇG„™g¡~•ƒÓÂÒ|QqþÓŽXN (!)Y5QV.¨Ðâã@…UnáÃ@Dœ=z<ÈÂʯ6"ˆ"§Ó,^º|{Ô¢€†PŸ`)s„šOøÒ…’€„* 4P{F‡„ôთl”4ý{ÄdÁ `Éû#c@’A†Üªd÷A`Ì`©1aK— l( µ+\=‘ ãP²wÒ1 ‘UâÅòb@„ Q©Œy“wïþýÆýù ’@)!†¡CM4¢°áœ&ï\rÂTäÉ+ɘÃÎ?úÄS|SÊØà‡$²#Ž<ôÜcÏ=¸ø @ Žü¢M4v˜þÿA!,b(0Â…¸Gk„Ä ÀB#ר‚ÆPp3Ž#9 ¨¢$Z(P‚vòÆl @'ñЂ|PℇäK € /Ë$SÆ @-ÚÀqJ>”@€° ÔbN4{¼°`@Ö8% iàáÇP#Ã3K#X¸ðÁW´‘È&Œ‘aÀ¢Ë1¿0Ñ&ùü£Ž'†0B(ÁA¦€S D Ì?ìXãHfP@ÿœr”ðÁ2ßÈqfuÒ‡šD¢Ä.¸Á 4ÊPbE"€/´rÍ! °Å,Kþ?ü,ƒI"i´p>L€6ŠрsTâI/Ó¨ƒO~ÿØó9·ü¡Û( E¤Q -Ü£ÌsŠ$A$« 3Ž:ÿÈãÏ'1Ž.d@pЍ¢ 8êÜÓ=üäÃIÜÇ&¶\ "Vð B”àcËH‡!bFâˆ!x”Ñ„5xR ,ˆTƒ¡×ñ®àcH ˜àÆjàPÂ5ˆ ?{À…œB3øðA/y S̶TГœH0flRdr†ÜÇ(·PL!aÄð–𳋠x°Ç ˆ@B¬ $ÅdcM0’Œ1þà / P \SÏ0½@£IlÔSŒ,…`RM7Å ¨…¼ƒ d0Ê;ß<²Æ!P0 @õèr80Â5²ÑT@=8ƒ"!Š^Œ"è€,‹i4ãh€ h s¨£ )`À@UЃ¡HD(¾‘ E\A€~Q=`jh&p±Œrø*?ú¸G=àá Zða È‘ X!«PÆ2®±Ž[dA(ÐÃ!<‘ m”cùðÇ2HXXã%Á ]Hƒ÷±Ç;üá Il $@ƒ!6ñ k€Ãå G;º‰`jðÃ" Q|þb„ D4€¨Í‰Ã«Ã™X â hC@ ì°‡h)æØÆ?àaˆ$À f€ ðAŒ7dà^#°„7F1ƒ”€°7`q _d¡è%8A%­à N<Æ5ºÑs”ã×pD Ђ9Ø!pøÒ€!Æ7Öñ gèb°È†;ÐQŒ;à´ ‚ʰ,Œ¡› 3º Eá5PF/Ä€8Aª˜DÛR àäC Šgƒ]Ü#Êp…2ð-Db¶H†%| A”€4¸QŽ>æc¬àB:p„ \  j°ÀÐŒm#þ´D €np‚`A"DQŠfˆcEüÈÏ>èvl#­X|ð™ *ˆ0Ñ‹p£øÀ‘‰]8ÃðèÇ?ÊÑ´A›A–HÌÂÜpG†èñ{@£}@ ÆI”Ùƒ…$¬Ð t $4áŠ_À£¸*°0Tb˜8ƒ$%IdaÈ#N`€àA-P@%l¡ [4£’U¢€A€#|ã_ˆ@ I¬!(BT dÀÕeÁúðJ”/ pô P°b¥-D  âƒ¨D*@шþ2  YcÚ6f¡ˆ0¨´È…ð€ €'ðÁŠ^D#¡p3Œá‡P”Q ‚j X@¬ Grp¯ˆ¿G9¢Á‡l¤¹°(( *\‰ÐÄ+h W,¢ ) ¸ ‚( p€là4$‚ÏÀ3"A‰fÀ" ÐÀLÑŠ`X#ôÐ~ú‘y¸ÃØ0F.bá‰DÔ +€€‚"À Èƒ&À@P‚ÄÀÆ7ê‘~\‚@>@€%С¯pF6ÚQ°|ðcòðF"n€€‘¬ü\ƒªƒ €[þ˜ƒþÀ X#Ãø…pO4À G:`…>  õÚƒ$À&¢ͪAÎІ;ôA 5«p>8¡¨B°)ha àA$`C@ãUPÀŽ€9ìÁ´kXF¢‚"d! q f Œ` qÐC!*ÁkW8b gI`P„/¤¡èzƒn b?VV0‘DÀX˜*‚ cpƒ¦€) 0¼°RðJ$@À†°…A0¢ŒÂP X ÃÞX…r„  gˆC¸ ÀL°ƒVpLT$¸þÀÂ@M4£Ãç°"z` ‚³h8àq‚Úü‡8f^‹UŒ"–ðô°ö™h@ lhƒº­ðHÖX‡†þ¡$ÀP& àB a´yö臆Új°B ˜‰ðÝ OxÃâ Pè"Ú¸Æ5’Q f`"@î19ô!pA²€ÌÁ{8C0€P@¸€L˜à¥‘ÀðDD%’@a /À<‡àaX,B&˜B,hBØ‹HÀäžHÀtÈ"ˆB,ìB18ƒ/TˆV¸ÝHh€þÀ Â0 è€ ´ŽHh˜#`B,hC1€ByÁP ø€ hЀ-Â^ÁLT  ÁL˜A(¤‚2Ã6€ƒ.Ø ´ÎÊÀ@lÀAÐÁ°ÁøA<Á 4 -€$A0)P•,T4€ä 2hÃ:Ð^í^õÃ=¼C:˜Ã4ƒ,¤)|‚&`B` ¬(@À`Á(‚'øB4¬>¸ƒ?ø+0H€ü€#pÂ.0C8¨<àGµƒ9d.$Bð€¬\9ÀÜÀ°AÄÁ ÂuÃþ"²Ã9`ƒ7Xƒ*PÁ@Œ@ÄA°Á,” ¨Á$‚(‚¼ÀÈŸH0@ ¼Ü@ À@"´A `Å$AAœ`œ $˜Á$B%°B/$-4BÈ@îÀpÀ ¸RÈ,B+C3T8èƒ=ă;´C;¬Ã8\C3 .°)˜#ÜÁ(VL€ „AäQ.(ƒ7´=|L>0_#B!P‚#hB)4œCŠà•>è= Ã6@1Ä‚#¨ÁTÁXtA€ÙÁ¼ÁDÂ'ô‚8¤C:ÈÃ>´C9¬ƒ7äB%ØêA°Áà$|&ˆ$G&B)<‚pÁ(HÁ! ‚´Aœ!”‚%‚"´tøÁÜ!XL8‹´SÎ!|Â/ÜÂ08ÃG9B$§pþˆAÔ´‚$ÀÂ3„ƒ8tƒ40C1øÂ,x‚ ¸A( ´@ øÀtÁ0Â4ÀDms‚AØA üPAÀˆÄ̤T@XA´ÁÌA´Á'¹`A¬ÁØÀJ@@F6$&È‚6dÃ6xÃ6(ƒ,€‚¤lD¼ètät’B*¤‚)ˆ‚&Â0È¡P@ÒiØ@­õA'è 8°œñ^å‡ááÃd¢Ã7TŒâÂ)ˆ'ü@,pÓ"x.Ã9Üâ>ÌÃbÉé/œ‚º˜+C6¨ƒ=äƒ}?ÐC:xƒþ4Ã-¨ÂžéÁüÐÁ  $„‚,,Ã8ÈC><Í=œƒÕqƒ5+ (è B$¨‚/ƒ-̯n‚&8‚(18Ã-€‚&TB#,¬A ‚$X‚'°D=!8‚$BB ÔA!,Bp@A>Fç¢2 ƒ3 H0È‚)PB $‚ÐÁÔ"ð D‚)ð‚4”ƒ:˜ƒ;lÃ1ðB-¨(p#$B!B"4‚" B 8, ШA¤xœ! ¬AÌ€4ÀKº]hØð Â8A p@ püAüAàÁ°A¤c"(Â'ÔþÂ1lƒ:¨ƒ8`C2è+lÂ$,Bº&©ô B-Ã…2ž'H!´xÀ¬\€ì@:vB/pƒ:øŠ?ô螢ÔÔ>ÜC<¨ÃLqC4èÂ,Èk'X#\+ÔRB)èB2¬:àÇ;¼Ã:ƒ7,„‚¬n5t)–ÚUù>ÌC;Œƒ4 ƒ.‚&H$8#0Â#L‚&x‚(À‚1h9ÄÃ?àÃåC>˜Ò50ƒ/¤‚(t#lÂ'¬,ÜB2Ã,Ä‚,Ø‚,Â*ø‚4C1Ô,°&<ÂÐŽ%|Â+´BgŽÂ)p‚+äB)€‚(xB&*<nRÂ!þ‚ ‚hÃ7œƒ:Ã4pæ*|B%,¶2"`Â$TÂ(äB]e'>àƒ<$«4ƒ-°‚(ˆÂDì#4‚%P&\Â!ü!‚%X‚%l(|‚ãIB\Á €À@ À0ÐÁ§°é'”Âà°@BÏF‚`zÂ%@ÂÚ …xÞ8¸Ã;´Ã9hÃ2à*|‚% "0B!è?à°;¤C8XC3 ×+@b(š'„B)œ‚)€B&T$`B)ÄÂbøB/ÐB+'H À4Ah`ƒJ‚*¨31û‚+Œ¿V‚‡*¨)t‚&|B{ƒ4|<„.š03Àk+\þ³Nc³-äB/0ƒ7”C9ˆƒ7\Ã3ƒ0u)tÂ$‚`DÁœ V*HÃ98&)c?ˆîòÂ=Ô8dÃ3¸µðžÂüC¨ÑÃUÉÙ ¯C9l5L¤Á,<|‘~ðÃd®dÂÃ:œ7”ó¯ùÂ.äÂ/2D7Ôêë…38ÛÃ<°9l%ƒ3<5È:˜Ã8€C7`C5\CÍ¡9„ƒ6H2œ³-ô/üÂ1DÃ5Xƒ4TÃ4¨¶7|ƒ6”34Œ¥5,CQ ð*øUÁƒ=Üp=¸9dÃ4(ß/è.ìBo3Ã4xƒ:ÌCJo*¨2¯ïb54ƒ1ƒbäB+þÀ-ÜB-ÄÂ?«Y.ó4¤¶3ä .À)TÉÖ¬™A B'˜‚ÿ^w68CC¿‚*”) ,ØÂ.ØÂ+¬‚+XV‘ÃpjÁDæ) D<¤C7´20$41 Ã4„C<< 3Gæ>à=´:ð;̃78ëÇœáñ8°è8œƒ;®q+ù:Ü­;ÄC’#º8 ö3Ô]4TƒL-â8”Ã8¤:;¨2þ9ƒ9$º8tw302C1·&>pê)êC.êu6Pƒ4PC‰ƒªÛƒ! ~<º´Çƒ*×:5@C²Ã1,ƒ34ƒ2ƒ0Ã1HC7pÐ:¬;”ƒ6„<ÀGx0ÜÂ*ˆÂ&̦Â"‚/«›G6lÃv¤{ªèÚýƒ6и6h¼=ÀYœqª÷<¼æ=¨´¤„~`½§²=¼C̆Ã7:¸Jÿ¦>œ"Ú£=~HþM«ßq¬s{?xÑŠÔÝ׋´|’×69ˆ8„C9°C<̃¸·;°Ã;ÈÃ<ÀC;ÀC< >eª:xƒ—kÃ7d'©…s©iÈF›Ã°› ·Ã<œ½§’2?H»<à±^s>w8üz8H>vÒ<Ø=éÊG[B5r*è¸(K9ЃùÞ;|C7pƒ6XÃuwƒ¶“uwÃ7ˆ9°Ã‘“r=hÕæß“¿C Ë™JƒnæÓ;„€3Ã0ðÂ+œê(”ÂÒ(8¸ÃÏGöç†.~Ä9^ùp¾mŸÃ9 @¨sGO¿ý%Ü·O_>‡"ô'1bÄ…ûòÕ“÷þÎ]¼yôîåÓ·°bEýø1̇_½z÷ôõ;©f͆øPêk9/ƒe"Di°ßSzòIJk÷Nl<ŽUƒŠ\yÏ^½yðÔóv š²dÈ’I㮾‘ûîÅ£º.Ý9tíÂÂãØî'¼¢ýFôÇ/ÔzôÜík_¾¬2O¢ô§¯^¼vç¾eCFl1cÉ aK'ïlÉ’ ‘sE«³ïöÖ¯£.)†Fú¯¢ôþIJ9µ´²çžÖbÉ5~°ƒï¨¤îù+žtÄçoÆQdz¬(¤Žžz𛧍{XdQÂõ*,n-®ô™ˆ¡¦òÑî?ö±ÊÈñfm¼!« , 6Ѱ«…h²Ï:¤’,O´³ºsɃ¤´ÒK+Q²ò:¤²=ÅˊɦöQ‹<“NúÒÌ2ÿI ´­ÈÌSOíœÍçêÑÌ.uÐQ' c;hBø(ÜŠ«7¹|4Í…ÎlóKáD¥|ì¡g|äi‡x>:ôË‚vÜÑÎ8­;¥´¨¼.¶ÿ’âî̉xŒé×vlÎê\M)ŸX5£C“}4P¼>×JKÓ÷^KR«…$E«89·°»õ(ª“%®ˆÂ Q)íÖ¤/—tÓ Xúî½g %üøÁIÎ{Ô3VY«Ä÷8~ÎÖ߀63K`ý5XÖ/gMXáûœ²Km¯+1AåtW€/NO^Y=éQ‚ž—¦‹PÆôŸ€;tkHTML-4ee7aaa953d6cb59/tests/page4/image4000064400000000000000000000000751151224263100173520ustar00nobodynobodyGIF89a€ÿÀÀÀ!ù,D;,L;tkHTML-4ee7aaa953d6cb59/tests/page4/image5000064400000000000000000000003111151224263100173440ustar00nobodynobodyGIF87aó 889YYZyy{‹¾¾½ÎÎÍÞÞÞÿÿÿ,@~ȈA æ4ICRž€"Ò¡¾pâ¹p ³(¦ƒ-—¾‘PÁˆ áD@‹…JŒd Š*‰i{’±»ê¨JFgˆ ”Ô…¶@ýBDÝÓ^,N¨uõ/i?\\VƒTCb*}c2a€!oBZ–>8gƒtlJ•1š;tkHTML-4ee7aaa953d6cb59/tests/page4/image6000064400000000000000000000003261151224263100173530ustar00nobodynobodyGIF87aó ,,)889PPRyy{‹¾¾½ÎÎÍÞÞÞÿÿÿ,@‹È) RK!#æDK¸ËPg1Œb&%m,/Áϳ""I=VË31`DA(!Üp‹A K)ÔŠ$²^qÜnL"d…æº0P‰@ÜaXØ-Å´_˜"sW(ˆ[-FW*&e!k,‚gmW>Ag}!€‚“”lnL¡1:;tkHTML-4ee7aaa953d6cb59/tests/page4/image7000064400000000000000000000002251151224263100173520ustar00nobodynobodyGIF87aò 889yy{‹¾¾½ÞÞÞÿÿÿ,@bº1eÇ”Ö*'ë¼ö6 æ›%–Ê'érÐ@ZQŋВ…À¸RàEÌ ‹Â8À)/‚S€Ì|ORÐ#h-¤Ár Ž©rzäE©ßžª¯5+€àüjâè$y ;tkHTML-4ee7aaa953d6cb59/tests/page4/image8000064400000000000000000000003131151224263100173510ustar00nobodynobodyGIF87aó$$ DDA]]Z}}{‹®®¬¾¾½ÞÞÞÿÿÿ,@€ÈÈA æ|Iq%ðzj%P(QTRÓ5ôÇíÕ$¦,V}¹IéÏAlÁVUˆέ[ 8@. ºEk£eÖ `ަX•ªkÒL”D‰EµÙq'^ž .(™oÑ€$ ŸÜg”E-Y×L>øúqß·cpÕ2p¹g ¸ÖxiêÀ'¬¨,ìûp tZTÂ5Uß,­BP»ç‚¹»FZœMrb,9“&G9ìr–Тo~>:DÚÕ5^Ï­ûÚdÈ쉺"'²g,tõ·km&˜'Ê`¤€ÿ (Àƒô$° Ðw[ (À•Bß­'Vlÿ•5š,A—Zoìeâ×kqµW‰+ÌÃ@3Ö8"̈׉°€<ÑXòÜk­¦Ö 2Ç‚#[p—¢ê9ç¢YÅ(Ïu¸]¨!4ævá•@¨Û}¤´_~ÃiBâgX,‹hJ‡®­¢CŽÀGÀŒ†É£Ÿòà¨á|óhæÏ7p†ˆŠ¿ ÷Š n‘éÂc÷Á%"–:zà+Žìħ< `¸'v ”*èŸôù´†“‰å·4ºÂ[v²8ž‡4IÄi;J@¨êXÂ8¦jèßÝ¡MV0‰ä.Í¢Rbg‰Öÿ“IÙt*#n Š:ã‚äB諪dÉ%’I¥Ù"dË·‚³¤9™µ¶~hâ®ɸã¯~^—}çàT¹ÚkúÉ ï$ø"6"Š™Þ‰ì¶Cr‹Vî .ÀÄúç ÿÖGVo ³›¦Ã‘å¨Ë)ˆóÇÌqâ:g6uNQÔÉó)Àj)!†I_w"áp‡¦„G\½+(²H‘SU£í¦F  F?‡úã¯Â~*цê3Î*¥ÔŠ‚€‡‰VØéšP9oë®QŽXYj„©@îÀ š@­¢é‚€+©°ÊÂÒÊ©ÉWëj”+wÅד^÷æSËX ÷uð¥g±ÕÏÿP#ºÖ2lµQÇ–gä•!˜ΰ`H±-:2#BÉ–éßÀ–ñÝ­¸¥gëòúPïí>>–hñ¶<­HªÔ,»(†ÏÕ®#•¯ÙçûÖœky£Ùžû“-&»8ë û^ÃW·ý» ³¬ví¢·mÂyòÚÜê:C̾廉Fçâ3åfˆ»]gÈ3$Ùůjvû5”Ñ>žü`Ëš—?M0/tãÛ‡ÓFãÀd¸ ¾˜+0V\̃:ta7ST¡ ¥øcà&H ò T¤ § …"˜ñƒpÁ!Û!ÈJÒˆM³$t9-xò“  ¥(GIÊRšò”¨L¥*WiÊ;tkHTML-4ee7aaa953d6cb59/tests/page4/index.html000064400000000000000000002267561151224263100202760ustar00nobodynobody [fm] welcome to freshmeat.net
      freshmeat.net
      find:
      linux.com partner
      news |
      appindex |
      editorials |
      lounge |
      contribute |
      feedback |
      about |
      awards |
      FAQ |

      sort by: [ date | name | urgency ]
       
      We should get this out of the door now
      scoop - January 29th 2000, 23:59 EST

      Everyone else is talking about it, so we should announce it ourselves before you start to think it's a government hoax. Server 51 is our new hosting service for Open Source projects, based on Super Cool Space Alien Technology(TM). We hadn't planned to announce it quite so soon, and it's still in the alpha stage as we work day and night at integrating SCSAT with our terrestrial systems, but feel free to take a look around and see what's going on. When we're out of the testing stage and ready to make room for your project, we'll send word via your implants. Be listening.

      [ comments (8) ]

       Category: freshmeat homepage  

      Is Linux for Crazies?
      jeff covey - January 29th 2000, 23:59 EST

      Ray Woodcock writes: "In terms relevant to Linux, this freshmeat editorial glances at the tendency of mainstream viewpoints to dismiss other viewpoints as 'fringe,' the propensity of dissident movements to splinter into factions before they can effectively counter their primary adversaries, and the difficulty of creating stability without squelching curiosity."

      [ comments (2), 2065 words in body ]

       Category: Editorial  

      RabbIT 2.0.2
      Ernimril - January 29th 2000, 18:29 EST

      RabbIt is the mutating, caching webproxy which is used to speed up surfing over slow links like modems. It does this by removing advertising and background images and scaling down images to low quality JPEGs. RabbIT is written in Java and should be able to run on any platform. It does depend upon an image converter if imagescaleing is on. The recommended image converter is "convert" from the ImageMagick package.

      Changes: Fixes have been made for a few bugs concerning keep alive and the HTTP response header, a bug with NT and cache directories, a bug concerning requests without a response body, a bug in GZIPHandler that caused it to not gzip already compressed (gzip or compress) streams, a bug in HTTPHeader regarding response phrases that are multiline, and a few bugs in ImageHandler and NCache. GZIPHandler has been built as an intermediate(*) to FilterHandler (this means that it is possible to gzip text/plain, etc., without filtering those streams) uuencoding has been added to the Coder, RabbIT now uses HTTP/1.1, HTMLParser now compiles cleanly with Jikes, and GeneralHeader has been created to allow for HTTPFooter (which is useful when sending chunked data).

      Urgency: low

      [ comments (0) ]

       License: freely distributable
       Category: Daemons/Proxy
      download homepage appindex record  

      nmpg 1.1.3
      Joel Lindau - January 29th 2000, 18:18 EST

      nmpg is a small command-driven frontend and network-jukebox for mpg123.

      Changes: Bugfixes, better memory managment, a new .nmpgrc parser, and new options.

      Urgency: low

      [ comments (0) ]

       License: OpenSource
       Category: Console/Sound
      download homepage changelog appindex record  

      mod_dtcl 0.7.3
      David Welton - January 29th 2000, 18:11 EST

      Mod_dtcl is a free/open source implementation of server-parsed Tcl under Apache. It allows you to tightly integrate HTML with Tcl, a widely-used scripting language with many years of development invested in it. There are also many external Tcl modules that you can load into mod_dtcl, to create images, access databases, etc.

      Changes: A major overhaul of header handling and internal buffering, and the addition of the ability to handle binary data.

      Urgency: low

      [ comments (0) ]

       License: GPL
       Category: Web/Development
      download homepage changelog appindex record  

      CoreLinux++ 0.4.6
      Frank V. Castellucci - January 29th 2000, 18:07 EST

      CoreLinux++ is an initiative to normalize methods and conventions for OOA/OOD/C++ development for Linux, materialized in a set of Open Source C++ class libraries (libcorelinux++ and libcoreframework++) to support common patterns and exploit the C++ standards.

      Changes: This release adds AbstractFactory and AssociativeIterator analysis, design, implementations, test code, a CVS daily tarball, a Patch Submission facility and updated FAQ, Web Pages, and defect reporting guidelines.

      Urgency: medium

      [ comments (0) ]

       License: LGPL
       Category: Development/Libraries
      download homepage changelog appindex record  

      scribe 0.2
      ChromeBob - January 29th 2000, 12:12 EST

      scribe writes functions prototypes for your C code, so you don't have to. It also compares unique functions between source code files and will 'extern' when appropriate. C++ methods support is also planned.

      Changes: A fix for an fflush() bug and better documentation.

      Urgency: low

      [ comments (0) ]

       License: GPL
       Category: Development/Tools
      download homepage appindex record  

      E theme updater 0.1
      Hallvar Helleseth - January 29th 2000, 12:04 EST

      E theme Updater is a bash script to automatically update all of your Enlightenment themes from e.themes.org.

      Changes: Initial release.

      [ comments (0) ]

       License: GPL
       Category: Console/Misc
      download homepage appindex record  

      Powertweak-Linux 0.1.7
      Dave Jones - January 29th 2000, 12:03 EST

      Powertweak-Linux is a port of the Microsoft Windows tool of the same name rewritten from the ground up. Its main function is to tune your system to its optimal performance settings. Currently, it tunes PCI chipsets and can set /proc/sys entries.

      Changes: A major GUI overhaul, the ability to generate configuration files, extended PCI information tabs, extra information support for the Matrox G200, and numerous other bugfixes & improvements.

      Urgency: low

      [ comments (2) ]

       License: GPL
       Category: Console/System
      download homepage changelog appindex record  

      Pexeso Beta
      Pavol Krigler - January 29th 2000, 11:55 EST

      pexeso is a simple graphic card game for one or two players.

      Changes: Initial public release.

      [ comments (0) ]

       License: Freeware
       Category: Console/Games
      download homepage appindex record  

      XZX 2.9.2
      E. Kunze - January 29th 2000, 11:54 EST

      XZX is a portable emulator of ZX Spectrum 48K/128K/+3 (8-bit home computers made by Sir Clive Sinclair) and Pentagon/Scorpion (Spectrum clones made in Russia) for machines running UNIX and the X Window system. XZX is completely written in C and emulates Spectrum 48K, 128K, +2 and +3, Pentagon and Scorpion, Interface I with up to 8 microdrives, Multiface 128 and Multiface 3, BetaDisk 128 interface by Technology Research Ltd with 4 disk drives, +D interface by Miles Gordon Technology with 2 disk drives, Kempston mouse, Kempston joystick and built-in machine code monitor.

      Changes: Lots of feature improvement and bug fixes. Most parts of the audio support has been rewritten for different UNICES.

      Urgency: low

      [ comments (0) ]

       License: Shareware
       Category: X11/Emulators
      download homepage changelog appindex record  

      DistroLib 0.4
      PhiR - January 29th 2000, 11:54 EST

      DistroLib is an abstraction library designed to make the development of distributed application easier. Its main target is currently compute-bound tasks based on a one server, many clients model (much like distributed.net), but it is quite generic and could be used for any client/server app. It is lightweight, easy-to-use, and relies heavily on threads.

      Changes: Important bug fixes and command history support.

      Urgency: low

      [ comments (0) ]

       License: GPL
       Category: Development/Libraries
      download homepage changelog appindex record  

      ToutDoux 1.1.7
      yeupou - January 29th 2000, 11:54 EST

      ToutDoux is a project manager which lets you design a plan of action using a tree structure, with translations in French and English.

      Changes: A new menu and XML standard for save files.

      Urgency: low

      [ comments (0) ]

       License: GPL
       Category: GNOME/Tools
      download homepage appindex record  

      goMP 1.0.3
      Gautier - January 29th 2000, 11:52 EST

      goMP is a set of CGI scripts that allows you to remotely control, via a Web browser, a computer acting as an MP3 jukebox. This program is very useful for someone who's got a dedicated computer with a lot of MP3 files but that doesn't have any output and input devices except network and sound card. It's main advantages are built-in cataloging, fast access to music, and no special software needed on the client side.

      Changes: Bugfixes, a password-protected config page, basic search function, easier installation thanks to an install script, and relocation of HTML docs and CGIs to a subdirectory.

      Urgency: medium

      [ comments (0) ]

       License: Artistic
       Category: Web/Tools
      download homepage changelog appindex record  

      APSEND 1.40
      M.K. - January 29th 2000, 11:50 EST

      APSEND is a TCP/IP packet sender to test firewalls and other network applications. It also includes a syn flood option, the land DoS attack, and a DoS attack against tcpdump running on a UNIX-based system. Future updates will include support for a scripting language to construct TCP packets and a few more options and protocols like UDP and ICMP. A port of APSEND from Perl to C is planned as well.

      Changes: The stream attack, bugfixes, and rewrites for parts of the code.

      Urgency: low

      [ comments (0) ]

       License: GPL
       Category: Console/Networking
      download homepage changelog appindex record  

      ecasound 1.6.12r10
      Kai Vehmanen - January 29th 2000, 11:48 EST

      Ecasound is a software package designed for multitrack audio processing. It can be used for simple tasks like audio playback, recording and format conversions, as well as for multitrack effect processing, mixing, recording and signal recycling. Ecasound supports a wide range of audio inputs, outputs and effect algorithms. Ecasound has a chain-based design that allows effects to be easily combined both in series and in parallel. Oscillators and MIDI-CCs can be used for controlling effect parameters. Includes a versatile console mode interface, a Qt-based X-interface and various command-line utils suitable for batch processing.

      Changes: Support for 24- and 32-bit audio formats and for ALSA 0.5, multichannel noisegate, a new 2nd order lowpass filter, some ia-mode commands, and various bugfixes and low-level improvements.

      Urgency: low

      [ comments (0) ]

       License: GPL
       Category: Console/Sound
      download homepage changelog appindex record  

      SCEZ 20000129
      endergone Zwiebeltuete - January 29th 2000, 11:46 EST

      SCEZ is a library that should make the handling of smart cards (not memory cards) and card readers as simple as possible and be at the same time small and easily portable. Currently supported are Dumb Mouse, CT-API and Towitoko readers and Schlumberger Cryptoflex, Gemplus GPK4000, GSM SIM and Telesec SigG cards. A PKCS#15 implementation is in the design phase. There are ports to PalmOS and MS-Windows available.

      Changes: More card and reader drivers, and an application to read out GSM SIM card (phone book and SMS) and write it to the card.

      Urgency: low

      [ comments (0) ]

       License: BSD type
       Category: Development/Libraries
      download homepage appindex record  

      Comicq 0.2.0
      Terminal6 - January 29th 2000, 11:45 EST

      COMICQ is a command line ICQ messaging tool that allows a user to connect to ICQ using your UIN and password, then sends a message to the destination UIN.

      Changes: Several bugfixes, icq99a compliance, and a new option --ip that allows you to get any user's IP by their UIN.

      Urgency: low

      [ comments (0) ]

       License: GPL
       Category: Console/Communication
      download homepage appindex record  

      senv 0.2
      Zbyszek Sobiecki - January 29th 2000, 11:44 EST

      Senv allows you to run programs with a specified environment. It can set uid, gid, root directory, working directory, limits, and environment variables. It is useful in init scripts and as a shell for users for setting resource limits and environment variables. You can create sets of configurations and specify the one to use from command line.

      Changes: Login shell limits and environment setting for users, permanent resource limits for specified groups of users and environment variables, and other minor bugfixes.

      Urgency: low

      [ comments (0) ]

       License: GPL
       Category: Console/Administration
      download changelog appindex record  

      XZX 2.9.2
      E. Kunze - January 29th 2000, 10:55 EST

      XZX is a portable emulator of ZX Spectrum 48K/128K/+3 (8-bit home computers made by Sir Clive Sinclair) and Pentagon/Scorpion (Spectrum clones made in Russia) for machines running UNIX and the X Window system. XZX is completely written in C and emulates Spectrum 48K, 128K, +2 and +3, Pentagon and Scorpion, Interface I with up to 8 microdrives, Multiface 128 and Multiface 3, BetaDisk 128 interface by Technology Research Ltd with 4 disk drives, +D interface by Miles Gordon Technology with 2 disk drives, Kempston mouse, Kempston joystick and built-in machine code monitor.

      Changes: Lots of feature improvement and bug fixes. Most parts of the audio support has been rewritten for different UNICES.

      Urgency: low

      [ comments (0) ]

       License: Shareware
       Category: X11/Emulators
      download homepage changelog appindex record  

      [ full page for today | yesterday's edition ]
      navigator
      - full page for today
      - yesterday's edition
      - new: fm news via NNTP
       

      eye catcher
      Free Shirts
      We give away a free freshmeat t-shirt every week for the best comment added to an application announcement or story posted on freshmeat.

      #freshmeat
      If you want to chat about what's new on freshmeat and hang out with other fm lounge lizards and the fm staff, head over to #freshmeat on irc.freshmeat.net, part of The Open Projects Network.  

      site notes
      - We should get this out of the door now (Jan 29th)
      - freshmeat Y2K report (Jan 01st)
      - Assorted freshmeat notes (Aug 16th)
       

      recent editorials
      - Is Linux for Crazies? (Jan 29th)
      - A New Business Plan for Free Software (Jan 22nd)
      - Is Linux Going to Reunite the UNIX Market? (Jan 15th)
       

      andover.net

      Mirror Logo

      - Animation Factory
      - DaveCentral
      - FreeCode
      - Internet Traffic Report
      - IT Manager's Journal
      - MediaBuilder
      - Slashdot
      - Slaughterhouse
      - TechMailings
      - TechSightings

      E-Commerce

      - ThinkGeek (Stuff for smart masses)
       

      supported sites
      - Userfriendly.org
      - SecurityFocus
      - copyleft
      - Filewatcher
      - Linux.com
      - LinuxTelephony
      - LinuxToday
      - Openprojects
      - 32bitsonline
      - The GNU Project
       

      saturday
      - We should get this out of the door now
      - Is Linux for Crazies?
      - RabbIT 2.0.2
      - nmpg 1.1.3
      - mod_dtcl 0.7.3
      - CoreLinux++ 0.4.6
      - scribe 0.2
      - E theme updater 0.1
      - Powertweak-Linux 0.1.7
      - Pexeso Beta
      - XZX 2.9.2
      - DistroLib 0.4
      - ToutDoux 1.1.7
      - goMP 1.0.3
      - APSEND 1.40
      - ecasound 1.6.12r10
      - SCEZ 20000129
      - Comicq 0.2.0
      - senv 0.2
      - XZX 2.9.2
      - log4j 0.7.5
      - SQN Linux 1.6
      - Limo 0.3.2
      - Fusion GS 1.3
      - MMR 1.5.4
      - KUPS 0.3.4
      - 3DSE patch for XMMS 4
      - Linux 2.3.41
      - Free Code for Linux S/390
      - CircleMUD 3.0 beta patchlevel 17
      - NiL Isn't Liero 000128
      - OpenSSH Unix Port 1.2.2
      - KBoxes! 1.3
      - phpLanParty 0.23
      - DGen/SDL 1.20
      - EdcomLib 1.0 alpha 5
      - Etherboot 4.4.2
      - BLADE 0.18.0
      - Sapphire 0.13.7
      - ippl 1.99.3
      - Saint 1.5patch1
      - Zircon 1.18.232
      - nmap 2.3BETA14
      - xterm patch #124
      - MyThreads-Links v0.5.2
      - sudo 1.6.2p1
      - MIT Photonic-Bands 0.10
      - Launcher 0.86
      - nano 0.8.1
      - Gtk-- 1.1.8
      - tkchooser 0.65
      - XShipWars 1.33a
      - Lamerpad 0.1
       

      friday
      - fsv 0.9
      - popsneaker 0.1.1
      - eyep-updater.sh 1.0
      - W3Mail 0.5.0
      - The Urgent Decision 0.9.9
      - LTSP 1.02
      - Production BASIC 0.2.12
      - Postfix 19991231-pl03
      - Mp3 Commander 0.7
      - iManager 1.0.1b
      - Eterm 0.9
      - dqd_dirindex 1.0
      - Tidings 1.0.4
      - localscan 2.1
      - WMKeyboard 0.3
      - fcmp 1.0.2
      - Akkord 0.3.1
      - HiM 0.1.1
      - cdrecord 1.8
      - eMixer 0.05.5
      - FreeVSD 1.4.0
      - Common C++ Libraries 0.0
      - Moonshine 1.0beta2
      - swim 0.3.5
      - Xmame/xmess 0.36b15.1
      - pcmcia-cs 3.1.9
      - gPS 0.5.2
      - Snort 1.5.1
      - Pygmy Linux 0.7 beta
      - Intro to Bash Programming HOWTO 0.3
      - GNU Pth 1.3b2
      - Laonux 0.1
      - x-wvdial 0.12
      - Intro to Bash Programming HOWTO 0.3
      - Catalog 1.02
      - harvest 1.5.20-kj-0.9
      - wmseti 0.3.0a
      - RIG 1.02
      - FreeAddr 0.2
      - GtkAda 1.2.5
      - dot.conf 0.6.0
      - dep.pl 1.28.0
      - Prae's Scripts 1.1
      - Project Clock 0.1
      - Xtheater 0.2.1
      - i-no Chart 0.1
      - spliff 0.8.1
      - Regexx 0.95
      - RBook 0.5.0
      - RIG 1.01
      - wchat 1.2.0
      - PCCS MySQLDatabase Admin Tool 1.2.2
       

      thursday
      - CADUBI 1.1b1
      - Angus' Chess Clock 0.8.1
      - MP3 Report Generator 1.0.0
      - 4DOM 0.9.2
      - 4XSLT 0.8.2
      - OpenNaken 1.10
      - iManager 1.0b
      - QuakeForge 0.1.0
      - pylice 0.7.0
      - Solfege 0.6.0
      - xinetd 2.1.8.7p1
      - jac 0.13
      - Xmms 1.0.0
      - KSrnd 0.97
      - getpg / UW-IMAP 0.54
      - getpg 0.53
      - setserial 2.17
      - Pan 0.7.3
      - jwhois 2.4.1
      - Kmp3 1.0
      - xPine 0.0.12
      - Avenger's News System 2.1 Alpha
      - RIG 1.0
      - scroller 1.0
      - Perl EyeP Client 0.1
      - sfront 0.54
      - XFrisk 1.2
      - Moffy 0.0.1
      - Solid POP3 0.14
      - php3guest 1.5
      - crUD 01.27.2000
      - crUD 01.27.2000
      - Free Pascal Compiler 0.99.14
      - gtk-font-hack 0.2-gtk-1.2.6
      - Linux 2.2.15pre5
      - krunseti 0.2.1
      - CompuPic 5.0.1036
      - gfontview 0.3.3
      - authlocal 1.0.2
      - bigwig 1.1
      - CAFire 0.0.11
      - ANVLOGIN 2.0
      - sawmill.el 1.9
      - Perlsh 20000127
      - sitescooper 2.1.2
      - MHDns 1.4
      - JChemPaint 0.5
      - Filesystems HOWTO 0.7.3
      - KSnes9x 1.2
      - Mozilla M13
      - edna 0.3
      - GMasqdialer 0.99.8
      - spliff 0.8
      - MultiSeti 0.3
      - rude 0.50
      - cgi-util++ 0.0
      - Cricket 0.72
      - nuni 0.04
      - Ksetiwatch 0.3.0
      - SiteMgrYAP 0.1.2
      - phpLanParty 0.21
      - Glitter Newsreader 0.1
      - Fastresolve 2.4
      - ColdSync 1.1.2
      - DDD 3.2
      - X Northern Captain 4.2.1
      - abcde 1.0.2
      - Gnapster 1.3.2
      - xmix 1.0 Alpha
      - gtktetcolor 0.3
      - muttzilla 0.40
      - muttzilla 0.40
      - asp2php 0.73.6
      - mod_ticket 1.0
      - MegaHAL for Eggdrop .01
      - Jetty 2.3.5
      - xlpotdb 1.0
      - Koala Complete MUD Server 0.1.1a
      - mcountd 0.4
      - cdbackup 0.5.0
      - The Java SSH/Telnet Application/Applet 2.0 RC1
       

      slashdot
      - Petition Apple for Linux QuickTime
      - GNUstep 0.6.5 freeze
      - YETI@Home
      - Documents Unsealed in Microsoft/Caldera Case
      - Who Bought Linux.Net?
      - E-Mails from (Over?) The Edge
      - Linux Kernel 2.3.41
      - Congress Still Figuring Out E-Mail
      - Sci Fi Literature 101?
      - Could Distributed.Net Help the Mars Polar Lander?
       

      securityfocus
      - Win2000 security hole a 'major threat'
      - Visa acknowledges cracker break-ins
      - What's Wrong With Microsoft Security?
      - Microsoft posts first Win2K security patch
      - Libnids 1.12
      - New hack attack is greater threat than imagined
      - Student charged with hacking
      - Building and Managing Virtual Private Networks (book)
      - Threats, Vulnerabilities and Real-Worl Responses: The Foundations of the TruSecure Process
      - The Hundredth Window : Protecting Your Privacy and Security in the Age of the Internet (boo
       

      bebits
      - Pe 3.0a3
      - Rarscript 1.5
      - CD Manager 0.66a beta
      - TraX 1.1
      - BeMath 1.2.2
      - simple blackjack 1
      - HtmlTree 0.5.3
      - Yacp 0.1
      - TicTacToe 1.5
      - Pe 3.0a2
       

      linuxtoday
      - Linux Journal: KDE--The Next Generation
      - Kernel Cousin gimp-devel #11 Is Out
      - Infoworld: Corel Linux OS ideal for the desktop
      - Technology Evaluation: IBM Jumps on the Linux Bandwagon with Both Feet, Sort Of
      - Tobias Hövekamp: European Union acknowledges
      - &
      - #34;Open Source Software
      - &
      - #34;
       

      linuxtelephony
      - Traverse Technologies releases NETspider-U in US
      - Quicknet releases new GPL'd Linux Drivers!
      - Natural Microsystems Delivers Carrier-Class Linux
      - Quicknet is hiring programmers of all kinds!
      - Babylon MLPPP Software Released under GPL
      - Linux Telephony Server Project?
      - Vovida Networks to Hire Telephony Software Engineers
      - SPIRO-Linux Introduces Web-Enabled Phone Administration
      - LinuxTelephony sponsors area at LinuxFest 2000
      - GSM-Mobile Switching Center (MSC) with Linux-PC
       

      32bitsonline
      - Game: Homeworld
      - DVD Lawsuit Spreads Its Own 'Trade Secrets'
      - Register.com Adds 'One-step' Domain Registration
      - WebEvent: Keeping you organized
      - Y2K Officers Defend $100 Bil Investment
      - DON'T BE FOOLED
      - Microsoft Scorns Think-Tank's Breakup Idea
      - Yahoo Accused Of Stalking Internet Users
      - eToys.com Settles Spat With Swiss Artist Group
      - [more articles/news]
       



      copyright © 1997-2000 Andover.Net - icons courtesy of tigert@gimp.org - code revision 20000101 - our privacy policy
      tkHTML-4ee7aaa953d6cb59/tests/reset.test000064400000000000000000000035071151224263100173070ustar00nobodynobody # This test script tests that Tkhtml3 behaves well when the # [$widget reset] method is called from with a node-handler # callback. This happens in Hv3 when a node specifies # a charset for the document. # proc sourcefile {file} { set fname [file join [file dirname [info script]] $file] uplevel "#0" [list source $fname] } sourcefile common.tcl set ::DocumentOne {
      123
      } set ::DocumentTwo {
      456
      } html .h .h handler node meta meta_node_handler proc meta_node_handler {n} { if {[$n attr id] eq $::iReset} { .h reset if {$::doParse == 1} { .h parse -final $::DocumentTwo } elseif {$::doParse == 2} { set ::doParse 1 .h parse -final $::DocumentOne } } } proc get_div_contents {} { set n [.h search div -index 0] if {$n eq ""} { set res "" } else { set res [[lindex [$n children] 0] text] } set res } # Run some tests with a few different values for global variables # ::doParse and ::iReset (used by proc [meta_node_handler] above). # foreach {test_number ::iReset ::doParse result} [list \ 1 n/a n/a 123 \ 2 1 0 "" \ 3 1 1 456 \ 4 1 2 456 \ 5 2 0 "" \ 6 2 1 456 \ 7 1 2 456 \ ] { tcltest::test reset-1.$test_number {} -body { .h reset .h parse -final $::DocumentOne get_div_contents } -result $result } finish_test tkHTML-4ee7aaa953d6cb59/tests/style.bt000064400000000000000000000014131151224263100167450ustar00nobodynobody #------------------------------------------------------------------------ # This is a "warm-body" test for the events module. # do_browser_test style.1 -timeout 10000000 -html {
      } -javascript { var div = document.getElementById("div"); return div.style.borderTopWidth } -expected "" do_browser_test style.2 -timeout 10000000 -html {
      } -javascript { var div = document.getElementById("div"); return div.style.borderTopWidth } -expected 22px do_browser_test style.3 -timeout 10000000 -javascript { return parseInt("") } -expected NaN do_browser_test style.4 -timeout 10000000 -javascript { var b = 8911 b = b - parseInt("") return b } -expected NaN tkHTML-4ee7aaa953d6cb59/tests/style.test000064400000000000000000000327011151224263100173230ustar00nobodynobody #--------------------------------------------------------------------- # This file contains automated tests for the Tkhtml stylesheet parser. # # Test script for Tkhtml proc sourcefile {file} { set fname [file join [file dirname [info script]] $file] uplevel #0 [list source $fname] } sourcefile common.tcl # Test organization for tests in this file. # # style-1.*: Tests the parsing of 'background-position' property values. # style-2.*: Tests the parsing of 'background' property values. # style-5.*: Tests some intentional stylesheet syntax errors observed # in the wild used to mask an @import directive. Apparently # one of the "IE-hacks". # # style-7.*: Security test. Tests that only a default stylesheet can # specify "tcl()" property values. If this were not the # case web pages could cause arbitrary scripts to be # executed in the applications interpreter. # # style-8.*: Tests that Tkhtml handles certain types of syntax errors # in stylesheets. Specifically, these test cases come # from the malformed selectors in the "acid2" test. # html .h .h handler script style styleHandler proc styleHandler {attr data} { .h style $data } proc property {node prop} { array set properties [$node prop] return $properties($prop) } #-------------------------------------------------------------------------- # Test cases style-1.* test the parsing of the 'background-position' property. # proc background-position {node} { return [list \ [$node property background-position-x] \ [$node property background-position-y] \ ] } proc test_background_position {name style value} { .h configure -defaultstyle "" .h reset .h style "div {background-position: $style}" tcltest::test $name {} -body { .h parse -final {
      } set node [lindex [.h search div] 0] background-position $node } -result $value # puts [.h styleconfig] } test_background_position style-1.0 "50% 50%" {50.0% 50.0%} test_background_position style-1.1 "center center" {50.0% 50.0%} test_background_position style-1.2 "111 222" {0px 0px} test_background_position style-1.3 "right" {100.0% 50.0%} test_background_position style-1.4 "blah" {0px 0px} #-------------------------------------------------------------------------- # Test cases style-2.* test the parsing of the 'background' property. # tcltest::test style-2.0 {} -body { .h reset .h parse -final {
      } set node [lindex [.h search .one] 0] background-position $node } -result {0px 0px} tcltest::test style-2.1 {} -body { property $node background-color } -result {black} # Note: in quirks mode the result would be {50px 100px} tcltest::test style-2.2 {} -body { set node2 [lindex [.h search .two] 0] background-position $node2 } -result {0px 0px} tcltest::test style-2.3 {} -body { property $node2 background-repeat } -result {no-repeat} #-------------------------------------------------------------------------- # Test cases style-3.* test some selectors # tcltest::test style-3.0 {} -body { .h reset .h parse -final { Hello Hello } set node [lindex [.h search i] 0] property $node color } -result {red} tcltest::test style-3.1 {} -body { set node [lindex [.h search b] 0] property $node color } -result {red} #-------------------------------------------------------------------------- # The following tests (style-4.*) test the parsing of stylesheets. # proc parse_stylesheet {stylesheet_text} { html .newwidget -defaultstyle "" .newwidget style $stylesheet_text set ret [list] foreach r [.newwidget styleconfig] { lappend ret [lrange $r 0 1] } destroy .newwidget return $ret } # # Test 4.1 tests the bug reported by ticket #43. The embedded stylesheet # contains an error - a ":" character is missing from a declaration. The # correct behaviour is to ignore the broken declaration and resume # parsing after the following semi-colon. In other words, the style-sheet # specified in the
      } set node [lindex [.h search div] 0] property $node color } -result red tcltest::test style-8.2 {} -body { .h reset .h configure -defaultstyle "" .h parse -final {
      } set node [lindex [.h search {#1}] 0] property $node color } -result red tcltest::test style-8.3 {} -body { .h configure -defaultstyle "" .h reset .h parse -final {
      } set node [lindex [.h search .eyes] 0] property $node position } -result static tcltest::test style-8.4 {} -body { .h reset .h configure -defaultstyle "" .h parse -final {
      } set node [lindex [.h search .eyes] 0] property $node position } -result absolute tcltest::test style-8.5 {} -body { .h reset .h configure -defaultstyle "" .h parse -final {
      } set node [lindex [.h search div] 0] property $node background-color } -result yellow tcltest::test style-9.1 {} -body { .h reset .h configure -defaultstyle "" .h parse -final {

      } set node [lindex [.h search p] 0] property $node color } -result {green} tcltest::test style-9.2 {} -body { parse_stylesheet { p ! p {color: purple;} } } -result {} tcltest::test style-9.3 {} -body { parse_stylesheet { p {COLOR: PURPLE;} } } -result [list {p color:PURPLE}] tcltest::test style-9.4 {} -body { parse_stylesheet { @three-dee { @background-lighting { azimuth: 30deg; elevation: 190deg; } P.seven { color: red } } P.eight {COLOR: GREEN;} } } -result [list {p.eight color:GREEN}] #---------------------------------------------------------------------------- # The following tests - style-10.* - test that the 'line-height' property # is parsed and applied to elements correctly. # tcltest::test style-10.1 {} -body { .h reset .h parse -final {

      } set res [list] foreach class [list .one .two .three .four .five] { lappend res [[lindex [.h search $class] 0] property line-height] } set res } -result [list normal 10px 130px 2.00 normal] #---------------------------------------------------------------------------- # The following tests - style-10.* - test property and override method. # tcltest::test style-11.1 {} -body { .h reset .h parse -final {

      foo

      bar
      baz
      } pack .h set n [.h search {div[id="inner"]}] # wish: ./src/htmlprop.c:3035: HtmlNodeGetProperty: # Assertion `eProp <= 108' failed. $n property background } -result [list none repeat scroll 0% 0%] tcltest::test style-11.2 {} -body { $n override } -result {} tcltest::test style-11.3 {} -body { # Missusing of trailing ':' set res [$n override {background-color: red}] after idle [list set ::wait 1] vwait ::wait # wish: ./src/htmlprop.c:300: getPropertyDef: # Assertion `eProp >= 0' failed. set res } -result {background-color: red} tcltest::test style-11.4 {} -body { set res [$n override {background-color red}] } -result {background-color red} #---------------------------------------------------------------------- finish_test tkHTML-4ee7aaa953d6cb59/tests/syntax.test000064400000000000000000000076071151224263100175200ustar00nobodynobody # Test script for Tkhtml # # This file contains test cases that ensure the handling of syntax # errors in stylesheets is consistent with other interpretations of # the various CSS specs. # # Interfaces: # # pathName style TEXT # pathName parse -final TEXT # pathName search SELECTOR # nodeHandle property PROPERTY-NAME # # Standard test file code. proc sourcefile {file} { set fname [file join [file dirname [info script]] $file] uplevel #0 [list source $fname] } sourcefile common.tcl html .h -defaultstyle "" proc syntaxtest {name args} { array set a $args .h reset .h parse -final $a(-document) .h style $a(-style) tcltest::test $name {} -body $a(-body) -result $a(-result) } #--------------------------------------------------------------------- # The following tests - syntax-1.* - come from the selectors # in the acid2 page. # syntaxtest syntax-1.0 -style { div { background: yellow /* comment */ no-repeat /* comment */ ; } } -document {
      } -body { set node [lindex [.h search div] 0] $node property background-color } -result yellow syntaxtest syntax-1.1 -style { [class~=one].first.one {color: red} } -document {
      } -body { set node [lindex [.h search div] 0] $node property color } -result red syntaxtest syntax-1.2 -style { [class~=one][class~=first] [class=second\ two][class="second two"] {color : red} } -document {
      } -body { set node [lindex [.h search {#1}] 0] $node property color } -result red syntaxtest syntax-1.4 -style { /* Note the syntax error in the next line! */ [class=second two] { background: red; } .eyes { position: absolute } } -document {
      } -body { set node [lindex [.h search .eyes] 0] $node property position } -result absolute #--------------------------------------------------------------------- # The selector in this test case - syntax-2.0 - comes from # "http://www.freenigma.com". This should just be handled as a # syntax error (ignore the whole declaration): # # a:* { # text-decoration: none; # color: #436976; # } # syntaxtest syntax-2.0 -style { * {color: black;} a:* { text-decoration: none; color: #436976; } } -document { Hello } -body { set node [lindex [.h search a] 0] $node property color } -result black # # Also from www.freenigma.com: # # @CHARSET "UTF-8"; # # div.content h1 { color: red } # #--------------------------------------------------------------------- # The selector in this test case - syntax-3.0 - tests a problem found at # "http://www.yahoo.com". The lines prefixed with "*" should be skipped, # the others respected. # # Apparently people have figured out that the following are all legal # ways of commenting out a property/value pair in CSS: # # selector { # *prop: value; # # prop: value; # // prop: value; # } # syntaxtest syntax-3.0 -style { div { text-decoration:underline; *color:red; color:green; *text-decoration:strikethrough; } } -document {
      Hello
      } -body { set node [lindex [.h search div] 0] list [$node property color] [$node property text-decoration] } -result {green underline} syntaxtest syntax-3.1 -style { div { text-decoration:underline; // color:red; color:green; # text-decoration:strikethrough; } } -document {
      Hello
      } -body { set node [lindex [.h search div] 0] list [$node property color] [$node property text-decoration] } -result {green underline} #--------------------------------------------------------------------- syntaxtest syntax-4.0 -style { @media all and (min-width: 0px) { #primary { margin-left: 0px; padding-left: 0; } } div {color:green} } -document {
      Hello
      } -body { set node [lindex [.h search div] 0] $node property color } -result {green} finish_test tkHTML-4ee7aaa953d6cb59/tests/tkhtml.tcl000064400000000000000000000101641151224263100172700ustar00nobodynobody# # tkhtml.tcl -- # # This file contains: # # - The default bindings for the Html widget, and # - Some Tcl functions used by the stylesheet html.css. # # ------------------------------------------------------------------------ # # Copyright (c) 2005 Eolas Technologies Inc. # All rights reserved. # # This Open Source project was made possible through the financial support # of Eolas Technologies Inc. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are met: # # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # * Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # * Neither the name of the nor the names of its # contributors may be used to endorse or promote products derived from # this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. # # Default bindings # # bind Html { focus %W } bind Html { %W yview scroll -1 units } bind Html { %W yview scroll 1 units } bind Html { %W yview scroll 1 units } bind Html { %W xview scroll 1 units } bind Html { %W xview scroll -1 units } bind Html { %W yview scroll 1 pages } bind Html { %W yview scroll 1 pages } bind Html { %W yview scroll -1 pages } bind Html { %W yview scroll -4 units } bind Html { %W yview scroll 4 units } # Some Tcl procs used by html.css # namespace eval tkhtml { proc len {val} { if {[regexp {^[0-9]+$} $val]} { append val px } return $val } proc color {val} { set len [string length $val] if {0==($len % 3) && [regexp {^[0-9a-fA-F]*$} $val]} { return "#$val" } return $val } swproc attr {attr {len 0 1} {color 0 1}} { upvar N node set val [$node attr -default "" $attr] if {$val == ""} {error ""} if {$len} {return [len $val]} if {$color} {return [color $val]} return $val } swproc aa {tag attr {len 0 1} {if NULL} {color 0 1}} { upvar N node for {} {$node != ""} {set node [$node parent]} { if {[$node tag] == $tag} { if {[catch {$node attr $attr} val]} {error ""} if {$if != "NULL"} {return $if} if {$val == ""} {error ""} if {$len} {return [len $val]} if {$color} {return [color $val]} return $val } } error "No such ancestor attribute: $tag $attr" } proc create_image_tile {img} { set w [image width $img] set h [image width $img] if {$w <= 0 || $h <= 0} {error "empty image"} set tw [expr int(200 / $w) * $w] set th [expr int(200 / $h) * $h] if {$tw == 0} {set tw $w} if {$th == 0} {set th $h} set newimg [image create photo] $newimg copy $img -from 0 0 -to 0 0 $tw $th return $newimg } } tkHTML-4ee7aaa953d6cb59/tests/tree.tcl000064400000000000000000000014651151224263100167300ustar00nobodynobody set auto_path [concat . $auto_path] package require Tkhtml # Procedure to return the contents of a file-system entry proc readFile {fname} { set ret {} catch { set fd [open $fname] set ret [read $fd] close $fd } return $ret } proc print_tree {node {indent 0}} { if {[$node tag]=="text"} { if {[regexp {^ *$} [$node text]]==0} { puts -nonewline [string repeat " " $indent] puts [$node text] } } else { puts -nonewline [string repeat " " $indent] puts "<[$node tag]>" for {set i 0} {$i < [$node nChildren]} {incr i} { print_tree [$node child $i] [expr $indent+2] } puts -nonewline [string repeat " " $indent] puts "" } } html .h .h parse [readFile [lindex $argv 0]] .h tree build set root [.h tree root] print_tree $root exit tkHTML-4ee7aaa953d6cb59/tests/tree.test000064400000000000000000000145711151224263100171270ustar00nobodynobody# Tkhtml test file proc sourcefile {file} { set fname [file join [file dirname [info script]] $file] uplevel #0 [list source $fname] } sourcefile common.tcl set ::script_handler_count 0 proc scriptHandler {attr data} { incr ::script_handler_count return "" } proc get_tree {{indent 0} {node ""}} { if {$node eq ""} { set node [.h node] } set output [string repeat " " $indent] set tag [$node tag] if {$tag eq ""} { append output "[$node text -tokens]\n" } else { append output "<${tag}>\n" } foreach child [$node children] { append output [get_tree [expr $indent + 2] $child] } if {$tag ne ""} { append output [string repeat " " $indent] append output "\n" } return $output } #-------------------------------------------------------------------------- # Test cases tree-1.* test the [widget handler script ...] command, # including in conjunction with incremental document parsing. # tcltest::test tree-1.0 {} -body { html .h .h handler script script scriptHandler set ::script_handler_count } -result 0 tcltest::test tree-1.1 {} -body { .h parse -final [string trim {

      Hello World

      Hello Again World }] set ::script_handler_count } -result 1 tcltest::test tree-1.2 {} -body { string trim [get_tree] } -result [string trim { {space 4}

      {text Hello} {space 1} {text World} {newline 1} {space 4} {newline 1} {space 4}

      {text Hello} {space 1} {text Again} {space 1} {text World} {newline 1} {space 4} {newline 1} {space 4}

      }] tcltest::test tree-1.3 {} -body { .h reset .h parse [string trim {

      Hello World

      Hello Again World }] set ::script_handler_count } -result 2 tcltest::test tree-1.4 {} -body { string trim [get_tree] } -result [string trim { {space 4} {space 4}

      {text Hello} {space 1} {text World} {newline 1} {space 4} {newline 1} {space 4}

      {text Hello} {space 1} {text Again} {space 1} {text World} {newline 1} {space 4} {newline 1} {space 4}

      }] tcltest::test tree-1.5 {} -body { .h reset .h parse [string trim {

      Paragraph one }] .h parse -final [string trim {

      Paragraph two }] set ::script_handler_count } -result 3 tcltest::test tree-1.6 {} -body { string trim [get_tree] } -result [string trim { {space 4} {newline 1} {space 4}

      {text Paragraph} {space 1} {text one}

      {text Paragraph} {space 1} {text two}

      }] tcltest::test tree-1.7 {} -body { .h reset .h parse -final { } set ::script_handler_count } -result 4 #-------------------------------------------------------------------------- # Test cases tree-2.* test that ticket #12 has been fixed. # tcltest::test tree-2.1 {} -body { .h reset .h parse -final {Hello World} string trim [get_tree] } -result [string trim { {text Hello} {space 1} {text World} }] #-------------------------------------------------------------------------- # Test cases tree-3.* test the [fragment] API. # tcltest::test tree-3.1.1 {} -body { set ::nodelist [.h fragment {}] llength $::nodelist } -result 1 tcltest::test tree-3.1.2 {} -body { set ::node [lindex $::nodelist 0] $::node tag } -result img tcltest::test tree-3.1.3 {} -body { $::node attr src } -result bg.gif tcltest::test tree-3.1.4 {} -body { $::node parent } -result "" tcltest::test tree-3.1.5 {} -body { .h reset set rc [catch {$::node attr src} msg] list $rc $msg } -result [list 1 "invalid command name \"$::node\""] tcltest::test tree-3.2.1 {} -body { set ::nodelist [.h fragment {
      hello
      text}] llength $::nodelist } -result 2 tcltest::test tree-3.2.2 {} -body { set ::textnode [lindex $::nodelist 1] $::textnode text -tokens } -result [list {space 2} {text text}] tcltest::test tree-3.2.3 {} -body { set ::divnode [lindex $::nodelist 0] $::divnode tag } -result div tcltest::test tree-3.2.4 {} -body { set ::divchild [lindex [$::divnode children] 0] $::divchild text } -result hello tcltest::test tree-3.2.5 {} -body { .h reset set rc [catch {$::divchild text} msg] list $rc $msg } -result [list 1 "invalid command name \"$::divchild\""] tcltest::test tree-3.3.1 {} -body { .h parse -final "
      " set ::nodelist [.h fragment "some text"] string trim [get_tree] } -result [string trim {
      }] tcltest::test tree-3.3.2 {} -body { set div [.h search div] $div insert [lindex $::nodelist 1] string trim [get_tree] } -result [string trim {
      }] tcltest::test tree-3.3.3 {} -body { set div [.h search div] $div insert -before [lindex [$div children] 0] [lindex $::nodelist 0] string trim [get_tree] } -result [string trim {
      {text some} {space 1} {text text}
      }] tcltest::test tree-3.3.4 {} -body { set div [.h search div] $div insert [lindex $::nodelist 0] string trim [get_tree] } -result [string trim {
      {text some} {space 1} {text text}
      }] tcltest::test tree-3.3.5 {} -body { set div [.h search div] $div remove [lindex $::nodelist 0] string trim [get_tree] } -result [string trim {
      }] finish_test tkHTML-4ee7aaa953d6cb59/tests/tree1.bt000064400000000000000000000120321151224263100166240ustar00nobodynobody #---------------------------------------------------------------------- # A "warm-body" test to check that the infrastructure is working. # Count the anchors in a document. # do_browser_test warmbody.1 -html { One Two Three } -javascript { return document.anchors.length } #---------------------------------------------------------------------- proc body_tree_test {name doc} { # Uses: # # Node.childNodes # Node.nodeType # Document.getElementsByTagName() # # NodeList.length # NodeList.item() # set body_tree_function { } browsertest $name utf-8 [string trim " $body_tree_function $doc "] # ::browsertest::do_test $name -timeout 10000000 -html [subst { # $body_tree_function # $doc # }] -javascript { # // return body_tree() # return dom_tree() # } -browsers {Hv3 Firefox} } #---------------------------------------------------------------------- # The following test cases - tables.X - examine the document trees # created when incorrectly (or partially) specified tables are parsed. # # From the HTML 4.0.1 DTD: # # # # # # # # # # # # In other words, all table sub-trees should look like: # # # ) # ... (etc.) # # (*)* # # (*)* # # (*)* # # The rules for how tag-soup is converted to this structure are # specified as part of: # body_tree_test tables.1 { [td][nbsp][td]

      [pagetitle]

      " append data [page_navigation_begin] } proc page_content {} { global pages unset pages(_) page_navigation_end } proc page_end {} { set last_update [readFile [file join [state] sn.time]] set data "" append data "" append data "[td][stats]
      ...
      } body_tree_test tables.2 {
      } body_tree_test tables.3 {
      \n" proc bgcolor {} [list return $oldcolor] } return "[lst_item "$cmd [join $args " "]"]" } proc description {} { global state set result "" if {$state(call) != {}} { append result [x_synopsis] if {$state(req)} {append result
      } append result [btable][tr][td][table]$state(call)
      } body_tree_test tables.4 {
      } body_tree_test tables.5 {
      } body_tree_test tables.6 { } body_tree_test tables.7 {
      } body_tree_test tables.8 {
      \n" } return "[lst_item "$cmd [join $args " "]"]\n" } proc description {} { global state set result "" if {$state(call) != {}} { append result [x_synopsis] if {$state(req)} {append result
      } proc bgcolor {} {return lightyellow} append result [btable][tr][td][table]$state(call)
      } body_tree_test tables.9 {
      } body_tree_test tables.10 { } body_tree_test tables.12 { "} proc tr {} {return ""} proc sect {s} {return "$s

      "} proc link {text url} {return "$text"} proc table {} {return "
      } body_tree_test tables.11 {
      } body_tree_test tables.13 {
      } body_tree_test tables.14 {
      } # This structure is found in the mail.yahoo.com application. # body_tree_test tables.15 {
      } body_tree_test tables.16 {
      } body_tree_test tree.1 {
      } body_tree_test attr.1 {
      hello } #---------------------------------------------------------------------- tkHTML-4ee7aaa953d6cb59/tests/vertical_align.html000064400000000000000000000061301151224263100211300ustar00nobodynobody
            .sub   {vertical-align: sub ; color: red}
            .super {vertical-align: super ; color: red}
      
            .percent50  {vertical-align: 50% ; color: green}
            .bigfont    {font-size: 1cm}
      
            .drop1cm    {vertical-align: -1cm ; color: blue}
            .raise1cm   {vertical-align: 1cm ; color: blue}
          

      Smoke test: This paragraph contains superscript and subscript text. The subscript text in the previous sentence should cause the following line to shift down a little to make room. Fill this paragraph up with text so that this is more obvious. Fill this paragraph up with text so that this is more obvious. Fill this paragraph up with text so that this is more obvious.


      Test for percentage values of vertical-align. Both the green elements in this paragraph have a vertical-align of 50%. But one element occurs in a taller line box than the other. Is the 50% based on the actual height of the line-box?

      A similar test to the previous. What if the text with the vertical align is itself rendered in a really big font? Again, put some filler text in this paragraph to make the effects easier to observe. Again, put some filler text in this paragraph to make the effects easier to observe. Again, put some filler text in this paragraph to make the effects easier to observe. Again, put some filler text in this paragraph to make the effects easier to observe.

      According to Mozilla and Konqueror, percentage values for vertical align are calculated relative to the line-height of the inline element itself. Opera calculates relative to the line-height of the parent block. It seems to me M and K have it right.


      When text is dropped or raised, the size of the line box should be increased so that the lines do not bleed into each other. I first noticed this problem with dropped text. xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx

      tkHTML-4ee7aaa953d6cb59/tools000075500000000000000000000000001151224263100151765ustar00nobodynobodytkHTML-4ee7aaa953d6cb59/tools/browsertester.tcl000064400000000000000000000164511151224263100207020ustar00nobodynobody package require Tk package require Tkhtml set ::aBrowser {Hv3 Mozilla} array set ::aResult {} array set ::anOutstanding {} set ::zStatus {} set ::template { HTTP/1.1 200 OK Content-type: text/html %ENCODING% Cache-Control: no-cache %TESTBODY% } set ::template2 { HTTP/1.1 200 OK Content-type: text/html Cache-Control: no-cache Tests finished. Click here to rerun. } proc log {args} { .text.t insert end "[join $args]\n" .text.t yview end } proc listen_for_connections {} { socket -server new_connection -myaddr 127.0.0.1 8080 } proc new_connection {channel clientaddr clientport} { fconfigure $channel -translation crlf # Read the request line: set request [gets $channel] # Read HTTP headers until we figure out which browser this is. # while {[set line [gets $channel]] ne ""} { set idx [string first : $line] if {$idx > 0} { set hdr [string range $line 0 [expr {$idx-1}]] switch -exact -- [string tolower $hdr] { user-agent { foreach browser $::aBrowser { if {[string first $browser $line] >= 0} { set zBrowser $browser break } } # If we couldn't identify the browser, drop the connection. # if {![info exists zBrowser]} { log $line log "Failed to identify browser. Disconnecting." close $channel return } } } } # log $line } set zPath [lindex [split $request " "] 1] log "$browser : $zPath " fconfigure $channel -encoding binary -translation binary if {$zPath eq "/"} { # Send the first test to the browser. # set ::anOutstanding($zBrowser) [llength $::tests] send_test $channel 0 set_status } elseif {[string first /next $zPath] == 0} { set idx [string first ? $zPath] set fields [string range $zPath [expr {$idx+1}] end] foreach field [split $fields &] { foreach {name value} [split $field =] break set $name $value } set ::aResult($zBrowser,$testid) [::tkhtml::decode $result] log "$zBrowser,$testid \"[::tkhtml::decode $result]\"" send_test $channel [expr {$testid+1}] incr ::anOutstanding($zBrowser) -1 set_status } elseif {[string first /tcl $zPath] == 0} { array set aParam [list] set idx [string first ? $zPath] set fields [string range $zPath [expr {$idx+1}] end] foreach field [split $fields &] { foreach {name value} [split $field =] break set aParam([::tkhtml::decode $name]) [::tkhtml::decode $value] } eval $aParam(script) $channel return } else { after idle {error "URI NO GOOD!"} } close $channel } proc send_test {channel testid} { if {$testid == [llength $::tests]} { puts -nonewline $channel [string trim $::template2] } else { set enc [lindex $::tests $testid 1] if {$enc ne ""} {set enc "; charset=$enc"} set map [list \ %TESTID% $testid \ %ENCODING% $enc \ %TESTBODY% [lindex $::tests $testid 2] \ ] puts -nonewline $channel [string map $map [string trim $::template]] } } proc setup_gui {} { frame .gotos button .gotos.hv3 -text "Signal Hv3" -command [list send hv3_main.tcl { [gui_current hv3] goto http://localhost:8080/ -cachecontrol no-cache }] button .gotos.firefox -text "Signal Firefox" -command [list exec \ firefox -remote "openurl(http://localhost:8080/,new-tab)" ] pack .gotos.hv3 -side left pack .gotos.firefox -side left frame .text text .text.t scrollbar .text.s -orient vertical .text.t configure -yscrollcommand [list .text.s set] .text.s configure -command [list .text.t yview] frame .buttons button .buttons.quit -command press_quit -text "Quit" button .buttons.report -command press_report -text "Report" button .buttons.clear -command [list .text.t delete 0.0 end] -text "Clear" button .buttons.reload -command press_reload -text "Reload" label .buttons.status -textvariable ::zStatus pack .buttons.quit -side left pack .buttons.report -side left pack .buttons.clear -side left pack .buttons.reload -side right pack .buttons.status -side left -fill x pack .text.t -side left -fill both -expand true pack .text.s -side left -fill y pack .gotos -side top -fill x pack .buttons -side bottom -fill x pack .text -side top -fill both -expand true } proc press_quit {} { exit } proc press_report {} { .text.t delete 0.0 end set nMatch 0 for {set ii 0} {$ii < [llength $::tests]} {incr ii} { set result_list [list] foreach {k v} [array get ::aResult "*,$ii"] {lappend result_list $v} set result_list [lsort $result_list] if { [llength $result_list] != [llength $::aBrowser] || [lindex $result_list 0] ne [lindex $result_list end] } { log "Test [lindex $::tests $ii 0] Failed: " foreach browser $::aBrowser { set res NR if {[info exists ::aResult($browser,$ii)]} { set res "\"$::aResult($browser,$ii)\"" } log [format " % -10s %s" "$browser:" $res] } } else { incr nMatch } } log "" log "$nMatch tests were successful" log "[expr [llength $::tests] - $nMatch] tests failed" } proc set_status {} { set z "Outstanding requests: " foreach browser $::aBrowser { if {![info exists ::anOutstanding($browser)]} { set ::anOutstanding($browser) [llength $::tests] } append z "$browser - $::anOutstanding($browser) " } set ::zStatus $z } set ::tests [list] proc browsertest {name encoding code} { lappend ::tests [list $name $encoding $code] } proc do_browser_test {name args} { # Argument processing: # set opts(-html) "" set opts(-encoding) "" set opts(-timeout) 1000000 array set opts $args if {![info exists opts(-javascript)]} { error "Missing mandatory -javascript option" } foreach option [array names opts] { switch -- $option { -browsers {} -timeout {} -html {} -javascript {} -expected {} -encoding {} default { error "Unknown option: $option" } } } browsertest $name $opts(-encoding) " $opts(-html) " } setup_gui proc press_reload {} { .text.t delete 0.0 end array unset ::anOutstanding array unset ::aResult set ::tests [list] foreach zFile $::argv { set nTest [llength $::tests] source $zFile log "Loaded [expr [llength $::tests]-$nTest] from $zFile" } log "Loaded 2 internal warmbody tests." do_browser_test warmbody-1 -javascript { return "hello" } do_browser_test warmbody-2 -javascript { return "world" } set_status } press_reload listen_for_connections tkHTML-4ee7aaa953d6cb59/tools/changelog_to_list000075500000000000000000000060011151224263100206640ustar00nobodynobody#!/bin/sh # -*-tcl-*- # the next line restarts using tclsh \ exec tclsh "${0}" "${@}" #################################### # Parse a ChangeLog files into a tcl structure. proc main {} { global argv set in [lindex $argv 0] set out [cl:parse [read [set fh [open $in r]]][close $fh]] #puts [join $out \n] -- Test code #exit puts $out } proc cl:parse {data} { set state unknown set chunk(date) {} set chunk(person) {} set chunk(items) {} set idata {} foreach line [split $data \n] { if {[cl:parse:chunk_intro $line date person]} { cl:parse:close_last_item cl:parse:close_last_chunk cl:parse:init_chunk $date $person continue } if {[cl:parse:item_line $line data]} { cl:parse:close_last_item cl:parse:init_item $data continue } if {[cl:parse:item_followup $line data]} { cl:parse:add2item $data continue } # ignore all other lines. } cl:parse:close_last_item cl:parse:close_last_chunk return $result } proc cl:parse:chunk_intro {line datevar personvar} { if {![regexp "^\[^\t \]" $line]} { return 0 } upvar $datevar d $personvar p if {[regexp -indices -- {^([0-9]+-[0-9-]+)} $line -> di]} { foreach {da de} $di break ; # lassign regsub -all "\[ \t\]+" [string trim [string range $line $da $de]] { } d regsub -all "\[ \t\]+" [string trim [string range $line [incr de] end]] { } p #puts stderr "$line +--> ($d | $p)" return 1 } regsub -all "\[\t \]+" $line { } line set line [split $line] set d [join [lrange $line 0 4]] set p [join [lrange $line 5 end]] #puts stderr "$line |--> ($d | $p)" return 1 } proc cl:parse:close_last_chunk {} { upvar result r chunk c if {$c(date) != {}} { lappend r [list $c(date) $c(person) $c(items)] set c(date) {} set c(person) {} set c(items) {} } return } proc cl:parse:init_chunk {date person} { upvar chunk c set c(date) $date set c(person) $person set c(items) {} return } proc cl:parse:item_line {line itemvar} { if {![regexp "^\[\t \]+\\*" $line]} { return 0 } upvar $itemvar i set line [string trimleft [string trimright $line] "\t *"] set i $line return 1 } if {0} { return 1 } proc cl:parse:close_last_item {} { upvar chunk c idata i if {$i != {}} { set ke [string first : $i] if {$ke < 0} { set ke -1 ; # No key at all, pure comment } set k [string trim [string range $i 0 [incr ke -1]]] set co [string trim [string range $i [incr ke 2] end]] lappend c(items) [list $k $co] set i {} } return } proc cl:parse:init_item {comment} { upvar idata i set i $comment return } proc cl:parse:item_followup {line commentvar} { upvar $commentvar c set line [string trim $line] if {$line == {}} { return 0 } set c $line return 1 } proc cl:parse:add2item {comment} { upvar idata i append i " $comment" } ########################################################## main exit 0 tkHTML-4ee7aaa953d6cb59/tools/check_manifest000064400000000000000000000011351151224263100201430ustar00nobodynobody#!/usr/local/bin/tclsh # -*- tcl -*- # check the manifest against the current contents of the directory set manifest [lindex $argv 0] rename file ori_file proc file {name} { global files set files($name) 1 if {! [ori_file exists $name]} { puts stdout "missing: $name" } } # read manifest and check existence of all listed files source $manifest # now backwards: find all files and check # for files not listed in the manifest set list [exec find . -print] regsub -all "\n" $list { } list foreach f $list { if {[catch {set files($f)}]} { puts stdout "new: $f" } } tkHTML-4ee7aaa953d6cb59/tools/crontab.sourceforge000075500000000000000000000004141151224263100211540ustar00nobodynobody# # (c) 2001, Andreas Kupries # # Hourly cron job to regenerate the dynamic parts of the # memchan website. # 28 * * * * /home/groups/m/me/memchan/tools/htdocs_refresh 17 6 * * * /home/groups/m/me/memchan/tools/watch_cvs tkHTML-4ee7aaa953d6cb59/tools/expand000075500000000000000000000727431151224263100164770ustar00nobodynobody#!/bin/sh # -*-tcl-*- # the next line restarts using tclsh\ exec tclsh "$0" "$@" #------------------------------------------------------------------------- # TITLE: # expand.tcl # # VERSION: # 2.0 # # AUTHOR: # Will Duquette # # DESCRIPTION: # Usage: tclsh expand.tcl [options] files.... # # Reads files, writing input to output. Most text # is output unchanged. Certain text is evaluated as Tcl code; # the result of the Tcl code, if any, is output. If the Tcl # code results in an error, the error result is output. # # Before reading any input, expand.tcl reads any exprules.tcl # file in the current directory, or alternatively a tcl file # specified by the "-rules" command line option. This allows the # caller to define special formatting macros for general use # and override them as needed. The rules file can also read # arguments from the command line, after options are removed but # before the files are processed. # # On an error in a macro, expand can "ignore" the macro, # "output" the macro unchanged, "fail" (the default), halting # processing, depending on the value of the "-error" option. # # Output is written to stdout, by default; the "-out" option # sends it to a file, instead. If the specified file is "nul", # then no output is written at all. The rules can also control # the output via the setoutput command. # # Any text in brackets, e.g., "[" and "]" is treated as a Tcl # command, and evaluated. The bracket characters can be changed # using ::expand::setbrackets. # # Normally Expand reads the output files only once; a rules file # can choose multiple passes using the ::expand::setpasses command. The # ::expand::exppass command returns the number of the current pass, # starting at 1. # # LICENSE: # Copyright (C) 2000 by William H. Duquette. See license.txt, # distributed with this file, for license information. # # CHANGE LOG: # # 06/27/98: Released V1.0 on web. # 06/27/98: Changed exp_extract to handle multi-character bracket # tokens. Added exp_stripBrackets to remove multi-character # bracket tokens. # 06/27/98: Added function setbrackets to allow the user to choose the # bracket tokens. # 06/27/98: Added brand new command line option parser. The new parser # can be used by the rules file's begin_hook. # # 06/28/98: Version 1.1 released. # # 06/29/98: Added init_hook. # 06/29/98: Added setoutput command. # 06/29/98: Added setpasses/exppass and multi-pass processing. # 06/29/98: Fixed potential bug in exp_getCmd: using "info complete" # with changed left and right brackets. # 06/30/98: Added -testmode flag: causes error output to go to # stdout instead of stderr to aid testing. # 07/01/98: Added a tclsh80 starter at the top of the file. # 07/01/98: exp_error calls "exit 1" instead of "exit 0" again. # 07/02/98: Added expandText and include commands. # 07/03/98: Renamed exp_write to expwrite, and made it public, # for use with setoutput. # 07/07/98: Released Expand V1.2 # # 10/10/99: Added raw_text_hook. # 01/15/00: Rewrote popArg, in an attempt to prevent an odd bug # that manifests only on certain platforms. # 01/15/00: Released Expand V1.3 # # 02/03/00: Found a bug in expandText; it isn't safe to extract # the command name from an arbitrary Tcl script using # lindex, as many valid scripts aren't valid lists. I # now use scan instead of lindex. # # 04/17/00: Version 2 rewrite begins. The code is cleaned up and # placed in the ::expand:: namespace. # # 05/07/00: Version 2 rewrite ends (for now). #------------------------------------------------------------------------- # Namespace: all of the expand code exists in the ::expand:: namespace, # leaving the global namespace for the user's rules. namespace eval ::expand:: { # Exported Commands namespace export {[a-z]*} # Expand Variables # Macro bracketing sequences. variable leftBracket "\[" variable rightBracket "\]" # What to output when an error is detected: # "nothing", "macro", "error", "fail" variable errorOutputMode fail # Number of passes to make over the input variable numberOfPasses 1 # The current output channel variable outputChannel "" # A command can push its context onto a stack, causing any text # that follows it to be saved separately. Later on, a paired command # can pop the stack, acquiring the saved text and including it in its own # output. variable level 0 variable context variable contextName variable contextData set context($level) "" set contextName($level) ":0" # Status variables variable currentFileName "" variable currentPass 0 } #------------------------------------------------------------------------- # User settings: These commands allow the users to set, and in some # cases retrieve, various expansion parameters. # lb # # Return the left bracket sequence. proc ::expand::lb {} { variable leftBracket return $leftBracket } # rb # # Return the right bracket sequence. proc ::expand::rb {} { variable rightBracket return $rightBracket } # setbrackets lb rb # # Set the bracket sequences proc ::expand::setbrackets {lb rb} { variable leftBracket variable rightBracket if {$lb == "" || $rb == ""} { error "Empty string specified as left or right bracket." } set leftBracket $lb set rightBracket $rb return } # setErrorOutputMode mode # # Set the error output mode proc ::expand::setErrorOutputMode {mode} { variable errorOutputMode if {![oneOf {fail nothing macro error} $mode]} { error "Invalid error output mode '$mode'" } set errorOutputMode $mode } # Return the current file name proc ::expand::expfile {} { variable currentFileName return $currentFileName } # Return the number of the current pass. proc ::expand::exppass {} { variable currentPass return $currentPass } # Set the number of passes proc ::expand::setpasses {passes} { variable numberOfPasses set numberOfPasses $passes if {$numberOfPasses < 1} { error "setpasses: must be >= 1" } } #------------------------------------------------------------------------- # User hooks: a rule set can redefine these hooks to do anything desired. # The init_hook doesn't contribute to the output, but the other hooks do. # Since the hooks do nothing by default, and are to be redefined by the # user, they are defined in the global name space. # Initialization Hook: called when the rule set is loaded. proc init_hook {} {} # Begin Hook: Called at the beginning of each pass. proc begin_hook {} {} # End Hook: Called at the end of each pass. proc end_hook {} {} # Begin File Hook: Called before each file is processed. proc begin_file_hook {fileName} {} # End File Hook: Called after each file is processed. proc end_file_hook {fileName} {} # Raw Text Hook: All plain (non-macro) text is passed through this # function. proc raw_text_hook {text} {return $text} #------------------------------------------------------------------------- # Context: Every expansion takes place in its own context; however, # a macro can push a new context, causing the text it returns and all # subsequent text to be saved separately. Later, a matching macro can # pop the context, acquiring all text saved since the first command, # and use that in its own output. # cpush name # # pushes an empty context onto the stack. All output text will be added # to this context until it is popped. proc ::expand::cpush {name} { variable level variable context variable contextName incr level set context($level) {} set contextName($level) $name } # cis name # # Returns true if the current context has the given name. proc ::expand::cis {name} { variable level variable contextName return [expr [string compare $name $contextName($level)] == 0] } # cname # # Returns the current context name. proc ::expand::cname {} { variable level variable contextName return $contextName($level) } # csave name value # # Save or retrieve value in the current context proc ::expand::csave {name value} { variable contextData variable level set contextData($level-$name) $value } # cget name # # Get the value of a context variable proc ::expand::cget {name} { variable contextData variable level if {![info exists contextData($level-$name)]} { error "*** Error, context var $name doesn't exist in this context" } return $contextData($level-$name) } # cvar name # # Get a context variable's real name, e.g., for appending or lappending proc ::expand::cvar {name} { variable contextData variable level if {![info exists contextData($level-$name)]} { error "*** Error, context var $name doesn't exist in this context" } return ::expand::contextData($level-$name) } # cpop # # Pops a context level off of the stack, returning the accumulated text. proc ::expand::cpop {name} { variable level variable context variable contextName variable contextData if {$level == 0} { error "*** Error, context mismatch: got unexpected '$name'" } if {"$contextName($level)" != "$name"} { error \ "*** Error, context mismatch: expected $contextName($level), got $name" } set result $context($level) set context($level) "" set contextName($level) "" foreach name [array names contextData $level-*] { unset contextData($name) } incr level -1 return $result } # ContextAppend text # # This private command appends text to the current context. It is for # use only by the Expand code; macros should return their text. proc ::expand::ContextAppend {text} { variable context variable level append context($level) $text } #------------------------------------------------------------------------- # Macro-expansion: The following code is the heart of the program. # Given a text string, and the current variable settings, this code # returns an expanded string, with all macros replaced. # # If a fatal error is detected during expansion, expandText throws # an error for its caller to handle. An error detected while # expanding a particular macro is only fatal if the errorOutputMode # is "fail"; otherwise, the result of the expansion attempt is # output according to the mode. # # All non-macro text is passed through the raw_text_hook. # Expands a string using the current macro definitions and Expand # variable settings. proc ::expand::expandText {inputString} { variable errorOutputMode global errorInfo cpush expandText while {[string length $inputString] > 0} { set plainText [ExtractToToken inputString [lb] exclude] # FIRST, If there was plain text, append it to the output, and # continue. if {$plainText != ""} { ContextAppend [raw_text_hook $plainText] if {[string length $inputString] == 0} { break } } # NEXT, A macro is the next thing; process it. if {[catch "GetMacro inputString" macro]} { error "*** Error reading macro from input: $macro" } # Expand the macro, and output the result, or # handle an error. if {![catch "uplevel #0 [list $macro]" result]} { ContextAppend $result continue } switch $errorOutputMode { nothing { } macro { ContextAppend "[lb]$macro[rb]" } error { ContextAppend "[lb]$macro[rb]\n" ContextAppend "*** Error in preceding macro: $result\n$errorInfo" } fail { error "*** Error in macro:\n[lb]$macro[rb]\n$result" } } } return [cpop expandText] } # ExtractToToken string token mode # # Extract text from a string, up to or including a particular # token. Remove the extracted text from the string. # mode determines whether the found token is removed; # it should be "include" or "exclude". The string is # modified in place, and the extracted text is returned. proc ::expand::ExtractToToken {string token mode} { upvar $string theString # First, determine the offset switch $mode { include { set offset [expr [string length $token] - 1] } exclude { set offset -1 } default { error "::expand::ExtractToToken: unknown mode $mode" } } # Next, find the first occurrence of the token. set tokenPos [string first $token $theString] # Next, return the entire string if it wasn't found, or just # the part upto or including the character. if {$tokenPos == -1} { set theText $theString set theString "" } else { set newEnd [expr $tokenPos + $offset] set newBegin [expr $newEnd + 1] set theText [string range $theString 0 $newEnd] set theString [string range $theString $newBegin end] } return $theText } # Get the next complete command, removing it from the string. proc ::expand::GetMacro {string} { upvar $string theString # FIRST, it's an error if the string doesn't begin with a # character. if {[string first [lb] $theString] != 0} { error "::expand::GetMacro: assertion failure, next text isn't a command! '$theString'" } # NEXT, extract a full macro set macro [ExtractToToken theString [lb] include] while {[string length $theString] > 0} { append macro [ExtractToToken theString [rb] include] # Verify that the command really ends with the [rb] characters, # whatever they are. If not, break because of unexpected # end of file. if {![IsBracketed $macro]} { break; } set strippedMacro [StripBrackets $macro] if {[info complete "puts \[$strippedMacro\]"]} { return $strippedMacro } } if {[string length $macro] > 40} { set macro "[string range $macro 0 39]...\n" } error "*** Error, unexpected EOF in macro:\n$macro" } # Strip left and right bracket tokens from the ends of a macro, # provided that it's properly bracketed. proc ::expand::StripBrackets {macro} { set llen [string length [lb]] set rlen [string length [rb]] set tlen [string length $macro] return [string range $macro $llen [expr $tlen - $rlen - 1]] } # Return 1 if the macro is properly bracketed, and 0 otherwise. proc ::expand::IsBracketed {macro} { set llen [string length [lb]] set rlen [string length [rb]] set tlen [string length $macro] set leftEnd [string range $macro 0 [expr $llen - 1]] set rightEnd [string range $macro [expr $tlen - $rlen] end] if {$leftEnd != [lb]} { return 0 } elseif {$rightEnd != [rb]} { return 0 } else { return 1 } } #------------------------------------------------------------------------- # File handling: these routines, some public and some private, handle # processing of files. # expand fileList outputFile # # This is the basic algorithm of the Expand tool. Given a list of files # to expand, it executes the following sequence. Return values of all # handlers, except for the initHandlers, is written to the current output # file. # # - For each pass, # - Set ::expand::currentPass. # - Call the begin_hook. # - For each file in the file list, # - Set ::expand::currentFileName # - Call the begin_file_hook. # - read file and expand its contents # - Call the end_file_hook. # - Call the end_hook. # - Close the current output file. proc ::expand::expand {fileList outputFile} { variable currentPass variable numberOfPasses variable currentFileName for {set currentPass 1} {$currentPass <= $numberOfPasses} \ {incr currentPass} { # First, if this is any pass but the last, set output to nul; # otherwise, set output to the requested output file. if {$currentPass < $numberOfPasses} { setoutput nul } else { setoutput $outputFile } # Next, execute the beginning hook set currentFileName "" expwrite [begin_hook] # Next, expand each of the files on the command line. foreach file $fileList { if {[catch "ExpandFile [list $file]" result]} { puts stderr $result exit 1 } expwrite $result } # Next, execute the end hook expwrite [end_hook] } # Next, close the output file. setoutput nul } # ExpandFile # # Helper routine for ::expand::expand. It expands a single file, # calling the begin and end file handlers and returning the expanded # result. proc ::expand::ExpandFile {fileName} { variable currentFileName # Set the current file set currentFileName $fileName # Call the begin_file_hook set output [begin_file_hook $fileName] # Expand the file set contents [readFile $fileName] if {[catch [list expandText $contents] result]} { error "*** Error expanding $fileName:\n$result" } append output $result # Call the endFileHandlers append output [end_file_hook $fileName] return $output } # include file # # Reads a file into memory, and expands its contents. proc ::expand::include {fileName} { # Get the file's contents, and prepare to output it. set contents [readFile $fileName] if {[catch [list expandText $contents] result]} { error "*** Error including $fileName:\n$result" } return $result } # readFile file # # Reads a file into memory, returning its contents. proc ::expand::readFile {fileName} { # Open the file. if {[catch "open $fileName" fin]} { error "Could not read file '$fileName': $fin" } # Read the contents and close the file. set contents [read $fin] close $fin return $contents } #------------------------------------------------------------------------- # Output Management # Set the output file proc ::expand::setoutput {fileName} { variable outputChannel # Close any existing file if {$outputChannel != "" && $outputChannel != "stdout"} { close $outputChannel } # Pick stdout, no output at all, or a real file if {$fileName == ""} { set outputChannel stdout } elseif {$fileName == "nul"} { set outputChannel "" } else { if {[catch "open $fileName w" outputChannel]} { error "Could not open output file $fileName" } } return } # Output a bunch of text to the output file. proc ::expand::expwrite {text} { variable outputChannel if {$outputChannel != ""} { puts -nonewline $outputChannel $text } } #------------------------------------------------------------------------- # getoptions: command line option parsing # # The getoptions function parses a list as a command line, removing # options and their values. Any remaining tokens and options remain # in the list and can be parsed by another call to getoptions or in # any other way the caller prefers. # # getoptions is called as follows: # # getoptions arglist [-strict] [{optionDef... }] # # "arglist" is the name of a list variable, typically argv. It is # passed by name, and modified in place. If the "-strict" option # is specified, unrecognized options are flagged as errors. # The call may include any number of option definitions, including # none. The call "getoptions argv -strict", for example, will ensure # that no options remain in the list contained in "argv". # # Option definitions may take the following forms. In each, NAME is # the option name, which must begin with a "-" character, and VAR is # the name of a variable in the caller's scope to receive the option's value. # # {NAME VAR flag} # If the option appears on the command line, the variable # is set to 1, otherwise to 0. # # {NAME VAR enum VAL1 VAL2....} # If the option appears on the command line, the next argument # must be one of the enumerated values, VAL1, VAL2, etc. The # variable is set to the value, or VAL1 if the option does not # appear on the command line. If the option's value is not one of # the valid choices, an error message will be displayed and the # program will halt. None of the enumerated values may begin with # a "-" character. # # {NAME VAR string DEFVALUE} # The named variable is set to the value following the option on # the command line. If the option doesn't appear, the variable is # set to the DEFVALUE. The option's value may not begin with # "-" character, as if it does, the most likely explanation is # that the option's real value is missing and the next argument is # another option name. # Utility routine: pops an arg off of the front of an arglist. proc ::expand::popArg {arglist} { upvar $arglist args if {[llength $args] == 0} { set arg "" } elseif {[llength $args] == 1} { set arg $args set args "" } else { set arg [lindex $args 0] set args [lrange $args 1 end] } return $arg } proc ::expand::getoptions {arglist strictOrDefs {defsOrNil ""}} { # First, the arglist is called by name. upvar $arglist args # Next, strictOrDefs is either the "-strict" option or the # definition list. if {$strictOrDefs == "-strict"} { set strictFlag 1 set defList $defsOrNil } else { set strictFlag 0 set defList $strictOrDefs } # Next, get names of the options set optNames {} set optTypes {flag enum string} set optLens {3 5 4} foreach def $defList { if {[llength $def] < 3} { error "Error in option definition: $def" } lappend optNames [lindex $def 0] set varName [lindex $def 1] set optType [lindex $def 2] set i [lsearch -exact $optTypes $optType] if {$i == -1} { error "Unknown option type: $optType" } if {[llength $def] < [lindex $optLens $i]} { error "Error in option definition: $def" } upvar $varName theVar switch $optType { flag {set theVar 0} enum - string {set theVar [lindex $def 3]} } } # Next, process the options on the command line. set errorCount 0 set newList {} for {set arg [popArg args]} {$arg != ""} {set arg [popArg args]} { # First, does it look like an option? If not, add it to the # output list. if {[string index $arg 0] != "-"} { lappend newList $arg continue } # Next, Is the argument unknown? Flag an error or just skip it. set i [lsearch -exact $optNames $arg] if {$i == -1} { if {$strictFlag} { puts stderr "*** Unknown option: $arg" incr errorCount } else { lappend newList $arg } continue } # Next, process the argument set def [lindex $defList $i] set varName [lindex $def 1] set optType [lindex $def 2] upvar $varName theVar switch $optType { flag { set theVar 1 } enum { set vals [lreplace $def 0 2] set theVar [popArg args] if {$theVar == "" || [string index $theVar 0] == "-"} { puts stderr "*** Missing option value: $arg" incr errorCount continue } if {[lsearch -exact $vals $theVar] == -1} { puts stderr "*** Invalid option value: $arg $theVar" incr errorCount } } string { set theVar [popArg args] if {$theVar == "" || [string index $theVar 0] == "-"} { puts stderr "*** Missing option value: $arg" incr errorCount } } } } # Next, if there are any errors, halt. if {$errorCount > 0} { exit 1 } # Next, return the new argument list. set args $newList return } #------------------------------------------------------------------------- # Importing macros into the global namespace # GlobalizeMacros args # # args is a list of glob patterns matching the macros to be imported. # The prefix ::expand:: is added automatically. proc ::expand::GlobalizeMacros {args} { set globList {} foreach arg $args { lappend globList ::expand::$arg } namespace eval :: "namespace import -force $globList" } #------------------------------------------------------------------------- # Standard Rule Set: # # These are the rules that are always available. proc ::expand::standardRuleSet {} { GlobalizeMacros cget cis cname cpop cpush csave cvar expandText expfile GlobalizeMacros exppass expwrite getoptions include lb popArg rb GlobalizeMacros readFile setErrorOutputMode setbrackets setoutput GlobalizeMacros setpasses textToID } #------------------------------------------------------------------------- # Rule Set: Web Rules # # These macros are for creating HTML pages. They are only defined when # webRuleSet is called. proc ::expand::webRuleSet {} { GlobalizeMacros dot tag link mailto today } # Output a big black dot. proc ::expand::dot {} { return "•" } # Format an html tag. name is the tag name, args is a list of # of attribute names and values proc ::expand::tag {name args} { set result "<$name" foreach {attr val} $args { append result " $attr=\"$val\"" } append result ">" } # Format a link. If text is given, use it as the displayed text; # otherwise use the url. proc ::expand::link {url {text ""}} { if {$text == ""} { set text $url } return "[tag a href $url]$text[tag /a]" } # Format an email URL proc ::expand::mailto {address {name ""}} { if {$name == ""} { set name $address } return "[tag a href mailto:$address]$name[tag /a]" } # Return today's date. Use dd MONTH yyyy unless some other format is # proposed. proc ::expand::today {{format ""}} { set secs [clock seconds] if {$format == ""} { set format "%d %B %Y" } return [string trimleft [clock format $secs -format $format] "0"] } #------------------------------------------------------------------------- # Miscellaneous utility commands # oneOf list value # # Checks to see if a value is in a list. proc ::expand::oneOf {list value} { return [expr {[lsearch -exact $list $value] != -1}] } # Converts a generic string to an ID string. Leading and trailing # whitespace and internal punctuation is removed, internal whitespace # is converted to "_", and the text is converted to lower case. proc ::expand::textToID {text} { # First, trim any white space and convert to lower case set text [string trim [string tolower $text]] # Next, substitute "_" for internal whitespace, and delete any # non-alphanumeric characters (other than "_", of course) regsub -all {[ ]+} $text "_" text regsub -all {[^a-z0-9_]} $text "" text return $text } #------------------------------------------------------------------------- # Main-line code: This is the implementation of the Expand tool # itself. It is executed only if this is the top-level script. proc ::expand::ShowHelp { } { puts {tclsh expand.tcl [options] files... -help Displays this text. -rules file Specify the name of the rules file (exprules.tcl is the default) -out file Specify the name of the output file, or "nul" for no output. Output is to stdout, by default. -errout mode nothing, macro, error, or fail (fail is the default) -web Enable the optional web rule set. files... Names of files to process.} } if {"[info script]" == "$argv0"} { # First, parse the command line ::expand::getoptions argv { {-help ::expand::helpFlag flag} {-errout ::expand::errorOutputMode enum fail nothing macro error} {-rules ::expand::rulesFile string "exprules.tcl"} {-web ::expand::webFlag flag} {-out ::expand::outputFile string ""} } # Next, if they asked for help or if there are no arguments left, # show help and stop. if {$::expand::helpFlag || [llength $argv] == 0} { ::expand::ShowHelp exit 0 } # Next, load the standard macros ::expand::standardRuleSet # Next, load optional rule sets. if {$::expand::webFlag} { ::expand::webRuleSet } # Next, load the rules file. (Should only do it if file exists; # should die if there are any errors) if {[file exists $::expand::rulesFile]} { if {[catch "source $::expand::rulesFile" result]} { puts "*** Error in rules file $::expand::rulesFile: $result" exit 1 } } elseif {$::expand::rulesFile != "exprules.tcl"} { puts "*** Rules file $rulesFile not found." exit 1 } # Next, call the init_hook. if {[catch init_hook result]} { puts "*** Error executing init_hook: $result" exit 1 } # Next, make sure the command line contains no additional options ::expand::getoptions argv -strict # Next, process the files ::expand::expand $argv $::expand::outputFile } tkHTML-4ee7aaa953d6cb59/tools/genStubs.tcl000064400000000000000000000515511151224263100175620ustar00nobodynobody# genStubs.tcl -- # # This script generates a set of stub files for a given # interface. # # # Copyright (c) 1998-1999 by Scriptics Corporation. # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. # # RCS: @(#) $Id: genStubs.tcl,v 1.1 2002/12/17 18:31:05 drh Exp $ namespace eval genStubs { # libraryName -- # # The name of the entire library. This value is used to compute # the USE_*_STUB_PROCS macro and the name of the init file. variable libraryName "UNKNOWN" # interfaces -- # # An array indexed by interface name that is used to maintain # the set of valid interfaces. The value is empty. array set interfaces {} # curName -- # # The name of the interface currently being defined. variable curName "UNKNOWN" # hooks -- # # An array indexed by interface name that contains the set of # subinterfaces that should be defined for a given interface. array set hooks {} # stubs -- # # This three dimensional array is indexed first by interface name, # second by platform name, and third by a numeric offset or the # constant "lastNum". The lastNum entry contains the largest # numeric offset used for a given interface/platform combo. Each # numeric offset contains the C function specification that # should be used for the given entry in the stub table. The spec # consists of a list in the form returned by parseDecl. array set stubs {} # outDir -- # # The directory where the generated files should be placed. variable outDir . } # genStubs::library -- # # This function is used in the declarations file to set the name # of the library that the interfaces are associated with (e.g. "tcl"). # This value will be used to define the inline conditional macro. # # Arguments: # name The library name. # # Results: # None. proc genStubs::library {name} { variable libraryName $name } # genStubs::interface -- # # This function is used in the declarations file to set the name # of the interface currently being defined. # # Arguments: # name The name of the interface. # # Results: # None. proc genStubs::interface {name} { variable curName $name variable interfaces set interfaces($name) {} return } # genStubs::hooks -- # # This function defines the subinterface hooks for the current # interface. # # Arguments: # names The ordered list of interfaces that are reachable through the # hook vector. # # Results: # None. proc genStubs::hooks {names} { variable curName variable hooks set hooks($curName) $names return } # genStubs::declare -- # # This function is used in the declarations file to declare a new # interface entry. # # Arguments: # index The index number of the interface. # platform The platform the interface belongs to. Should be one # of generic, win, unix, or mac. # decl The C function declaration, or {} for an undefined # entry. # # Results: # None. proc genStubs::declare {args} { variable stubs variable curName if {[llength $args] != 3} { puts stderr "wrong # args: declare $args" } lassign $args index platformList decl # Check for duplicate declarations, then add the declaration and # bump the lastNum counter if necessary. foreach platform $platformList { if {[info exists stubs($curName,$platform,$index)]} { puts stderr "Duplicate entry: declare $args" } } regsub -all "\[ \t\n\]+" [string trim $decl] " " decl set decl [parseDecl $decl] foreach platform $platformList { if {$decl != ""} { set stubs($curName,$platform,$index) $decl if {![info exists stubs($curName,$platform,lastNum)] \ || ($index > $stubs($curName,$platform,lastNum))} { set stubs($curName,$platform,lastNum) $index } } } return } # genStubs::rewriteFile -- # # This function replaces the machine generated portion of the # specified file with new contents. It looks for the !BEGIN! and # !END! comments to determine where to place the new text. # # Arguments: # file The name of the file to modify. # text The new text to place in the file. # # Results: # None. proc genStubs::rewriteFile {file text} { if {![file exist $file]} { puts stderr "Cannot find file: $file" return } set in [open ${file} r] set out [open ${file}.new w] # Always write out the file with LF termination fconfigure $out -translation lf while {![eof $in]} { set line [gets $in] if {[regexp {!BEGIN!} $line]} { break } puts $out $line } puts $out "/* !BEGIN!: Do not edit below this line. */" puts $out $text while {![eof $in]} { set line [gets $in] if {[regexp {!END!} $line]} { break } } puts $out "/* !END!: Do not edit above this line. */" puts -nonewline $out [read $in] close $in close $out file rename -force ${file}.new ${file} return } # genStubs::addPlatformGuard -- # # Wrap a string inside a platform #ifdef. # # Arguments: # plat Platform to test. # # Results: # Returns the original text inside an appropriate #ifdef. proc genStubs::addPlatformGuard {plat text} { switch $plat { win { return "#ifdef __WIN32__\n${text}#endif /* __WIN32__ */\n" } unix { return "#if !defined(__WIN32__) && !defined(MAC_TCL) /* UNIX */\n${text}#endif /* UNIX */\n" } mac { return "#ifdef MAC_TCL\n${text}#endif /* MAC_TCL */\n" } } return "$text" } # genStubs::emitSlots -- # # Generate the stub table slots for the given interface. If there # are no generic slots, then one table is generated for each # platform, otherwise one table is generated for all platforms. # # Arguments: # name The name of the interface being emitted. # textVar The variable to use for output. # # Results: # None. proc genStubs::emitSlots {name textVar} { variable stubs upvar $textVar text forAllStubs $name makeSlot 1 text {" void *reserved$i;\n"} return } # genStubs::parseDecl -- # # Parse a C function declaration into its component parts. # # Arguments: # decl The function declaration. # # Results: # Returns a list of the form {returnType name args}. The args # element consists of a list of type/name pairs, or a single # element "void". If the function declaration is malformed # then an error is displayed and the return value is {}. proc genStubs::parseDecl {decl} { if {![regexp {^(.*)\((.*)\)$} $decl all prefix args]} { puts stderr "Malformed declaration: $decl" return } set prefix [string trim $prefix] if {![regexp {^(.+[ ][*]*)([^ *]+)$} $prefix all rtype fname]} { puts stderr "Bad return type: $decl" return } set rtype [string trim $rtype] foreach arg [split $args ,] { lappend argList [string trim $arg] } if {![string compare [lindex $argList end] "..."]} { if {[llength $argList] != 2} { puts stderr "Only one argument is allowed in varargs form: $decl" } set arg [parseArg [lindex $argList 0]] if {$arg == "" || ([llength $arg] != 2)} { puts stderr "Bad argument: '[lindex $argList 0]' in '$decl'" return } set args [list TCL_VARARGS $arg] } else { set args {} foreach arg $argList { set argInfo [parseArg $arg] if {![string compare $argInfo "void"]} { lappend args "void" break } elseif {[llength $argInfo] == 2 || [llength $argInfo] == 3} { lappend args $argInfo } else { puts stderr "Bad argument: '$arg' in '$decl'" return } } } return [list $rtype $fname $args] } # genStubs::parseArg -- # # This function parses a function argument into a type and name. # # Arguments: # arg The argument to parse. # # Results: # Returns a list of type and name with an optional third array # indicator. If the argument is malformed, returns "". proc genStubs::parseArg {arg} { if {![regexp {^(.+[ ][*]*)([^][ *]+)(\[\])?$} $arg all type name array]} { if {$arg == "void"} { return $arg } else { return } } set result [list [string trim $type] $name] if {$array != ""} { lappend result $array } return $result } # genStubs::makeDecl -- # # Generate the prototype for a function. # # Arguments: # name The interface name. # decl The function declaration. # index The slot index for this function. # # Results: # Returns the formatted declaration string. proc genStubs::makeDecl {name decl index} { lassign $decl rtype fname args append text "/* $index */\n" set line "EXTERN $rtype" set count [expr {2 - ([string length $line] / 8)}] append line [string range "\t\t\t" 0 $count] set pad [expr {24 - [string length $line]}] if {$pad <= 0} { append line " " set pad 0 } append line "$fname _ANSI_ARGS_(" set arg1 [lindex $args 0] switch -exact $arg1 { void { append line "(void)" } TCL_VARARGS { set arg [lindex $args 1] append line "TCL_VARARGS([lindex $arg 0],[lindex $arg 1])" } default { set sep "(" foreach arg $args { append line $sep set next {} append next [lindex $arg 0] " " [lindex $arg 1] \ [lindex $arg 2] if {[string length $line] + [string length $next] \ + $pad > 76} { append text $line \n set line "\t\t\t\t" set pad 28 } append line $next set sep ", " } append line ")" } } append text $line append text ");\n" return $text } # genStubs::makeMacro -- # # Generate the inline macro for a function. # # Arguments: # name The interface name. # decl The function declaration. # index The slot index for this function. # # Results: # Returns the formatted macro definition. proc genStubs::makeMacro {name decl index} { lassign $decl rtype fname args set lfname [string tolower [string index $fname 0]] append lfname [string range $fname 1 end] set text "#ifndef $fname\n#define $fname" set arg1 [lindex $args 0] set argList "" switch -exact $arg1 { void { set argList "()" } TCL_VARARGS { } default { set sep "(" foreach arg $args { append argList $sep [lindex $arg 1] set sep ", " } append argList ")" } } append text " \\\n\t(${name}StubsPtr->$lfname)" append text " /* $index */\n#endif\n" return $text } # genStubs::makeStub -- # # Emits a stub function definition. # # Arguments: # name The interface name. # decl The function declaration. # index The slot index for this function. # # Results: # Returns the formatted stub function definition. proc genStubs::makeStub {name decl index} { lassign $decl rtype fname args set lfname [string tolower [string index $fname 0]] append lfname [string range $fname 1 end] append text "/* Slot $index */\n" $rtype "\n" $fname set arg1 [lindex $args 0] if {![string compare $arg1 "TCL_VARARGS"]} { lassign [lindex $args 1] type argName append text " TCL_VARARGS_DEF($type,$argName)\n\{\n" append text " " $type " var;\n va_list argList;\n" if {[string compare $rtype "void"]} { append text " " $rtype " resultValue;\n" } append text "\n var = (" $type ") TCL_VARARGS_START(" \ $type "," $argName ",argList);\n\n " if {[string compare $rtype "void"]} { append text "resultValue = " } append text "(" $name "StubsPtr->" $lfname "VA)(var, argList);\n" append text " va_end(argList);\n" if {[string compare $rtype "void"]} { append text "return resultValue;\n" } append text "\}\n\n" return $text } if {![string compare $arg1 "void"]} { set argList "()" set argDecls "" } else { set argList "" set sep "(" foreach arg $args { append argList $sep [lindex $arg 1] append argDecls " " [lindex $arg 0] " " \ [lindex $arg 1] [lindex $arg 2] ";\n" set sep ", " } append argList ")" } append text $argList "\n" $argDecls "{\n " if {[string compare $rtype "void"]} { append text "return " } append text "(" $name "StubsPtr->" $lfname ")" $argList ";\n}\n\n" return $text } # genStubs::makeSlot -- # # Generate the stub table entry for a function. # # Arguments: # name The interface name. # decl The function declaration. # index The slot index for this function. # # Results: # Returns the formatted table entry. proc genStubs::makeSlot {name decl index} { lassign $decl rtype fname args set lfname [string tolower [string index $fname 0]] append lfname [string range $fname 1 end] set text " " append text $rtype " (*" $lfname ") _ANSI_ARGS_(" set arg1 [lindex $args 0] switch -exact $arg1 { void { append text "(void)" } TCL_VARARGS { set arg [lindex $args 1] append text "TCL_VARARGS([lindex $arg 0],[lindex $arg 1])" } default { set sep "(" foreach arg $args { append text $sep [lindex $arg 0] " " [lindex $arg 1] \ [lindex $arg 2] set sep ", " } append text ")" } } append text "); /* $index */\n" return $text } # genStubs::makeInit -- # # Generate the prototype for a function. # # Arguments: # name The interface name. # decl The function declaration. # index The slot index for this function. # # Results: # Returns the formatted declaration string. proc genStubs::makeInit {name decl index} { append text " " [lindex $decl 1] ", /* " $index " */\n" return $text } # genStubs::forAllStubs -- # # This function iterates over all of the platforms and invokes # a callback for each slot. The result of the callback is then # placed inside appropriate platform guards. # # Arguments: # name The interface name. # slotProc The proc to invoke to handle the slot. It will # have the interface name, the declaration, and # the index appended. # onAll If 1, emit the skip string even if there are # definitions for one or more platforms. # textVar The variable to use for output. # skipString The string to emit if a slot is skipped. This # string will be subst'ed in the loop so "$i" can # be used to substitute the index value. # # Results: # None. proc genStubs::forAllStubs {name slotProc onAll textVar \ {skipString {"/* Slot $i is reserved */\n"}}} { variable stubs upvar $textVar text set plats [array names stubs $name,*,lastNum] if {[info exists stubs($name,generic,lastNum)]} { # Emit integrated stubs block set lastNum -1 foreach plat [array names stubs $name,*,lastNum] { if {$stubs($plat) > $lastNum} { set lastNum $stubs($plat) } } for {set i 0} {$i <= $lastNum} {incr i} { set slots [array names stubs $name,*,$i] set emit 0 if {[info exists stubs($name,generic,$i)]} { if {[llength $slots] > 1} { puts stderr "platform entry duplicates generic entry: $i" } append text [$slotProc $name $stubs($name,generic,$i) $i] set emit 1 } elseif {[llength $slots] > 0} { foreach plat {unix win mac} { if {[info exists stubs($name,$plat,$i)]} { append text [addPlatformGuard $plat \ [$slotProc $name $stubs($name,$plat,$i) $i]] set emit 1 } elseif {$onAll} { append text [eval {addPlatformGuard $plat} $skipString] set emit 1 } } } if {$emit == 0} { eval {append text} $skipString } } } else { # Emit separate stubs blocks per platform foreach plat {unix win mac} { if {[info exists stubs($name,$plat,lastNum)]} { set lastNum $stubs($name,$plat,lastNum) set temp {} for {set i 0} {$i <= $lastNum} {incr i} { if {![info exists stubs($name,$plat,$i)]} { eval {append temp} $skipString } else { append temp [$slotProc $name $stubs($name,$plat,$i) $i] } } append text [addPlatformGuard $plat $temp] } } } } # genStubs::emitDeclarations -- # # This function emits the function declarations for this interface. # # Arguments: # name The interface name. # textVar The variable to use for output. # # Results: # None. proc genStubs::emitDeclarations {name textVar} { variable stubs upvar $textVar text append text "\n/*\n * Exported function declarations:\n */\n\n" forAllStubs $name makeDecl 0 text return } # genStubs::emitMacros -- # # This function emits the inline macros for an interface. # # Arguments: # name The name of the interface being emitted. # textVar The variable to use for output. # # Results: # None. proc genStubs::emitMacros {name textVar} { variable stubs variable libraryName upvar $textVar text set upName [string toupper $libraryName] append text "\n#if defined(USE_${upName}_STUBS) && !defined(USE_${upName}_STUB_PROCS)\n" append text "\n/*\n * Inline function declarations:\n */\n\n" forAllStubs $name makeMacro 0 text append text "\n#endif /* defined(USE_${upName}_STUBS) && !defined(USE_${upName}_STUB_PROCS) */\n" return } # genStubs::emitHeader -- # # This function emits the body of the Decls.h file for # the specified interface. # # Arguments: # name The name of the interface being emitted. # # Results: # None. proc genStubs::emitHeader {name} { variable outDir variable hooks set capName [string toupper [string index $name 0]] append capName [string range $name 1 end] emitDeclarations $name text if {[info exists hooks($name)]} { append text "\ntypedef struct ${capName}StubHooks {\n" foreach hook $hooks($name) { set capHook [string toupper [string index $hook 0]] append capHook [string range $hook 1 end] append text " struct ${capHook}Stubs *${hook}Stubs;\n" } append text "} ${capName}StubHooks;\n" } append text "\ntypedef struct ${capName}Stubs {\n" append text " int magic;\n" append text " struct ${capName}StubHooks *hooks;\n\n" emitSlots $name text append text "} ${capName}Stubs;\n" append text "\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n" append text "extern ${capName}Stubs *${name}StubsPtr;\n" append text "#ifdef __cplusplus\n}\n#endif\n" emitMacros $name text rewriteFile [file join $outDir ${name}Decls.h] $text return } # genStubs::emitStubs -- # # This function emits the body of the Stubs.c file for # the specified interface. # # Arguments: # name The name of the interface being emitted. # # Results: # None. proc genStubs::emitStubs {name} { variable outDir append text "\n/*\n * Exported stub functions:\n */\n\n" forAllStubs $name makeStub 0 text rewriteFile [file join $outDir ${name}Stubs.c] $text return } # genStubs::emitInit -- # # Generate the table initializers for an interface. # # Arguments: # name The name of the interface to initialize. # textVar The variable to use for output. # # Results: # Returns the formatted output. proc genStubs::emitInit {name textVar} { variable stubs variable hooks upvar $textVar text set capName [string toupper [string index $name 0]] append capName [string range $name 1 end] if {[info exists hooks($name)]} { append text "\nstatic ${capName}StubHooks ${name}StubHooks = \{\n" set sep " " foreach sub $hooks($name) { append text $sep "&${sub}Stubs" set sep ",\n " } append text "\n\};\n" } append text "\n${capName}Stubs ${name}Stubs = \{\n" append text " TCL_STUB_MAGIC,\n" if {[info exists hooks($name)]} { append text " &${name}StubHooks,\n" } else { append text " NULL,\n" } forAllStubs $name makeInit 1 text {" NULL, /* $i */\n"} append text "\};\n" return } # genStubs::emitInits -- # # This function emits the body of the StubInit.c file for # the specified interface. # # Arguments: # name The name of the interface being emitted. # # Results: # None. proc genStubs::emitInits {} { variable hooks variable outDir variable libraryName variable interfaces # Assuming that dependencies only go one level deep, we need to emit # all of the leaves first to avoid needing forward declarations. set leaves {} set roots {} foreach name [lsort [array names interfaces]] { if {[info exists hooks($name)]} { lappend roots $name } else { lappend leaves $name } } foreach name $leaves { emitInit $name text } foreach name $roots { emitInit $name text } rewriteFile [file join $outDir ${libraryName}StubInit.c] $text } # genStubs::init -- # # This is the main entry point. # # Arguments: # None. # # Results: # None. proc genStubs::init {} { global argv argv0 variable outDir variable interfaces if {[llength $argv] < 2} { puts stderr "usage: $argv0 outDir declFile ?declFile...?" exit 1 } set outDir [lindex $argv 0] foreach file [lrange $argv 1 end] { source $file } foreach name [lsort [array names interfaces]] { puts "Emitting $name" emitHeader $name } emitInits } # lassign -- # # This function emulates the TclX lassign command. # # Arguments: # valueList A list containing the values to be assigned. # args The list of variables to be assigned. # # Results: # Returns any values that were not assigned to variables. proc lassign {valueList args} { if {[llength $args] == 0} { error "wrong # args: lassign list varname ?varname..?" } uplevel [list foreach $args $valueList {break}] return [lrange $valueList [llength $args] end] } genStubs::init tkHTML-4ee7aaa953d6cb59/tools/getpage.c000064400000000000000000000100461151224263100170360ustar00nobodynobody/* ** This is a simple program used to retrieve an HTML document using ** HTTP. The program also fetches all images that the document ** references. */ #include #include #include "getpage.h" #define stricmp strcasecmp /* ** Each image to be loaded is an instance of the following structure. */ typedef struct Image Image; struct Image { char *zUrl; /* The URL for this image */ char *zLocal; /* The local filename */ Image *pNext; /* Next in a list of them all */ }; static FILE *html; /* Html output to this file. */ static int nImage = 0; /* Number of images loaded so far */ static Image *pImage; /* List of all images */ static global_nErr = 0; /* System wide errors */ static char baseUrl[1000];/* The base URL */ static int quiet = 0; /* The quiet flag */ /* ** Make sure the given URL is loaded as a local file. Return the ** name of the local file. */ static char *GetImage(char *zUrl){ Image *p; for(p=pImage; p; p=p->pNext){ if( strcmp(p->zUrl,zUrl)==0 ){ return p->zLocal; } } p = malloc( sizeof(*p) + strlen(zUrl) + 100 ); p->zUrl = (char*)&p[1]; strcpy(p->zUrl, zUrl); p->zLocal = &p->zUrl[strlen(zUrl)+1]; sprintf(p->zLocal,"image%d", ++nImage); p->pNext = pImage; pImage = p; HttpFetch(zUrl, p->zLocal, quiet, 0, 0); return p->zLocal; } /* ** Print a usage comment and exit */ void usage(char *argv0){ fprintf(stderr,"Usage: %s URL\n",argv0); exit(1); } /* ** Handle anything that isn't markup */ static void WordHandler(const char *zText, void *notUsed){ fprintf(html, zText); } /* ** Handle all markup that we don't care about. */ static void DefaultMarkup(int argc, const char **argv, void *notUsed){ int i; fprintf(html,"<%s",argv[0]); for(i=1; i"); } /* ** Handler for markup */ static void ImageMarkup(int argc, const char **argv, void *notUsed){ int i; for(i=1; i (%s)\n",baseUrl, azUrl[0], zResolved); } argv[i+1] = GetImage(zResolved); /* printf("%s -> %s -> argv[i+1]\n",argv[i+1], zResolved); */ free(zResolved); } } DefaultMarkup(argc, argv, 0); } /* ** Handler for markup */ static void BaseMarkup(int argc, const char **argv, void *notUsed){ int i; for(i=1; i $destination" exec /usr/bin/wget -q -O $destination [set $urlvar] >/dev/null } puts "Remembering time --> state/sn.time" puts [set fh [open state/sn.time w]] $now; close $fh ### Future ### Edit the delivered HTML to fit them better into our site. ### Done inside of the page generation templates ! exit tkHTML-4ee7aaa953d6cb59/tools/htdocs_refresh000075500000000000000000000002601151224263100202030ustar00nobodynobody#!/bin/sh cd `dirname $0`/../htdocs out=$HOME/logs/crontab mkdir -p `dirname $out` ../tools/htdocs_get_sf_stats >> $out 2>&1 ../tools/htdocs_regen >> $out 2>&1 exit tkHTML-4ee7aaa953d6cb59/tools/htdocs_regen000075500000000000000000000003531151224263100176500ustar00nobodynobody#!/bin/sh # Assume call with pwd = 'htdocs'. for i in `ls raw/*.exp` do echo $i '-->' `basename $i .exp`.html ../tools/expand -rules ../tools/rules/memchan $i > `basename $i .exp`.html done rm index.php ln -s index.html index.php tkHTML-4ee7aaa953d6cb59/tools/htdocs_setup000075500000000000000000000023211151224263100177050ustar00nobodynobody#!/bin/sh # # Called in response to changes in the cvs repository of memchan # Assumes that the changed files were already retrieved. Uses them to # regenerate the whole website. # pwd = /home/groups/m/me/memchan/ # Remove old temporary information. rm -rf doc mkdir doc cp -r memchan/doc/* doc/ cp -r memchan/htdocs/* htdocs/ # Regenerate the external representatons of all manpages, and the site # itself. At last generate bundles of the documentation for download. out=$HOME/logs/crontab mkdir -p `dirname $out` rm $out ; touch $out cd doc ; ../tools/manpage_regen >>$out ; cd .. cd htdocs ; ../tools/htdocs_refresh ; cd .. tar cf - doc/*.n | gzip -9 > memchan.nroff.tar.gz tar cf - doc/*.n | bzip2 > memchan.nroff.tar.bz2 zip memchan.nroff.tar.zip doc/*.n > /dev/null tar cf - doc/*.html | gzip -9 > memchan.html.tar.gz tar cf - doc/*.html | bzip2 > memchan.html.tar.bz2 zip memchan.html.tar.zip doc/*.html > /dev/null tar cf - doc/*.tmml | gzip -9 > memchan.tmml.tar.gz tar cf - doc/*.tmml | bzip2 > memchan.tmml.tar.bz2 zip memchan.tmml.tar.zip doc/*.tmml > /dev/null mkdir -p htdocs/doc mv memchan.* htdocs/doc/ (sleep 5 ; cp -r memchan/tools/* tools/) & exit tkHTML-4ee7aaa953d6cb59/tools/httpget.c000064400000000000000000000123751151224263100171100ustar00nobodynobody/* ** This file contains code to fetch a single URL into a local file. */ #include #include #include #include #include #include "httpget.h" #define strnicmp strncasecmp /* ** Get a URL using HTTP. Return the result code. If a Location: field ** appears in the header, write it into zLocation[]. Location[] should ** be at least 200 characters in size. */ static int HttpTryOnce(char *zUrl, char *zLocalFile, int quiet, char *zLocation){ int i, j; int nErr = 0; /* Number of errors */ char *zPath; /* Pathname to send as second argument to GET */ int iPort; /* TCP port for the server */ struct hostent *pHost; /* Name information */ int s; /* The main communications socket */ int c; /* A character read from the remote side */ int n; /* Number of characters in header */ int rc = 200; /* The result code */ FILE *sock; /* FILE corresponding to file descriptor s */ FILE *out; /* Write output here */ int last_was_nl; /* TRUE if last character received was '\n' */ struct sockaddr_in addr; /* The address structure */ int nByte = 0; char zIpAddr[400]; /* The IP address of the server to print */ char zMsg[1000]; /* Space to hold error messages */ char zLine[1000]; /* A single line of the header */ out = fopen(zLocalFile, "w"); if( out==0 ){ sprintf(zMsg, "can't open output fule \"%.100s\"", zLocalFile); perror(zMsg); return 1; } i = 0; if( strnicmp(zUrl,"http:",5)==0 ){ i = 5; } while( zUrl[i]=='/' ){ i++; } j = 0; while( zUrl[i] && zUrl[i]!=':' && zUrl[i]!='/' ){ if( jh_addr_list[0],pHost->h_length); if( !quiet ){ fprintf(stderr,"Address resolution: %s -> %d.%d.%d.%d\n",zIpAddr, pHost->h_addr_list[0][0]&0xff, pHost->h_addr_list[0][1]&0xff, pHost->h_addr_list[0][2]&0xff, pHost->h_addr_list[0][3]&0xff); } } s = socket(AF_INET,SOCK_STREAM,0); if( s<0 ){ sprintf(zMsg,"can't open socket to %.100s", zIpAddr); perror(zMsg); fclose(out); return 1; } if( connect(s,(struct sockaddr*)&addr,sizeof(addr))<0 ){ sprintf(zMsg,"can't connect to host %.100s", zIpAddr); perror(zMsg); fclose(out); return 1; } sock = fdopen(s,"r+"); if( *zPath==0 ) zPath = "/"; fprintf(sock,"GET %s HTTP/1.0\r\n",zPath); fprintf(sock,"User-Agent: Mozilla/2.0 (X11; U; Linux 0.99p17 i486)\r\n"); if( iPort!=80 ){ fprintf(sock,"Host: %s:%d\r\n", zIpAddr, iPort); }else{ fprintf(sock,"Host: %s\r\n", zIpAddr); } fprintf(sock,"Accept: image/gif, image/x-xbitmap, image/jpeg, */*\r\n"); fprintf(sock,"\r\n"); fflush(sock); n = 0; rc = 0; while( (c=getc(sock))!=EOF && (c!='\n' || !last_was_nl) ){ if( c=='\r' ) continue; last_was_nl = (c=='\n'); if( last_was_nl ){ zLine[n] = 0; if( strncmp(zLine,"Location:",9)==0 && zLocation ){ int j, k; for(j=9; isspace(zLine[j]); j++){} k = 0; while( zLine[j] && !isspace(zLine[j]) && k<199 ){ zLocation[k++] = zLine[j++]; } zLocation[k] = 0; if( !quiet ) fprintf(stderr,"Location: %s\n", zLocation); }else if( rc==0 ){ sscanf(zLine,"HTTP/%*d.%*d %d ",&rc); if( !quiet ) fprintf(stderr,"Status: %d\n", rc); } } if( n %s\n", zUrl, zLocalFile); rc = HttpTryOnce(zUrl, zLocalFile, quiet, zLocation); if( rc==301 || rc==302 ){ char *z; const char *az[2]; az[0] = zLocation; az[1] = 0; z = ResolveUrl(zUrl, az); if( zUrl!=zOriginalUrl ){ free(zUrl); } zUrl = z; }else{ break; } } if( nActual>0 && zActual!=0 ){ sprintf(zActual, "%.*s", nActual, zUrl); } if( zUrl!=zOriginalUrl ){ free(zUrl); } return rc; } tkHTML-4ee7aaa953d6cb59/tools/importicons.tcl000064400000000000000000000012511151224263100203260ustar00nobodynobodypackage require base64 set dir /Users/dan/tmp/tango-icon-theme-0.8.1/32x32/ set A(hv3_previmg) actions/go-previous.png set A(hv3_nextimg) actions/go-next.png set A(hv3_stopimg) actions/process-stop.png set A(hv3_newimg) actions/tab-new.png set A(hv3_reloadimg) actions/view-refresh.png set A(hv3_homeimg) actions/go-home.png set A(hv3_bugimg) actions/mail-message-new.png puts "proc color_icons {} {" foreach {key value} [array get A] { set fd [open [file join $dir $value]] fconfigure $fd -translation binary -encoding binary set data [read $fd] close $fd puts "image create photo $key -data {" puts [base64 -mode encode $data] puts "}" } puts "}" tkHTML-4ee7aaa953d6cb59/tools/install-sh000075500000000000000000000042121151224263100172600ustar00nobodynobody#!/bin/sh # # install - install a program, script, or datafile # This comes from X11R5; it is not part of GNU. # # $XConsortium: install.sh,v 1.2 89/12/18 14:47:22 jim Exp $ # # This script is compatible with the BSD install script, but was written # from scratch. # # set DOITPROG to echo to test this script # Don't use :- since 4.3BSD and earlier shells don't like it. doit="${DOITPROG-}" # put in absolute paths if you don't have them in your path; or use env. vars. mvprog="${MVPROG-mv}" cpprog="${CPPROG-cp}" chmodprog="${CHMODPROG-chmod}" chownprog="${CHOWNPROG-chown}" chgrpprog="${CHGRPPROG-chgrp}" stripprog="${STRIPPROG-strip}" rmprog="${RMPROG-rm}" instcmd="$mvprog" chmodcmd="" chowncmd="" chgrpcmd="" stripcmd="" rmcmd="$rmprog -f" mvcmd="$mvprog" src="" dst="" while [ x"$1" != x ]; do case $1 in -c) instcmd="$cpprog" shift continue;; -m) chmodcmd="$chmodprog $2" shift shift continue;; -o) chowncmd="$chownprog $2" shift shift continue;; -g) chgrpcmd="$chgrpprog $2" shift shift continue;; -s) stripcmd="$stripprog" shift continue;; *) if [ x"$src" = x ] then src=$1 else dst=$1 fi shift continue;; esac done if [ x"$src" = x ] then echo "install: no input file specified" exit 1 fi if [ x"$dst" = x ] then echo "install: no destination specified" exit 1 fi # If destination is a directory, append the input filename; if your system # does not like double slashes in filenames, you may need to add some logic if [ -d $dst ] then dst="$dst"/`basename $src` fi # Make a temp file name in the proper directory. dstdir=`dirname $dst` dsttmp=$dstdir/#inst.$$# # Move or copy the file name to the temp name $doit $instcmd $src $dsttmp # and set any options; do chmod last to preserve setuid bits if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; fi if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; fi if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; fi if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; fi # Now rename the file to the real destination. $doit $rmcmd $dst $doit $mvcmd $dsttmp $dst exit 0 tkHTML-4ee7aaa953d6cb59/tools/lemon.c000064400000000000000000004166411151224263100165470ustar00nobodynobody/* ** This file contains all sources (including headers) to the LEMON ** LALR(1) parser generator. The sources have been combined into a ** single file to make it easy to include LEMON in the source tree ** and Makefile of another program. ** ** The author of this program disclaims copyright. */ #include #include #include #include #include #ifndef __WIN32__ # if defined(_WIN32) || defined(WIN32) # define __WIN32__ # endif #endif /* #define PRIVATE static */ #define PRIVATE #ifdef TEST #define MAXRHS 5 /* Set low to exercise exception code */ #else #define MAXRHS 1000 #endif char *msort(); extern void *malloc(); /******** From the file "action.h" *************************************/ struct action *Action_new(); struct action *Action_sort(); /********* From the file "assert.h" ************************************/ void myassert(); #ifndef NDEBUG # define assert(X) if(!(X))myassert(__FILE__,__LINE__) #else # define assert(X) #endif /********** From the file "build.h" ************************************/ void FindRulePrecedences(); void FindFirstSets(); void FindStates(); void FindLinks(); void FindFollowSets(); void FindActions(); /********* From the file "configlist.h" *********************************/ void Configlist_init(/* void */); struct config *Configlist_add(/* struct rule *, int */); struct config *Configlist_addbasis(/* struct rule *, int */); void Configlist_closure(/* void */); void Configlist_sort(/* void */); void Configlist_sortbasis(/* void */); struct config *Configlist_return(/* void */); struct config *Configlist_basis(/* void */); void Configlist_eat(/* struct config * */); void Configlist_reset(/* void */); /********* From the file "error.h" ***************************************/ void ErrorMsg(const char *, int,const char *, ...); /****** From the file "option.h" ******************************************/ struct s_options { enum { OPT_FLAG=1, OPT_INT, OPT_DBL, OPT_STR, OPT_FFLAG, OPT_FINT, OPT_FDBL, OPT_FSTR} type; char *label; char *arg; char *message; }; int OptInit(/* char**,struct s_options*,FILE* */); int OptNArgs(/* void */); char *OptArg(/* int */); void OptErr(/* int */); void OptPrint(/* void */); /******** From the file "parse.h" *****************************************/ void Parse(/* struct lemon *lemp */); /********* From the file "plink.h" ***************************************/ struct plink *Plink_new(/* void */); void Plink_add(/* struct plink **, struct config * */); void Plink_copy(/* struct plink **, struct plink * */); void Plink_delete(/* struct plink * */); /********** From the file "report.h" *************************************/ void Reprint(/* struct lemon * */); void ReportOutput(/* struct lemon * */); void ReportTable(/* struct lemon * */); void ReportHeader(/* struct lemon * */); void CompressTables(/* struct lemon * */); void ResortStates(/* struct lemon * */); /********** From the file "set.h" ****************************************/ void SetSize(/* int N */); /* All sets will be of size N */ char *SetNew(/* void */); /* A new set for element 0..N */ void SetFree(/* char* */); /* Deallocate a set */ int SetAdd(/* char*,int */); /* Add element to a set */ int SetUnion(/* char *A,char *B */); /* A <- A U B, thru element N */ #define SetFind(X,Y) (X[Y]) /* True if Y is in set X */ /********** From the file "struct.h" *************************************/ /* ** Principal data structures for the LEMON parser generator. */ typedef enum {B_FALSE=0, B_TRUE} Boolean; /* Symbols (terminals and nonterminals) of the grammar are stored ** in the following: */ struct symbol { char *name; /* Name of the symbol */ int index; /* Index number for this symbol */ enum { TERMINAL, NONTERMINAL, MULTITERMINAL } type; /* Symbols are all either TERMINALS or NTs */ struct rule *rule; /* Linked list of rules of this (if an NT) */ struct symbol *fallback; /* fallback token in case this token doesn't parse */ int prec; /* Precedence if defined (-1 otherwise) */ enum e_assoc { LEFT, RIGHT, NONE, UNK } assoc; /* Associativity if predecence is defined */ char *firstset; /* First-set for all rules of this symbol */ Boolean lambda; /* True if NT and can generate an empty string */ char *destructor; /* Code which executes whenever this symbol is ** popped from the stack during error processing */ int destructorln; /* Line number of destructor code */ char *datatype; /* The data type of information held by this ** object. Only used if type==NONTERMINAL */ int dtnum; /* The data type number. In the parser, the value ** stack is a union. The .yy%d element of this ** union is the correct data type for this object */ /* The following fields are used by MULTITERMINALs only */ int nsubsym; /* Number of constituent symbols in the MULTI */ struct symbol **subsym; /* Array of constituent symbols */ }; /* Each production rule in the grammar is stored in the following ** structure. */ struct rule { struct symbol *lhs; /* Left-hand side of the rule */ char *lhsalias; /* Alias for the LHS (NULL if none) */ int ruleline; /* Line number for the rule */ int nrhs; /* Number of RHS symbols */ struct symbol **rhs; /* The RHS symbols */ char **rhsalias; /* An alias for each RHS symbol (NULL if none) */ int line; /* Line number at which code begins */ char *code; /* The code executed when this rule is reduced */ struct symbol *precsym; /* Precedence symbol for this rule */ int index; /* An index number for this rule */ Boolean canReduce; /* True if this rule is ever reduced */ struct rule *nextlhs; /* Next rule with the same LHS */ struct rule *next; /* Next rule in the global list */ }; /* A configuration is a production rule of the grammar together with ** a mark (dot) showing how much of that rule has been processed so far. ** Configurations also contain a follow-set which is a list of terminal ** symbols which are allowed to immediately follow the end of the rule. ** Every configuration is recorded as an instance of the following: */ struct config { struct rule *rp; /* The rule upon which the configuration is based */ int dot; /* The parse point */ char *fws; /* Follow-set for this configuration only */ struct plink *fplp; /* Follow-set forward propagation links */ struct plink *bplp; /* Follow-set backwards propagation links */ struct state *stp; /* Pointer to state which contains this */ enum { COMPLETE, /* The status is used during followset and */ INCOMPLETE /* shift computations */ } status; struct config *next; /* Next configuration in the state */ struct config *bp; /* The next basis configuration */ }; /* Every shift or reduce operation is stored as one of the following */ struct action { struct symbol *sp; /* The look-ahead symbol */ enum e_action { SHIFT, ACCEPT, REDUCE, ERROR, CONFLICT, /* Was a reduce, but part of a conflict */ SH_RESOLVED, /* Was a shift. Precedence resolved conflict */ RD_RESOLVED, /* Was reduce. Precedence resolved conflict */ NOT_USED /* Deleted by compression */ } type; union { struct state *stp; /* The new state, if a shift */ struct rule *rp; /* The rule, if a reduce */ } x; struct action *next; /* Next action for this state */ struct action *collide; /* Next action with the same hash */ }; /* Each state of the generated parser's finite state machine ** is encoded as an instance of the following structure. */ struct state { struct config *bp; /* The basis configurations for this state */ struct config *cfp; /* All configurations in this set */ int statenum; /* Sequencial number for this state */ struct action *ap; /* Array of actions for this state */ int nTknAct, nNtAct; /* Number of actions on terminals and nonterminals */ int iTknOfst, iNtOfst; /* yy_action[] offset for terminals and nonterms */ int iDflt; /* Default action */ }; #define NO_OFFSET (-2147483647) /* A followset propagation link indicates that the contents of one ** configuration followset should be propagated to another whenever ** the first changes. */ struct plink { struct config *cfp; /* The configuration to which linked */ struct plink *next; /* The next propagate link */ }; /* The state vector for the entire parser generator is recorded as ** follows. (LEMON uses no global variables and makes little use of ** static variables. Fields in the following structure can be thought ** of as begin global variables in the program.) */ struct lemon { struct state **sorted; /* Table of states sorted by state number */ struct rule *rule; /* List of all rules */ int nstate; /* Number of states */ int nrule; /* Number of rules */ int nsymbol; /* Number of terminal and nonterminal symbols */ int nterminal; /* Number of terminal symbols */ struct symbol **symbols; /* Sorted array of pointers to symbols */ int errorcnt; /* Number of errors */ struct symbol *errsym; /* The error symbol */ char *name; /* Name of the generated parser */ char *arg; /* Declaration of the 3th argument to parser */ char *tokentype; /* Type of terminal symbols in the parser stack */ char *vartype; /* The default type of non-terminal symbols */ char *start; /* Name of the start symbol for the grammar */ char *stacksize; /* Size of the parser stack */ char *include; /* Code to put at the start of the C file */ int includeln; /* Line number for start of include code */ char *error; /* Code to execute when an error is seen */ int errorln; /* Line number for start of error code */ char *overflow; /* Code to execute on a stack overflow */ int overflowln; /* Line number for start of overflow code */ char *failure; /* Code to execute on parser failure */ int failureln; /* Line number for start of failure code */ char *accept; /* Code to execute when the parser excepts */ int acceptln; /* Line number for the start of accept code */ char *extracode; /* Code appended to the generated file */ int extracodeln; /* Line number for the start of the extra code */ char *tokendest; /* Code to execute to destroy token data */ int tokendestln; /* Line number for token destroyer code */ char *vardest; /* Code for the default non-terminal destructor */ int vardestln; /* Line number for default non-term destructor code*/ char *filename; /* Name of the input file */ char *outname; /* Name of the current output file */ char *tokenprefix; /* A prefix added to token names in the .h file */ int nconflict; /* Number of parsing conflicts */ int tablesize; /* Size of the parse tables */ int basisflag; /* Print only basis configurations */ int has_fallback; /* True if any %fallback is seen in the grammer */ char *argv0; /* Name of the program */ }; #define MemoryCheck(X) if((X)==0){ \ extern void memory_error(); \ memory_error(); \ } /**************** From the file "table.h" *********************************/ /* ** All code in this file has been automatically generated ** from a specification in the file ** "table.q" ** by the associative array code building program "aagen". ** Do not edit this file! Instead, edit the specification ** file, then rerun aagen. */ /* ** Code for processing tables in the LEMON parser generator. */ /* Routines for handling a strings */ char *Strsafe(); void Strsafe_init(/* void */); int Strsafe_insert(/* char * */); char *Strsafe_find(/* char * */); /* Routines for handling symbols of the grammar */ struct symbol *Symbol_new(); int Symbolcmpp(/* struct symbol **, struct symbol ** */); void Symbol_init(/* void */); int Symbol_insert(/* struct symbol *, char * */); struct symbol *Symbol_find(/* char * */); struct symbol *Symbol_Nth(/* int */); int Symbol_count(/* */); struct symbol **Symbol_arrayof(/* */); /* Routines to manage the state table */ int Configcmp(/* struct config *, struct config * */); struct state *State_new(); void State_init(/* void */); int State_insert(/* struct state *, struct config * */); struct state *State_find(/* struct config * */); struct state **State_arrayof(/* */); /* Routines used for efficiency in Configlist_add */ void Configtable_init(/* void */); int Configtable_insert(/* struct config * */); struct config *Configtable_find(/* struct config * */); void Configtable_clear(/* int(*)(struct config *) */); /****************** From the file "action.c" *******************************/ /* ** Routines processing parser actions in the LEMON parser generator. */ /* Allocate a new parser action */ struct action *Action_new(){ static struct action *freelist = 0; struct action *new; if( freelist==0 ){ int i; int amt = 100; freelist = (struct action *)malloc( sizeof(struct action)*amt ); if( freelist==0 ){ fprintf(stderr,"Unable to allocate memory for a new parser action."); exit(1); } for(i=0; inext; return new; } /* Compare two actions */ static int actioncmp(ap1,ap2) struct action *ap1; struct action *ap2; { int rc; rc = ap1->sp->index - ap2->sp->index; if( rc==0 ) rc = (int)ap1->type - (int)ap2->type; if( rc==0 ){ assert( ap1->type==REDUCE || ap1->type==RD_RESOLVED || ap1->type==CONFLICT); assert( ap2->type==REDUCE || ap2->type==RD_RESOLVED || ap2->type==CONFLICT); rc = ap1->x.rp->index - ap2->x.rp->index; } return rc; } /* Sort parser actions */ struct action *Action_sort(ap) struct action *ap; { ap = (struct action *)msort((char *)ap,(char **)&ap->next,actioncmp); return ap; } void Action_add(app,type,sp,arg) struct action **app; enum e_action type; struct symbol *sp; char *arg; { struct action *new; new = Action_new(); new->next = *app; *app = new; new->type = type; new->sp = sp; if( type==SHIFT ){ new->x.stp = (struct state *)arg; }else{ new->x.rp = (struct rule *)arg; } } /********************** New code to implement the "acttab" module ***********/ /* ** This module implements routines use to construct the yy_action[] table. */ /* ** The state of the yy_action table under construction is an instance of ** the following structure */ typedef struct acttab acttab; struct acttab { int nAction; /* Number of used slots in aAction[] */ int nActionAlloc; /* Slots allocated for aAction[] */ struct { int lookahead; /* Value of the lookahead token */ int action; /* Action to take on the given lookahead */ } *aAction, /* The yy_action[] table under construction */ *aLookahead; /* A single new transaction set */ int mnLookahead; /* Minimum aLookahead[].lookahead */ int mnAction; /* Action associated with mnLookahead */ int mxLookahead; /* Maximum aLookahead[].lookahead */ int nLookahead; /* Used slots in aLookahead[] */ int nLookaheadAlloc; /* Slots allocated in aLookahead[] */ }; /* Return the number of entries in the yy_action table */ #define acttab_size(X) ((X)->nAction) /* The value for the N-th entry in yy_action */ #define acttab_yyaction(X,N) ((X)->aAction[N].action) /* The value for the N-th entry in yy_lookahead */ #define acttab_yylookahead(X,N) ((X)->aAction[N].lookahead) /* Free all memory associated with the given acttab */ void acttab_free(acttab *p){ free( p->aAction ); free( p->aLookahead ); free( p ); } /* Allocate a new acttab structure */ acttab *acttab_alloc(void){ acttab *p = malloc( sizeof(*p) ); if( p==0 ){ fprintf(stderr,"Unable to allocate memory for a new acttab."); exit(1); } memset(p, 0, sizeof(*p)); return p; } /* Add a new action to the current transaction set */ void acttab_action(acttab *p, int lookahead, int action){ if( p->nLookahead>=p->nLookaheadAlloc ){ p->nLookaheadAlloc += 25; p->aLookahead = realloc( p->aLookahead, sizeof(p->aLookahead[0])*p->nLookaheadAlloc ); if( p->aLookahead==0 ){ fprintf(stderr,"malloc failed\n"); exit(1); } } if( p->nLookahead==0 ){ p->mxLookahead = lookahead; p->mnLookahead = lookahead; p->mnAction = action; }else{ if( p->mxLookaheadmxLookahead = lookahead; if( p->mnLookahead>lookahead ){ p->mnLookahead = lookahead; p->mnAction = action; } } p->aLookahead[p->nLookahead].lookahead = lookahead; p->aLookahead[p->nLookahead].action = action; p->nLookahead++; } /* ** Add the transaction set built up with prior calls to acttab_action() ** into the current action table. Then reset the transaction set back ** to an empty set in preparation for a new round of acttab_action() calls. ** ** Return the offset into the action table of the new transaction. */ int acttab_insert(acttab *p){ int i, j, k, n; assert( p->nLookahead>0 ); /* Make sure we have enough space to hold the expanded action table ** in the worst case. The worst case occurs if the transaction set ** must be appended to the current action table */ n = p->mxLookahead + 1; if( p->nAction + n >= p->nActionAlloc ){ int oldAlloc = p->nActionAlloc; p->nActionAlloc = p->nAction + n + p->nActionAlloc + 20; p->aAction = realloc( p->aAction, sizeof(p->aAction[0])*p->nActionAlloc); if( p->aAction==0 ){ fprintf(stderr,"malloc failed\n"); exit(1); } for(i=oldAlloc; inActionAlloc; i++){ p->aAction[i].lookahead = -1; p->aAction[i].action = -1; } } /* Scan the existing action table looking for an offset where we can ** insert the current transaction set. Fall out of the loop when that ** offset is found. In the worst case, we fall out of the loop when ** i reaches p->nAction, which means we append the new transaction set. ** ** i is the index in p->aAction[] where p->mnLookahead is inserted. */ for(i=0; inAction+p->mnLookahead; i++){ if( p->aAction[i].lookahead<0 ){ for(j=0; jnLookahead; j++){ k = p->aLookahead[j].lookahead - p->mnLookahead + i; if( k<0 ) break; if( p->aAction[k].lookahead>=0 ) break; } if( jnLookahead ) continue; for(j=0; jnAction; j++){ if( p->aAction[j].lookahead==j+p->mnLookahead-i ) break; } if( j==p->nAction ){ break; /* Fits in empty slots */ } }else if( p->aAction[i].lookahead==p->mnLookahead ){ if( p->aAction[i].action!=p->mnAction ) continue; for(j=0; jnLookahead; j++){ k = p->aLookahead[j].lookahead - p->mnLookahead + i; if( k<0 || k>=p->nAction ) break; if( p->aLookahead[j].lookahead!=p->aAction[k].lookahead ) break; if( p->aLookahead[j].action!=p->aAction[k].action ) break; } if( jnLookahead ) continue; n = 0; for(j=0; jnAction; j++){ if( p->aAction[j].lookahead<0 ) continue; if( p->aAction[j].lookahead==j+p->mnLookahead-i ) n++; } if( n==p->nLookahead ){ break; /* Same as a prior transaction set */ } } } /* Insert transaction set at index i. */ for(j=0; jnLookahead; j++){ k = p->aLookahead[j].lookahead - p->mnLookahead + i; p->aAction[k] = p->aLookahead[j]; if( k>=p->nAction ) p->nAction = k+1; } p->nLookahead = 0; /* Return the offset that is added to the lookahead in order to get the ** index into yy_action of the action */ return i - p->mnLookahead; } /********************** From the file "assert.c" ****************************/ /* ** A more efficient way of handling assertions. */ void myassert(file,line) char *file; int line; { fprintf(stderr,"Assertion failed on line %d of file \"%s\"\n",line,file); exit(1); } /********************** From the file "build.c" *****************************/ /* ** Routines to construction the finite state machine for the LEMON ** parser generator. */ /* Find a precedence symbol of every rule in the grammar. ** ** Those rules which have a precedence symbol coded in the input ** grammar using the "[symbol]" construct will already have the ** rp->precsym field filled. Other rules take as their precedence ** symbol the first RHS symbol with a defined precedence. If there ** are not RHS symbols with a defined precedence, the precedence ** symbol field is left blank. */ void FindRulePrecedences(xp) struct lemon *xp; { struct rule *rp; for(rp=xp->rule; rp; rp=rp->next){ if( rp->precsym==0 ){ int i, j; for(i=0; inrhs && rp->precsym==0; i++){ struct symbol *sp = rp->rhs[i]; if( sp->type==MULTITERMINAL ){ for(j=0; jnsubsym; j++){ if( sp->subsym[j]->prec>=0 ){ rp->precsym = sp->subsym[j]; break; } } }else if( sp->prec>=0 ){ rp->precsym = rp->rhs[i]; } } } } return; } /* Find all nonterminals which will generate the empty string. ** Then go back and compute the first sets of every nonterminal. ** The first set is the set of all terminal symbols which can begin ** a string generated by that nonterminal. */ void FindFirstSets(lemp) struct lemon *lemp; { int i, j; struct rule *rp; int progress; for(i=0; insymbol; i++){ lemp->symbols[i]->lambda = B_FALSE; } for(i=lemp->nterminal; insymbol; i++){ lemp->symbols[i]->firstset = SetNew(); } /* First compute all lambdas */ do{ progress = 0; for(rp=lemp->rule; rp; rp=rp->next){ if( rp->lhs->lambda ) continue; for(i=0; inrhs; i++){ struct symbol *sp = rp->rhs[i]; if( sp->type!=TERMINAL || sp->lambda==B_FALSE ) break; } if( i==rp->nrhs ){ rp->lhs->lambda = B_TRUE; progress = 1; } } }while( progress ); /* Now compute all first sets */ do{ struct symbol *s1, *s2; progress = 0; for(rp=lemp->rule; rp; rp=rp->next){ s1 = rp->lhs; for(i=0; inrhs; i++){ s2 = rp->rhs[i]; if( s2->type==TERMINAL ){ progress += SetAdd(s1->firstset,s2->index); break; }else if( s2->type==MULTITERMINAL ){ for(j=0; jnsubsym; j++){ progress += SetAdd(s1->firstset,s2->subsym[j]->index); } break; }else if( s1==s2 ){ if( s1->lambda==B_FALSE ) break; }else{ progress += SetUnion(s1->firstset,s2->firstset); if( s2->lambda==B_FALSE ) break; } } } }while( progress ); return; } /* Compute all LR(0) states for the grammar. Links ** are added to between some states so that the LR(1) follow sets ** can be computed later. */ PRIVATE struct state *getstate(/* struct lemon * */); /* forward reference */ void FindStates(lemp) struct lemon *lemp; { struct symbol *sp; struct rule *rp; Configlist_init(); /* Find the start symbol */ if( lemp->start ){ sp = Symbol_find(lemp->start); if( sp==0 ){ ErrorMsg(lemp->filename,0, "The specified start symbol \"%s\" is not \ in a nonterminal of the grammar. \"%s\" will be used as the start \ symbol instead.",lemp->start,lemp->rule->lhs->name); lemp->errorcnt++; sp = lemp->rule->lhs; } }else{ sp = lemp->rule->lhs; } /* Make sure the start symbol doesn't occur on the right-hand side of ** any rule. Report an error if it does. (YACC would generate a new ** start symbol in this case.) */ for(rp=lemp->rule; rp; rp=rp->next){ int i; for(i=0; inrhs; i++){ if( rp->rhs[i]==sp ){ /* FIX ME: Deal with multiterminals */ ErrorMsg(lemp->filename,0, "The start symbol \"%s\" occurs on the \ right-hand side of a rule. This will result in a parser which \ does not work properly.",sp->name); lemp->errorcnt++; } } } /* The basis configuration set for the first state ** is all rules which have the start symbol as their ** left-hand side */ for(rp=sp->rule; rp; rp=rp->nextlhs){ struct config *newcfp; newcfp = Configlist_addbasis(rp,0); SetAdd(newcfp->fws,0); } /* Compute the first state. All other states will be ** computed automatically during the computation of the first one. ** The returned pointer to the first state is not used. */ (void)getstate(lemp); return; } /* Return a pointer to a state which is described by the configuration ** list which has been built from calls to Configlist_add. */ PRIVATE void buildshifts(/* struct lemon *, struct state * */); /* Forwd ref */ PRIVATE struct state *getstate(lemp) struct lemon *lemp; { struct config *cfp, *bp; struct state *stp; /* Extract the sorted basis of the new state. The basis was constructed ** by prior calls to "Configlist_addbasis()". */ Configlist_sortbasis(); bp = Configlist_basis(); /* Get a state with the same basis */ stp = State_find(bp); if( stp ){ /* A state with the same basis already exists! Copy all the follow-set ** propagation links from the state under construction into the ** preexisting state, then return a pointer to the preexisting state */ struct config *x, *y; for(x=bp, y=stp->bp; x && y; x=x->bp, y=y->bp){ Plink_copy(&y->bplp,x->bplp); Plink_delete(x->fplp); x->fplp = x->bplp = 0; } cfp = Configlist_return(); Configlist_eat(cfp); }else{ /* This really is a new state. Construct all the details */ Configlist_closure(lemp); /* Compute the configuration closure */ Configlist_sort(); /* Sort the configuration closure */ cfp = Configlist_return(); /* Get a pointer to the config list */ stp = State_new(); /* A new state structure */ MemoryCheck(stp); stp->bp = bp; /* Remember the configuration basis */ stp->cfp = cfp; /* Remember the configuration closure */ stp->statenum = lemp->nstate++; /* Every state gets a sequence number */ stp->ap = 0; /* No actions, yet. */ State_insert(stp,stp->bp); /* Add to the state table */ buildshifts(lemp,stp); /* Recursively compute successor states */ } return stp; } /* ** Return true if two symbols are the same. */ int same_symbol(a,b) struct symbol *a; struct symbol *b; { int i; if( a==b ) return 1; if( a->type!=MULTITERMINAL ) return 0; if( b->type!=MULTITERMINAL ) return 0; if( a->nsubsym!=b->nsubsym ) return 0; for(i=0; insubsym; i++){ if( a->subsym[i]!=b->subsym[i] ) return 0; } return 1; } /* Construct all successor states to the given state. A "successor" ** state is any state which can be reached by a shift action. */ PRIVATE void buildshifts(lemp,stp) struct lemon *lemp; struct state *stp; /* The state from which successors are computed */ { struct config *cfp; /* For looping thru the config closure of "stp" */ struct config *bcfp; /* For the inner loop on config closure of "stp" */ struct config *new; /* */ struct symbol *sp; /* Symbol following the dot in configuration "cfp" */ struct symbol *bsp; /* Symbol following the dot in configuration "bcfp" */ struct state *newstp; /* A pointer to a successor state */ /* Each configuration becomes complete after it contibutes to a successor ** state. Initially, all configurations are incomplete */ for(cfp=stp->cfp; cfp; cfp=cfp->next) cfp->status = INCOMPLETE; /* Loop through all configurations of the state "stp" */ for(cfp=stp->cfp; cfp; cfp=cfp->next){ if( cfp->status==COMPLETE ) continue; /* Already used by inner loop */ if( cfp->dot>=cfp->rp->nrhs ) continue; /* Can't shift this config */ Configlist_reset(); /* Reset the new config set */ sp = cfp->rp->rhs[cfp->dot]; /* Symbol after the dot */ /* For every configuration in the state "stp" which has the symbol "sp" ** following its dot, add the same configuration to the basis set under ** construction but with the dot shifted one symbol to the right. */ for(bcfp=cfp; bcfp; bcfp=bcfp->next){ if( bcfp->status==COMPLETE ) continue; /* Already used */ if( bcfp->dot>=bcfp->rp->nrhs ) continue; /* Can't shift this one */ bsp = bcfp->rp->rhs[bcfp->dot]; /* Get symbol after dot */ if( !same_symbol(bsp,sp) ) continue; /* Must be same as for "cfp" */ bcfp->status = COMPLETE; /* Mark this config as used */ new = Configlist_addbasis(bcfp->rp,bcfp->dot+1); Plink_add(&new->bplp,bcfp); } /* Get a pointer to the state described by the basis configuration set ** constructed in the preceding loop */ newstp = getstate(lemp); /* The state "newstp" is reached from the state "stp" by a shift action ** on the symbol "sp" */ if( sp->type==MULTITERMINAL ){ int i; for(i=0; insubsym; i++){ Action_add(&stp->ap,SHIFT,sp->subsym[i],(char*)newstp); } }else{ Action_add(&stp->ap,SHIFT,sp,(char *)newstp); } } } /* ** Construct the propagation links */ void FindLinks(lemp) struct lemon *lemp; { int i; struct config *cfp, *other; struct state *stp; struct plink *plp; /* Housekeeping detail: ** Add to every propagate link a pointer back to the state to ** which the link is attached. */ for(i=0; instate; i++){ stp = lemp->sorted[i]; for(cfp=stp->cfp; cfp; cfp=cfp->next){ cfp->stp = stp; } } /* Convert all backlinks into forward links. Only the forward ** links are used in the follow-set computation. */ for(i=0; instate; i++){ stp = lemp->sorted[i]; for(cfp=stp->cfp; cfp; cfp=cfp->next){ for(plp=cfp->bplp; plp; plp=plp->next){ other = plp->cfp; Plink_add(&other->fplp,cfp); } } } } /* Compute all followsets. ** ** A followset is the set of all symbols which can come immediately ** after a configuration. */ void FindFollowSets(lemp) struct lemon *lemp; { int i; struct config *cfp; struct plink *plp; int progress; int change; for(i=0; instate; i++){ for(cfp=lemp->sorted[i]->cfp; cfp; cfp=cfp->next){ cfp->status = INCOMPLETE; } } do{ progress = 0; for(i=0; instate; i++){ for(cfp=lemp->sorted[i]->cfp; cfp; cfp=cfp->next){ if( cfp->status==COMPLETE ) continue; for(plp=cfp->fplp; plp; plp=plp->next){ change = SetUnion(plp->cfp->fws,cfp->fws); if( change ){ plp->cfp->status = INCOMPLETE; progress = 1; } } cfp->status = COMPLETE; } } }while( progress ); } static int resolve_conflict(); /* Compute the reduce actions, and resolve conflicts. */ void FindActions(lemp) struct lemon *lemp; { int i,j; struct config *cfp; struct state *stp; struct symbol *sp; struct rule *rp; /* Add all of the reduce actions ** A reduce action is added for each element of the followset of ** a configuration which has its dot at the extreme right. */ for(i=0; instate; i++){ /* Loop over all states */ stp = lemp->sorted[i]; for(cfp=stp->cfp; cfp; cfp=cfp->next){ /* Loop over all configurations */ if( cfp->rp->nrhs==cfp->dot ){ /* Is dot at extreme right? */ for(j=0; jnterminal; j++){ if( SetFind(cfp->fws,j) ){ /* Add a reduce action to the state "stp" which will reduce by the ** rule "cfp->rp" if the lookahead symbol is "lemp->symbols[j]" */ Action_add(&stp->ap,REDUCE,lemp->symbols[j],(char *)cfp->rp); } } } } } /* Add the accepting token */ if( lemp->start ){ sp = Symbol_find(lemp->start); if( sp==0 ) sp = lemp->rule->lhs; }else{ sp = lemp->rule->lhs; } /* Add to the first state (which is always the starting state of the ** finite state machine) an action to ACCEPT if the lookahead is the ** start nonterminal. */ Action_add(&lemp->sorted[0]->ap,ACCEPT,sp,0); /* Resolve conflicts */ for(i=0; instate; i++){ struct action *ap, *nap; struct state *stp; stp = lemp->sorted[i]; assert( stp->ap ); stp->ap = Action_sort(stp->ap); for(ap=stp->ap; ap && ap->next; ap=ap->next){ for(nap=ap->next; nap && nap->sp==ap->sp; nap=nap->next){ /* The two actions "ap" and "nap" have the same lookahead. ** Figure out which one should be used */ lemp->nconflict += resolve_conflict(ap,nap,lemp->errsym); } } } /* Report an error for each rule that can never be reduced. */ for(rp=lemp->rule; rp; rp=rp->next) rp->canReduce = B_FALSE; for(i=0; instate; i++){ struct action *ap; for(ap=lemp->sorted[i]->ap; ap; ap=ap->next){ if( ap->type==REDUCE ) ap->x.rp->canReduce = B_TRUE; } } for(rp=lemp->rule; rp; rp=rp->next){ if( rp->canReduce ) continue; ErrorMsg(lemp->filename,rp->ruleline,"This rule can not be reduced.\n"); lemp->errorcnt++; } } /* Resolve a conflict between the two given actions. If the ** conflict can't be resolve, return non-zero. ** ** NO LONGER TRUE: ** To resolve a conflict, first look to see if either action ** is on an error rule. In that case, take the action which ** is not associated with the error rule. If neither or both ** actions are associated with an error rule, then try to ** use precedence to resolve the conflict. ** ** If either action is a SHIFT, then it must be apx. This ** function won't work if apx->type==REDUCE and apy->type==SHIFT. */ static int resolve_conflict(apx,apy,errsym) struct action *apx; struct action *apy; struct symbol *errsym; /* The error symbol (if defined. NULL otherwise) */ { struct symbol *spx, *spy; int errcnt = 0; assert( apx->sp==apy->sp ); /* Otherwise there would be no conflict */ if( apx->type==SHIFT && apy->type==REDUCE ){ spx = apx->sp; spy = apy->x.rp->precsym; if( spy==0 || spx->prec<0 || spy->prec<0 ){ /* Not enough precedence information. */ apy->type = CONFLICT; errcnt++; }else if( spx->prec>spy->prec ){ /* Lower precedence wins */ apy->type = RD_RESOLVED; }else if( spx->precprec ){ apx->type = SH_RESOLVED; }else if( spx->prec==spy->prec && spx->assoc==RIGHT ){ /* Use operator */ apy->type = RD_RESOLVED; /* associativity */ }else if( spx->prec==spy->prec && spx->assoc==LEFT ){ /* to break tie */ apx->type = SH_RESOLVED; }else{ assert( spx->prec==spy->prec && spx->assoc==NONE ); apy->type = CONFLICT; errcnt++; } }else if( apx->type==REDUCE && apy->type==REDUCE ){ spx = apx->x.rp->precsym; spy = apy->x.rp->precsym; if( spx==0 || spy==0 || spx->prec<0 || spy->prec<0 || spx->prec==spy->prec ){ apy->type = CONFLICT; errcnt++; }else if( spx->prec>spy->prec ){ apy->type = RD_RESOLVED; }else if( spx->precprec ){ apx->type = RD_RESOLVED; } }else{ assert( apx->type==SH_RESOLVED || apx->type==RD_RESOLVED || apx->type==CONFLICT || apy->type==SH_RESOLVED || apy->type==RD_RESOLVED || apy->type==CONFLICT ); /* The REDUCE/SHIFT case cannot happen because SHIFTs come before ** REDUCEs on the list. If we reach this point it must be because ** the parser conflict had already been resolved. */ } return errcnt; } /********************* From the file "configlist.c" *************************/ /* ** Routines to processing a configuration list and building a state ** in the LEMON parser generator. */ static struct config *freelist = 0; /* List of free configurations */ static struct config *current = 0; /* Top of list of configurations */ static struct config **currentend = 0; /* Last on list of configs */ static struct config *basis = 0; /* Top of list of basis configs */ static struct config **basisend = 0; /* End of list of basis configs */ /* Return a pointer to a new configuration */ PRIVATE struct config *newconfig(){ struct config *new; if( freelist==0 ){ int i; int amt = 3; freelist = (struct config *)malloc( sizeof(struct config)*amt ); if( freelist==0 ){ fprintf(stderr,"Unable to allocate memory for a new configuration."); exit(1); } for(i=0; inext; return new; } /* The configuration "old" is no longer used */ PRIVATE void deleteconfig(old) struct config *old; { old->next = freelist; freelist = old; } /* Initialized the configuration list builder */ void Configlist_init(){ current = 0; currentend = ¤t; basis = 0; basisend = &basis; Configtable_init(); return; } /* Initialized the configuration list builder */ void Configlist_reset(){ current = 0; currentend = ¤t; basis = 0; basisend = &basis; Configtable_clear(0); return; } /* Add another configuration to the configuration list */ struct config *Configlist_add(rp,dot) struct rule *rp; /* The rule */ int dot; /* Index into the RHS of the rule where the dot goes */ { struct config *cfp, model; assert( currentend!=0 ); model.rp = rp; model.dot = dot; cfp = Configtable_find(&model); if( cfp==0 ){ cfp = newconfig(); cfp->rp = rp; cfp->dot = dot; cfp->fws = SetNew(); cfp->stp = 0; cfp->fplp = cfp->bplp = 0; cfp->next = 0; cfp->bp = 0; *currentend = cfp; currentend = &cfp->next; Configtable_insert(cfp); } return cfp; } /* Add a basis configuration to the configuration list */ struct config *Configlist_addbasis(rp,dot) struct rule *rp; int dot; { struct config *cfp, model; assert( basisend!=0 ); assert( currentend!=0 ); model.rp = rp; model.dot = dot; cfp = Configtable_find(&model); if( cfp==0 ){ cfp = newconfig(); cfp->rp = rp; cfp->dot = dot; cfp->fws = SetNew(); cfp->stp = 0; cfp->fplp = cfp->bplp = 0; cfp->next = 0; cfp->bp = 0; *currentend = cfp; currentend = &cfp->next; *basisend = cfp; basisend = &cfp->bp; Configtable_insert(cfp); } return cfp; } /* Compute the closure of the configuration list */ void Configlist_closure(lemp) struct lemon *lemp; { struct config *cfp, *newcfp; struct rule *rp, *newrp; struct symbol *sp, *xsp; int i, dot; assert( currentend!=0 ); for(cfp=current; cfp; cfp=cfp->next){ rp = cfp->rp; dot = cfp->dot; if( dot>=rp->nrhs ) continue; sp = rp->rhs[dot]; if( sp->type==NONTERMINAL ){ if( sp->rule==0 && sp!=lemp->errsym ){ ErrorMsg(lemp->filename,rp->line,"Nonterminal \"%s\" has no rules.", sp->name); lemp->errorcnt++; } for(newrp=sp->rule; newrp; newrp=newrp->nextlhs){ newcfp = Configlist_add(newrp,0); for(i=dot+1; inrhs; i++){ xsp = rp->rhs[i]; if( xsp->type==TERMINAL ){ SetAdd(newcfp->fws,xsp->index); break; }else if( xsp->type==MULTITERMINAL ){ int k; for(k=0; knsubsym; k++){ SetAdd(newcfp->fws, xsp->subsym[k]->index); } break; }else{ SetUnion(newcfp->fws,xsp->firstset); if( xsp->lambda==B_FALSE ) break; } } if( i==rp->nrhs ) Plink_add(&cfp->fplp,newcfp); } } } return; } /* Sort the configuration list */ void Configlist_sort(){ current = (struct config *)msort((char *)current,(char **)&(current->next),Configcmp); currentend = 0; return; } /* Sort the basis configuration list */ void Configlist_sortbasis(){ basis = (struct config *)msort((char *)current,(char **)&(current->bp),Configcmp); basisend = 0; return; } /* Return a pointer to the head of the configuration list and ** reset the list */ struct config *Configlist_return(){ struct config *old; old = current; current = 0; currentend = 0; return old; } /* Return a pointer to the head of the configuration list and ** reset the list */ struct config *Configlist_basis(){ struct config *old; old = basis; basis = 0; basisend = 0; return old; } /* Free all elements of the given configuration list */ void Configlist_eat(cfp) struct config *cfp; { struct config *nextcfp; for(; cfp; cfp=nextcfp){ nextcfp = cfp->next; assert( cfp->fplp==0 ); assert( cfp->bplp==0 ); if( cfp->fws ) SetFree(cfp->fws); deleteconfig(cfp); } return; } /***************** From the file "error.c" *********************************/ /* ** Code for printing error message. */ /* Find a good place to break "msg" so that its length is at least "min" ** but no more than "max". Make the point as close to max as possible. */ static int findbreak(msg,min,max) char *msg; int min; int max; { int i,spot; char c; for(i=spot=min; i<=max; i++){ c = msg[i]; if( c=='\t' ) msg[i] = ' '; if( c=='\n' ){ msg[i] = ' '; spot = i; break; } if( c==0 ){ spot = i; break; } if( c=='-' && i0 ){ sprintf(prefix,"%.*s:%d: ",PREFIXLIMIT-10,filename,lineno); }else{ sprintf(prefix,"%.*s: ",PREFIXLIMIT-10,filename); } prefixsize = strlen(prefix); availablewidth = LINEWIDTH - prefixsize; /* Generate the error message */ vsprintf(errmsg,format,ap); va_end(ap); errmsgsize = strlen(errmsg); /* Remove trailing '\n's from the error message. */ while( errmsgsize>0 && errmsg[errmsgsize-1]=='\n' ){ errmsg[--errmsgsize] = 0; } /* Print the error message */ base = 0; while( errmsg[base]!=0 ){ end = restart = findbreak(&errmsg[base],0,availablewidth); restart += base; while( errmsg[restart]==' ' ) restart++; fprintf(stdout,"%s%.*s\n",prefix,end,&errmsg[base]); base = restart; } } /**************** From the file "main.c" ************************************/ /* ** Main program file for the LEMON parser generator. */ /* Report an out-of-memory condition and abort. This function ** is used mostly by the "MemoryCheck" macro in struct.h */ void memory_error(){ fprintf(stderr,"Out of memory. Aborting...\n"); exit(1); } static int nDefine = 0; /* Number of -D options on the command line */ static char **azDefine = 0; /* Name of the -D macros */ /* This routine is called with the argument to each -D command-line option. ** Add the macro defined to the azDefine array. */ static void handle_D_option(char *z){ char **paz; nDefine++; azDefine = realloc(azDefine, sizeof(azDefine[0])*nDefine); if( azDefine==0 ){ fprintf(stderr,"out of memory\n"); exit(1); } paz = &azDefine[nDefine-1]; *paz = malloc( strlen(z)+1 ); if( *paz==0 ){ fprintf(stderr,"out of memory\n"); exit(1); } strcpy(*paz, z); for(z=*paz; *z && *z!='='; z++){} *z = 0; } /* The main program. Parse the command line and do it... */ int main(argc,argv) int argc; char **argv; { static int version = 0; static int rpflag = 0; static int basisflag = 0; static int compress = 0; static int quiet = 0; static int statistics = 0; static int mhflag = 0; static struct s_options options[] = { {OPT_FLAG, "b", (char*)&basisflag, "Print only the basis in report."}, {OPT_FLAG, "c", (char*)&compress, "Don't compress the action table."}, {OPT_FSTR, "D", (char*)handle_D_option, "Define an %ifdef macro."}, {OPT_FLAG, "g", (char*)&rpflag, "Print grammar without actions."}, {OPT_FLAG, "m", (char*)&mhflag, "Output a makeheaders compatible file"}, {OPT_FLAG, "q", (char*)&quiet, "(Quiet) Don't print the report file."}, {OPT_FLAG, "s", (char*)&statistics, "Print parser stats to standard output."}, {OPT_FLAG, "x", (char*)&version, "Print the version number."}, {OPT_FLAG,0,0,0} }; int i; struct lemon lem; OptInit(argv,options,stderr); if( version ){ printf("Lemon version 1.0\n"); exit(0); } if( OptNArgs()!=1 ){ fprintf(stderr,"Exactly one filename argument is required.\n"); exit(1); } lem.errorcnt = 0; /* Initialize the machine */ Strsafe_init(); Symbol_init(); State_init(); lem.argv0 = argv[0]; lem.filename = OptArg(0); lem.basisflag = basisflag; lem.has_fallback = 0; lem.nconflict = 0; lem.name = lem.include = lem.arg = lem.tokentype = lem.start = 0; lem.vartype = 0; lem.stacksize = 0; lem.error = lem.overflow = lem.failure = lem.accept = lem.tokendest = lem.tokenprefix = lem.outname = lem.extracode = 0; lem.vardest = 0; lem.tablesize = 0; Symbol_new("$"); lem.errsym = Symbol_new("error"); /* Parse the input file */ Parse(&lem); if( lem.errorcnt ) exit(lem.errorcnt); if( lem.rule==0 ){ fprintf(stderr,"Empty grammar.\n"); exit(1); } /* Count and index the symbols of the grammar */ lem.nsymbol = Symbol_count(); Symbol_new("{default}"); lem.symbols = Symbol_arrayof(); for(i=0; i<=lem.nsymbol; i++) lem.symbols[i]->index = i; qsort(lem.symbols,lem.nsymbol+1,sizeof(struct symbol*), (int(*)())Symbolcmpp); for(i=0; i<=lem.nsymbol; i++) lem.symbols[i]->index = i; for(i=1; isupper(lem.symbols[i]->name[0]); i++); lem.nterminal = i; /* Generate a reprint of the grammar, if requested on the command line */ if( rpflag ){ Reprint(&lem); }else{ /* Initialize the size for all follow and first sets */ SetSize(lem.nterminal); /* Find the precedence for every production rule (that has one) */ FindRulePrecedences(&lem); /* Compute the lambda-nonterminals and the first-sets for every ** nonterminal */ FindFirstSets(&lem); /* Compute all LR(0) states. Also record follow-set propagation ** links so that the follow-set can be computed later */ lem.nstate = 0; FindStates(&lem); lem.sorted = State_arrayof(); /* Tie up loose ends on the propagation links */ FindLinks(&lem); /* Compute the follow set of every reducible configuration */ FindFollowSets(&lem); /* Compute the action tables */ FindActions(&lem); /* Compress the action tables */ if( compress==0 ) CompressTables(&lem); /* Reorder and renumber the states so that states with fewer choices ** occur at the end. */ ResortStates(&lem); /* Generate a report of the parser generated. (the "y.output" file) */ if( !quiet ) ReportOutput(&lem); /* Generate the source code for the parser */ ReportTable(&lem, mhflag); /* Produce a header file for use by the scanner. (This step is ** omitted if the "-m" option is used because makeheaders will ** generate the file for us.) */ if( !mhflag ) ReportHeader(&lem); } if( statistics ){ printf("Parser statistics: %d terminals, %d nonterminals, %d rules\n", lem.nterminal, lem.nsymbol - lem.nterminal, lem.nrule); printf(" %d states, %d parser table entries, %d conflicts\n", lem.nstate, lem.tablesize, lem.nconflict); } if( lem.nconflict ){ fprintf(stderr,"%d parsing conflicts.\n",lem.nconflict); } exit(lem.errorcnt + lem.nconflict); return (lem.errorcnt + lem.nconflict); } /******************** From the file "msort.c" *******************************/ /* ** A generic merge-sort program. ** ** USAGE: ** Let "ptr" be a pointer to some structure which is at the head of ** a null-terminated list. Then to sort the list call: ** ** ptr = msort(ptr,&(ptr->next),cmpfnc); ** ** In the above, "cmpfnc" is a pointer to a function which compares ** two instances of the structure and returns an integer, as in ** strcmp. The second argument is a pointer to the pointer to the ** second element of the linked list. This address is used to compute ** the offset to the "next" field within the structure. The offset to ** the "next" field must be constant for all structures in the list. ** ** The function returns a new pointer which is the head of the list ** after sorting. ** ** ALGORITHM: ** Merge-sort. */ /* ** Return a pointer to the next structure in the linked list. */ #define NEXT(A) (*(char**)(((unsigned long)A)+offset)) /* ** Inputs: ** a: A sorted, null-terminated linked list. (May be null). ** b: A sorted, null-terminated linked list. (May be null). ** cmp: A pointer to the comparison function. ** offset: Offset in the structure to the "next" field. ** ** Return Value: ** A pointer to the head of a sorted list containing the elements ** of both a and b. ** ** Side effects: ** The "next" pointers for elements in the lists a and b are ** changed. */ static char *merge(a,b,cmp,offset) char *a; char *b; int (*cmp)(); int offset; { char *ptr, *head; if( a==0 ){ head = b; }else if( b==0 ){ head = a; }else{ if( (*cmp)(a,b)<0 ){ ptr = a; a = NEXT(a); }else{ ptr = b; b = NEXT(b); } head = ptr; while( a && b ){ if( (*cmp)(a,b)<0 ){ NEXT(ptr) = a; ptr = a; a = NEXT(a); }else{ NEXT(ptr) = b; ptr = b; b = NEXT(b); } } if( a ) NEXT(ptr) = a; else NEXT(ptr) = b; } return head; } /* ** Inputs: ** list: Pointer to a singly-linked list of structures. ** next: Pointer to pointer to the second element of the list. ** cmp: A comparison function. ** ** Return Value: ** A pointer to the head of a sorted list containing the elements ** orginally in list. ** ** Side effects: ** The "next" pointers for elements in list are changed. */ #define LISTSIZE 30 char *msort(list,next,cmp) char *list; char **next; int (*cmp)(); { unsigned long offset; char *ep; char *set[LISTSIZE]; int i; offset = (unsigned long)next - (unsigned long)list; for(i=0; istate = WAITING_FOR_DECL_KEYWORD; }else if( islower(x[0]) ){ psp->lhs = Symbol_new(x); psp->nrhs = 0; psp->lhsalias = 0; psp->state = WAITING_FOR_ARROW; }else if( x[0]=='{' ){ if( psp->prevrule==0 ){ ErrorMsg(psp->filename,psp->tokenlineno, "There is not prior rule opon which to attach the code \ fragment which begins on this line."); psp->errorcnt++; }else if( psp->prevrule->code!=0 ){ ErrorMsg(psp->filename,psp->tokenlineno, "Code fragment beginning on this line is not the first \ to follow the previous rule."); psp->errorcnt++; }else{ psp->prevrule->line = psp->tokenlineno; psp->prevrule->code = &x[1]; } }else if( x[0]=='[' ){ psp->state = PRECEDENCE_MARK_1; }else{ ErrorMsg(psp->filename,psp->tokenlineno, "Token \"%s\" should be either \"%%\" or a nonterminal name.", x); psp->errorcnt++; } break; case PRECEDENCE_MARK_1: if( !isupper(x[0]) ){ ErrorMsg(psp->filename,psp->tokenlineno, "The precedence symbol must be a terminal."); psp->errorcnt++; }else if( psp->prevrule==0 ){ ErrorMsg(psp->filename,psp->tokenlineno, "There is no prior rule to assign precedence \"[%s]\".",x); psp->errorcnt++; }else if( psp->prevrule->precsym!=0 ){ ErrorMsg(psp->filename,psp->tokenlineno, "Precedence mark on this line is not the first \ to follow the previous rule."); psp->errorcnt++; }else{ psp->prevrule->precsym = Symbol_new(x); } psp->state = PRECEDENCE_MARK_2; break; case PRECEDENCE_MARK_2: if( x[0]!=']' ){ ErrorMsg(psp->filename,psp->tokenlineno, "Missing \"]\" on precedence mark."); psp->errorcnt++; } psp->state = WAITING_FOR_DECL_OR_RULE; break; case WAITING_FOR_ARROW: if( x[0]==':' && x[1]==':' && x[2]=='=' ){ psp->state = IN_RHS; }else if( x[0]=='(' ){ psp->state = LHS_ALIAS_1; }else{ ErrorMsg(psp->filename,psp->tokenlineno, "Expected to see a \":\" following the LHS symbol \"%s\".", psp->lhs->name); psp->errorcnt++; psp->state = RESYNC_AFTER_RULE_ERROR; } break; case LHS_ALIAS_1: if( isalpha(x[0]) ){ psp->lhsalias = x; psp->state = LHS_ALIAS_2; }else{ ErrorMsg(psp->filename,psp->tokenlineno, "\"%s\" is not a valid alias for the LHS \"%s\"\n", x,psp->lhs->name); psp->errorcnt++; psp->state = RESYNC_AFTER_RULE_ERROR; } break; case LHS_ALIAS_2: if( x[0]==')' ){ psp->state = LHS_ALIAS_3; }else{ ErrorMsg(psp->filename,psp->tokenlineno, "Missing \")\" following LHS alias name \"%s\".",psp->lhsalias); psp->errorcnt++; psp->state = RESYNC_AFTER_RULE_ERROR; } break; case LHS_ALIAS_3: if( x[0]==':' && x[1]==':' && x[2]=='=' ){ psp->state = IN_RHS; }else{ ErrorMsg(psp->filename,psp->tokenlineno, "Missing \"->\" following: \"%s(%s)\".", psp->lhs->name,psp->lhsalias); psp->errorcnt++; psp->state = RESYNC_AFTER_RULE_ERROR; } break; case IN_RHS: if( x[0]=='.' ){ struct rule *rp; rp = (struct rule *)malloc( sizeof(struct rule) + sizeof(struct symbol*)*psp->nrhs + sizeof(char*)*psp->nrhs ); if( rp==0 ){ ErrorMsg(psp->filename,psp->tokenlineno, "Can't allocate enough memory for this rule."); psp->errorcnt++; psp->prevrule = 0; }else{ int i; rp->ruleline = psp->tokenlineno; rp->rhs = (struct symbol**)&rp[1]; rp->rhsalias = (char**)&(rp->rhs[psp->nrhs]); for(i=0; inrhs; i++){ rp->rhs[i] = psp->rhs[i]; rp->rhsalias[i] = psp->alias[i]; } rp->lhs = psp->lhs; rp->lhsalias = psp->lhsalias; rp->nrhs = psp->nrhs; rp->code = 0; rp->precsym = 0; rp->index = psp->gp->nrule++; rp->nextlhs = rp->lhs->rule; rp->lhs->rule = rp; rp->next = 0; if( psp->firstrule==0 ){ psp->firstrule = psp->lastrule = rp; }else{ psp->lastrule->next = rp; psp->lastrule = rp; } psp->prevrule = rp; } psp->state = WAITING_FOR_DECL_OR_RULE; }else if( isalpha(x[0]) ){ if( psp->nrhs>=MAXRHS ){ ErrorMsg(psp->filename,psp->tokenlineno, "Too many symbols on RHS or rule beginning at \"%s\".", x); psp->errorcnt++; psp->state = RESYNC_AFTER_RULE_ERROR; }else{ psp->rhs[psp->nrhs] = Symbol_new(x); psp->alias[psp->nrhs] = 0; psp->nrhs++; } }else if( (x[0]=='|' || x[0]=='/') && psp->nrhs>0 ){ struct symbol *msp = psp->rhs[psp->nrhs-1]; if( msp->type!=MULTITERMINAL ){ struct symbol *origsp = msp; msp = malloc(sizeof(*msp)); memset(msp, 0, sizeof(*msp)); msp->type = MULTITERMINAL; msp->nsubsym = 1; msp->subsym = malloc(sizeof(struct symbol*)); msp->subsym[0] = origsp; msp->name = origsp->name; psp->rhs[psp->nrhs-1] = msp; } msp->nsubsym++; msp->subsym = realloc(msp->subsym, sizeof(struct symbol*)*msp->nsubsym); msp->subsym[msp->nsubsym-1] = Symbol_new(&x[1]); if( islower(x[1]) || islower(msp->subsym[0]->name[0]) ){ ErrorMsg(psp->filename,psp->tokenlineno, "Cannot form a compound containing a non-terminal"); psp->errorcnt++; } }else if( x[0]=='(' && psp->nrhs>0 ){ psp->state = RHS_ALIAS_1; }else{ ErrorMsg(psp->filename,psp->tokenlineno, "Illegal character on RHS of rule: \"%s\".",x); psp->errorcnt++; psp->state = RESYNC_AFTER_RULE_ERROR; } break; case RHS_ALIAS_1: if( isalpha(x[0]) ){ psp->alias[psp->nrhs-1] = x; psp->state = RHS_ALIAS_2; }else{ ErrorMsg(psp->filename,psp->tokenlineno, "\"%s\" is not a valid alias for the RHS symbol \"%s\"\n", x,psp->rhs[psp->nrhs-1]->name); psp->errorcnt++; psp->state = RESYNC_AFTER_RULE_ERROR; } break; case RHS_ALIAS_2: if( x[0]==')' ){ psp->state = IN_RHS; }else{ ErrorMsg(psp->filename,psp->tokenlineno, "Missing \")\" following LHS alias name \"%s\".",psp->lhsalias); psp->errorcnt++; psp->state = RESYNC_AFTER_RULE_ERROR; } break; case WAITING_FOR_DECL_KEYWORD: if( isalpha(x[0]) ){ psp->declkeyword = x; psp->declargslot = 0; psp->decllnslot = 0; psp->state = WAITING_FOR_DECL_ARG; if( strcmp(x,"name")==0 ){ psp->declargslot = &(psp->gp->name); }else if( strcmp(x,"include")==0 ){ psp->declargslot = &(psp->gp->include); psp->decllnslot = &psp->gp->includeln; }else if( strcmp(x,"code")==0 ){ psp->declargslot = &(psp->gp->extracode); psp->decllnslot = &psp->gp->extracodeln; }else if( strcmp(x,"token_destructor")==0 ){ psp->declargslot = &psp->gp->tokendest; psp->decllnslot = &psp->gp->tokendestln; }else if( strcmp(x,"default_destructor")==0 ){ psp->declargslot = &psp->gp->vardest; psp->decllnslot = &psp->gp->vardestln; }else if( strcmp(x,"token_prefix")==0 ){ psp->declargslot = &psp->gp->tokenprefix; }else if( strcmp(x,"syntax_error")==0 ){ psp->declargslot = &(psp->gp->error); psp->decllnslot = &psp->gp->errorln; }else if( strcmp(x,"parse_accept")==0 ){ psp->declargslot = &(psp->gp->accept); psp->decllnslot = &psp->gp->acceptln; }else if( strcmp(x,"parse_failure")==0 ){ psp->declargslot = &(psp->gp->failure); psp->decllnslot = &psp->gp->failureln; }else if( strcmp(x,"stack_overflow")==0 ){ psp->declargslot = &(psp->gp->overflow); psp->decllnslot = &psp->gp->overflowln; }else if( strcmp(x,"extra_argument")==0 ){ psp->declargslot = &(psp->gp->arg); }else if( strcmp(x,"token_type")==0 ){ psp->declargslot = &(psp->gp->tokentype); }else if( strcmp(x,"default_type")==0 ){ psp->declargslot = &(psp->gp->vartype); }else if( strcmp(x,"stack_size")==0 ){ psp->declargslot = &(psp->gp->stacksize); }else if( strcmp(x,"start_symbol")==0 ){ psp->declargslot = &(psp->gp->start); }else if( strcmp(x,"left")==0 ){ psp->preccounter++; psp->declassoc = LEFT; psp->state = WAITING_FOR_PRECEDENCE_SYMBOL; }else if( strcmp(x,"right")==0 ){ psp->preccounter++; psp->declassoc = RIGHT; psp->state = WAITING_FOR_PRECEDENCE_SYMBOL; }else if( strcmp(x,"nonassoc")==0 ){ psp->preccounter++; psp->declassoc = NONE; psp->state = WAITING_FOR_PRECEDENCE_SYMBOL; }else if( strcmp(x,"destructor")==0 ){ psp->state = WAITING_FOR_DESTRUCTOR_SYMBOL; }else if( strcmp(x,"type")==0 ){ psp->state = WAITING_FOR_DATATYPE_SYMBOL; }else if( strcmp(x,"fallback")==0 ){ psp->fallback = 0; psp->state = WAITING_FOR_FALLBACK_ID; }else{ ErrorMsg(psp->filename,psp->tokenlineno, "Unknown declaration keyword: \"%%%s\".",x); psp->errorcnt++; psp->state = RESYNC_AFTER_DECL_ERROR; } }else{ ErrorMsg(psp->filename,psp->tokenlineno, "Illegal declaration keyword: \"%s\".",x); psp->errorcnt++; psp->state = RESYNC_AFTER_DECL_ERROR; } break; case WAITING_FOR_DESTRUCTOR_SYMBOL: if( !isalpha(x[0]) ){ ErrorMsg(psp->filename,psp->tokenlineno, "Symbol name missing after %destructor keyword"); psp->errorcnt++; psp->state = RESYNC_AFTER_DECL_ERROR; }else{ struct symbol *sp = Symbol_new(x); psp->declargslot = &sp->destructor; psp->decllnslot = &sp->destructorln; psp->state = WAITING_FOR_DECL_ARG; } break; case WAITING_FOR_DATATYPE_SYMBOL: if( !isalpha(x[0]) ){ ErrorMsg(psp->filename,psp->tokenlineno, "Symbol name missing after %destructor keyword"); psp->errorcnt++; psp->state = RESYNC_AFTER_DECL_ERROR; }else{ struct symbol *sp = Symbol_new(x); psp->declargslot = &sp->datatype; psp->decllnslot = 0; psp->state = WAITING_FOR_DECL_ARG; } break; case WAITING_FOR_PRECEDENCE_SYMBOL: if( x[0]=='.' ){ psp->state = WAITING_FOR_DECL_OR_RULE; }else if( isupper(x[0]) ){ struct symbol *sp; sp = Symbol_new(x); if( sp->prec>=0 ){ ErrorMsg(psp->filename,psp->tokenlineno, "Symbol \"%s\" has already be given a precedence.",x); psp->errorcnt++; }else{ sp->prec = psp->preccounter; sp->assoc = psp->declassoc; } }else{ ErrorMsg(psp->filename,psp->tokenlineno, "Can't assign a precedence to \"%s\".",x); psp->errorcnt++; } break; case WAITING_FOR_DECL_ARG: if( (x[0]=='{' || x[0]=='\"' || isalnum(x[0])) ){ if( *(psp->declargslot)!=0 ){ ErrorMsg(psp->filename,psp->tokenlineno, "The argument \"%s\" to declaration \"%%%s\" is not the first.", x[0]=='\"' ? &x[1] : x,psp->declkeyword); psp->errorcnt++; psp->state = RESYNC_AFTER_DECL_ERROR; }else{ *(psp->declargslot) = (x[0]=='\"' || x[0]=='{') ? &x[1] : x; if( psp->decllnslot ) *psp->decllnslot = psp->tokenlineno; psp->state = WAITING_FOR_DECL_OR_RULE; } }else{ ErrorMsg(psp->filename,psp->tokenlineno, "Illegal argument to %%%s: %s",psp->declkeyword,x); psp->errorcnt++; psp->state = RESYNC_AFTER_DECL_ERROR; } break; case WAITING_FOR_FALLBACK_ID: if( x[0]=='.' ){ psp->state = WAITING_FOR_DECL_OR_RULE; }else if( !isupper(x[0]) ){ ErrorMsg(psp->filename, psp->tokenlineno, "%%fallback argument \"%s\" should be a token", x); psp->errorcnt++; }else{ struct symbol *sp = Symbol_new(x); if( psp->fallback==0 ){ psp->fallback = sp; }else if( sp->fallback ){ ErrorMsg(psp->filename, psp->tokenlineno, "More than one fallback assigned to token %s", x); psp->errorcnt++; }else{ sp->fallback = psp->fallback; psp->gp->has_fallback = 1; } } break; case RESYNC_AFTER_RULE_ERROR: /* if( x[0]=='.' ) psp->state = WAITING_FOR_DECL_OR_RULE; ** break; */ case RESYNC_AFTER_DECL_ERROR: if( x[0]=='.' ) psp->state = WAITING_FOR_DECL_OR_RULE; if( x[0]=='%' ) psp->state = WAITING_FOR_DECL_KEYWORD; break; } } /* Run the proprocessor over the input file text. The global variables ** azDefine[0] through azDefine[nDefine-1] contains the names of all defined ** macros. This routine looks for "%ifdef" and "%ifndef" and "%endif" and ** comments them out. Text in between is also commented out as appropriate. */ static void preprocess_input(char *z){ int i, j, k, n; int exclude = 0; int start; int lineno = 1; int start_lineno; for(i=0; z[i]; i++){ if( z[i]=='\n' ) lineno++; if( z[i]!='%' || (i>0 && z[i-1]!='\n') ) continue; if( strncmp(&z[i],"%endif",6)==0 && isspace(z[i+6]) ){ if( exclude ){ exclude--; if( exclude==0 ){ for(j=start; jfilename; ps.errorcnt = 0; ps.state = INITIALIZE; /* Begin by reading the input file */ fp = fopen(ps.filename,"rb"); if( fp==0 ){ ErrorMsg(ps.filename,0,"Can't open this file for reading."); gp->errorcnt++; return; } fseek(fp,0,2); filesize = ftell(fp); rewind(fp); filebuf = (char *)malloc( filesize+1 ); if( filebuf==0 ){ ErrorMsg(ps.filename,0,"Can't allocate %d of memory to hold this file.", filesize+1); gp->errorcnt++; return; } if( fread(filebuf,1,filesize,fp)!=filesize ){ ErrorMsg(ps.filename,0,"Can't read in all %d bytes of this file.", filesize); free(filebuf); gp->errorcnt++; return; } fclose(fp); filebuf[filesize] = 0; /* Make an initial pass through the file to handle %ifdef and %ifndef */ preprocess_input(filebuf); /* Now scan the text of the input file */ lineno = 1; for(cp=filebuf; (c= *cp)!=0; ){ if( c=='\n' ) lineno++; /* Keep track of the line number */ if( isspace(c) ){ cp++; continue; } /* Skip all white space */ if( c=='/' && cp[1]=='/' ){ /* Skip C++ style comments */ cp+=2; while( (c= *cp)!=0 && c!='\n' ) cp++; continue; } if( c=='/' && cp[1]=='*' ){ /* Skip C style comments */ cp+=2; while( (c= *cp)!=0 && (c!='/' || cp[-1]!='*') ){ if( c=='\n' ) lineno++; cp++; } if( c ) cp++; continue; } ps.tokenstart = cp; /* Mark the beginning of the token */ ps.tokenlineno = lineno; /* Linenumber on which token begins */ if( c=='\"' ){ /* String literals */ cp++; while( (c= *cp)!=0 && c!='\"' ){ if( c=='\n' ) lineno++; cp++; } if( c==0 ){ ErrorMsg(ps.filename,startline, "String starting on this line is not terminated before the end of the file."); ps.errorcnt++; nextcp = cp; }else{ nextcp = cp+1; } }else if( c=='{' ){ /* A block of C code */ int level; cp++; for(level=1; (c= *cp)!=0 && (level>1 || c!='}'); cp++){ if( c=='\n' ) lineno++; else if( c=='{' ) level++; else if( c=='}' ) level--; else if( c=='/' && cp[1]=='*' ){ /* Skip comments */ int prevc; cp = &cp[2]; prevc = 0; while( (c= *cp)!=0 && (c!='/' || prevc!='*') ){ if( c=='\n' ) lineno++; prevc = c; cp++; } }else if( c=='/' && cp[1]=='/' ){ /* Skip C++ style comments too */ cp = &cp[2]; while( (c= *cp)!=0 && c!='\n' ) cp++; if( c ) lineno++; }else if( c=='\'' || c=='\"' ){ /* String a character literals */ int startchar, prevc; startchar = c; prevc = 0; for(cp++; (c= *cp)!=0 && (c!=startchar || prevc=='\\'); cp++){ if( c=='\n' ) lineno++; if( prevc=='\\' ) prevc = 0; else prevc = c; } } } if( c==0 ){ ErrorMsg(ps.filename,ps.tokenlineno, "C code starting on this line is not terminated before the end of the file."); ps.errorcnt++; nextcp = cp; }else{ nextcp = cp+1; } }else if( isalnum(c) ){ /* Identifiers */ while( (c= *cp)!=0 && (isalnum(c) || c=='_') ) cp++; nextcp = cp; }else if( c==':' && cp[1]==':' && cp[2]=='=' ){ /* The operator "::=" */ cp += 3; nextcp = cp; }else if( (c=='/' || c=='|') && isalpha(cp[1]) ){ cp += 2; while( (c = *cp)!=0 && (isalnum(c) || c=='_') ) cp++; nextcp = cp; }else{ /* All other (one character) operators */ cp++; nextcp = cp; } c = *cp; *cp = 0; /* Null terminate the token */ parseonetoken(&ps); /* Parse the token */ *cp = c; /* Restore the buffer */ cp = nextcp; } free(filebuf); /* Release the buffer after parsing */ gp->rule = ps.firstrule; gp->errorcnt = ps.errorcnt; } /*************************** From the file "plink.c" *********************/ /* ** Routines processing configuration follow-set propagation links ** in the LEMON parser generator. */ static struct plink *plink_freelist = 0; /* Allocate a new plink */ struct plink *Plink_new(){ struct plink *new; if( plink_freelist==0 ){ int i; int amt = 100; plink_freelist = (struct plink *)malloc( sizeof(struct plink)*amt ); if( plink_freelist==0 ){ fprintf(stderr, "Unable to allocate memory for a new follow-set propagation link.\n"); exit(1); } for(i=0; inext; return new; } /* Add a plink to a plink list */ void Plink_add(plpp,cfp) struct plink **plpp; struct config *cfp; { struct plink *new; new = Plink_new(); new->next = *plpp; *plpp = new; new->cfp = cfp; } /* Transfer every plink on the list "from" to the list "to" */ void Plink_copy(to,from) struct plink **to; struct plink *from; { struct plink *nextpl; while( from ){ nextpl = from->next; from->next = *to; *to = from; from = nextpl; } } /* Delete every plink on the list */ void Plink_delete(plp) struct plink *plp; { struct plink *nextpl; while( plp ){ nextpl = plp->next; plp->next = plink_freelist; plink_freelist = plp; plp = nextpl; } } /*********************** From the file "report.c" **************************/ /* ** Procedures for generating reports and tables in the LEMON parser generator. */ /* Generate a filename with the given suffix. Space to hold the ** name comes from malloc() and must be freed by the calling ** function. */ PRIVATE char *file_makename(lemp,suffix) struct lemon *lemp; char *suffix; { char *name; char *cp; name = malloc( strlen(lemp->filename) + strlen(suffix) + 5 ); if( name==0 ){ fprintf(stderr,"Can't allocate space for a filename.\n"); exit(1); } strcpy(name,lemp->filename); cp = strrchr(name,'.'); if( cp ) *cp = 0; strcat(name,suffix); return name; } /* Open a file with a name based on the name of the input file, ** but with a different (specified) suffix, and return a pointer ** to the stream */ PRIVATE FILE *file_open(lemp,suffix,mode) struct lemon *lemp; char *suffix; char *mode; { FILE *fp; if( lemp->outname ) free(lemp->outname); lemp->outname = file_makename(lemp, suffix); fp = fopen(lemp->outname,mode); if( fp==0 && *mode=='w' ){ fprintf(stderr,"Can't open file \"%s\".\n",lemp->outname); lemp->errorcnt++; return 0; } return fp; } /* Duplicate the input file without comments and without actions ** on rules */ void Reprint(lemp) struct lemon *lemp; { struct rule *rp; struct symbol *sp; int i, j, maxlen, len, ncolumns, skip; printf("// Reprint of input file \"%s\".\n// Symbols:\n",lemp->filename); maxlen = 10; for(i=0; insymbol; i++){ sp = lemp->symbols[i]; len = strlen(sp->name); if( len>maxlen ) maxlen = len; } ncolumns = 76/(maxlen+5); if( ncolumns<1 ) ncolumns = 1; skip = (lemp->nsymbol + ncolumns - 1)/ncolumns; for(i=0; insymbol; j+=skip){ sp = lemp->symbols[j]; assert( sp->index==j ); printf(" %3d %-*.*s",j,maxlen,maxlen,sp->name); } printf("\n"); } for(rp=lemp->rule; rp; rp=rp->next){ printf("%s",rp->lhs->name); /* if( rp->lhsalias ) printf("(%s)",rp->lhsalias); */ printf(" ::="); for(i=0; inrhs; i++){ sp = rp->rhs[i]; printf(" %s", sp->name); if( sp->type==MULTITERMINAL ){ for(j=1; jnsubsym; j++){ printf("|%s", sp->subsym[j]->name); } } /* if( rp->rhsalias[i] ) printf("(%s)",rp->rhsalias[i]); */ } printf("."); if( rp->precsym ) printf(" [%s]",rp->precsym->name); /* if( rp->code ) printf("\n %s",rp->code); */ printf("\n"); } } void ConfigPrint(fp,cfp) FILE *fp; struct config *cfp; { struct rule *rp; struct symbol *sp; int i, j; rp = cfp->rp; fprintf(fp,"%s ::=",rp->lhs->name); for(i=0; i<=rp->nrhs; i++){ if( i==cfp->dot ) fprintf(fp," *"); if( i==rp->nrhs ) break; sp = rp->rhs[i]; fprintf(fp," %s", sp->name); if( sp->type==MULTITERMINAL ){ for(j=1; jnsubsym; j++){ fprintf(fp,"|%s",sp->subsym[j]->name); } } } } /* #define TEST */ #if 0 /* Print a set */ PRIVATE void SetPrint(out,set,lemp) FILE *out; char *set; struct lemon *lemp; { int i; char *spacer; spacer = ""; fprintf(out,"%12s[",""); for(i=0; interminal; i++){ if( SetFind(set,i) ){ fprintf(out,"%s%s",spacer,lemp->symbols[i]->name); spacer = " "; } } fprintf(out,"]\n"); } /* Print a plink chain */ PRIVATE void PlinkPrint(out,plp,tag) FILE *out; struct plink *plp; char *tag; { while( plp ){ fprintf(out,"%12s%s (state %2d) ","",tag,plp->cfp->stp->statenum); ConfigPrint(out,plp->cfp); fprintf(out,"\n"); plp = plp->next; } } #endif /* Print an action to the given file descriptor. Return FALSE if ** nothing was actually printed. */ int PrintAction(struct action *ap, FILE *fp, int indent){ int result = 1; switch( ap->type ){ case SHIFT: fprintf(fp,"%*s shift %d",indent,ap->sp->name,ap->x.stp->statenum); break; case REDUCE: fprintf(fp,"%*s reduce %d",indent,ap->sp->name,ap->x.rp->index); break; case ACCEPT: fprintf(fp,"%*s accept",indent,ap->sp->name); break; case ERROR: fprintf(fp,"%*s error",indent,ap->sp->name); break; case CONFLICT: fprintf(fp,"%*s reduce %-3d ** Parsing conflict **", indent,ap->sp->name,ap->x.rp->index); break; case SH_RESOLVED: case RD_RESOLVED: case NOT_USED: result = 0; break; } return result; } /* Generate the "y.output" log file */ void ReportOutput(lemp) struct lemon *lemp; { int i; struct state *stp; struct config *cfp; struct action *ap; FILE *fp; fp = file_open(lemp,".out","wb"); if( fp==0 ) return; fprintf(fp," \b"); for(i=0; instate; i++){ stp = lemp->sorted[i]; fprintf(fp,"State %d:\n",stp->statenum); if( lemp->basisflag ) cfp=stp->bp; else cfp=stp->cfp; while( cfp ){ char buf[20]; if( cfp->dot==cfp->rp->nrhs ){ sprintf(buf,"(%d)",cfp->rp->index); fprintf(fp," %5s ",buf); }else{ fprintf(fp," "); } ConfigPrint(fp,cfp); fprintf(fp,"\n"); #if 0 SetPrint(fp,cfp->fws,lemp); PlinkPrint(fp,cfp->fplp,"To "); PlinkPrint(fp,cfp->bplp,"From"); #endif if( lemp->basisflag ) cfp=cfp->bp; else cfp=cfp->next; } fprintf(fp,"\n"); for(ap=stp->ap; ap; ap=ap->next){ if( PrintAction(ap,fp,30) ) fprintf(fp,"\n"); } fprintf(fp,"\n"); } fclose(fp); return; } /* Search for the file "name" which is in the same directory as ** the exacutable */ PRIVATE char *pathsearch(argv0,name,modemask) char *argv0; char *name; int modemask; { char *pathlist; char *path,*cp; char c; extern int access(); #ifdef __WIN32__ cp = strrchr(argv0,'\\'); #else cp = strrchr(argv0,'/'); #endif if( cp ){ c = *cp; *cp = 0; path = (char *)malloc( strlen(argv0) + strlen(name) + 2 ); if( path ) sprintf(path,"%s/%s",argv0,name); *cp = c; }else{ extern char *getenv(); pathlist = getenv("PATH"); if( pathlist==0 ) pathlist = ".:/bin:/usr/bin"; path = (char *)malloc( strlen(pathlist)+strlen(name)+2 ); if( path!=0 ){ while( *pathlist ){ cp = strchr(pathlist,':'); if( cp==0 ) cp = &pathlist[strlen(pathlist)]; c = *cp; *cp = 0; sprintf(path,"%s/%s",pathlist,name); *cp = c; if( c==0 ) pathlist = ""; else pathlist = &cp[1]; if( access(path,modemask)==0 ) break; } } } return path; } /* Given an action, compute the integer value for that action ** which is to be put in the action table of the generated machine. ** Return negative if no action should be generated. */ PRIVATE int compute_action(lemp,ap) struct lemon *lemp; struct action *ap; { int act; switch( ap->type ){ case SHIFT: act = ap->x.stp->statenum; break; case REDUCE: act = ap->x.rp->index + lemp->nstate; break; case ERROR: act = lemp->nstate + lemp->nrule; break; case ACCEPT: act = lemp->nstate + lemp->nrule + 1; break; default: act = -1; break; } return act; } #define LINESIZE 1000 /* The next cluster of routines are for reading the template file ** and writing the results to the generated parser */ /* The first function transfers data from "in" to "out" until ** a line is seen which begins with "%%". The line number is ** tracked. ** ** if name!=0, then any word that begin with "Parse" is changed to ** begin with *name instead. */ PRIVATE void tplt_xfer(name,in,out,lineno) char *name; FILE *in; FILE *out; int *lineno; { int i, iStart; char line[LINESIZE]; while( fgets(line,LINESIZE,in) && (line[0]!='%' || line[1]!='%') ){ (*lineno)++; iStart = 0; if( name ){ for(i=0; line[i]; i++){ if( line[i]=='P' && strncmp(&line[i],"Parse",5)==0 && (i==0 || !isalpha(line[i-1])) ){ if( i>iStart ) fprintf(out,"%.*s",i-iStart,&line[iStart]); fprintf(out,"%s",name); i += 4; iStart = i+1; } } } fprintf(out,"%s",&line[iStart]); } } /* The next function finds the template file and opens it, returning ** a pointer to the opened file. */ PRIVATE FILE *tplt_open(lemp) struct lemon *lemp; { static char templatename[] = "lempar.c"; char buf[1000]; FILE *in; char *tpltname; char *cp; cp = strrchr(lemp->filename,'.'); if( cp ){ sprintf(buf,"%.*s.lt",(int)(cp-lemp->filename),lemp->filename); }else{ sprintf(buf,"%s.lt",lemp->filename); } if( access(buf,004)==0 ){ tpltname = buf; }else if( access(templatename,004)==0 ){ tpltname = templatename; }else{ tpltname = pathsearch(lemp->argv0,templatename,0); } if( tpltname==0 ){ fprintf(stderr,"Can't find the parser driver template file \"%s\".\n", templatename); lemp->errorcnt++; return 0; } in = fopen(tpltname,"rb"); if( in==0 ){ fprintf(stderr,"Can't open the template file \"%s\".\n",templatename); lemp->errorcnt++; return 0; } return in; } /* Print a #line directive line to the output file. */ PRIVATE void tplt_linedir(out,lineno,filename) FILE *out; int lineno; char *filename; { fprintf(out,"#line %d \"",lineno); while( *filename ){ if( *filename == '\\' ) putc('\\',out); putc(*filename,out); filename++; } fprintf(out,"\"\n"); } /* Print a string to the file and keep the linenumber up to date */ PRIVATE void tplt_print(out,lemp,str,strln,lineno) FILE *out; struct lemon *lemp; char *str; int strln; int *lineno; { if( str==0 ) return; tplt_linedir(out,strln,lemp->filename); (*lineno)++; while( *str ){ if( *str=='\n' ) (*lineno)++; putc(*str,out); str++; } if( str[-1]!='\n' ){ putc('\n',out); (*lineno)++; } tplt_linedir(out,*lineno+2,lemp->outname); (*lineno)+=2; return; } /* ** The following routine emits code for the destructor for the ** symbol sp */ void emit_destructor_code(out,sp,lemp,lineno) FILE *out; struct symbol *sp; struct lemon *lemp; int *lineno; { char *cp = 0; int linecnt = 0; if( sp->type==TERMINAL ){ cp = lemp->tokendest; if( cp==0 ) return; tplt_linedir(out,lemp->tokendestln,lemp->filename); fprintf(out,"{"); }else if( sp->destructor ){ cp = sp->destructor; tplt_linedir(out,sp->destructorln,lemp->filename); fprintf(out,"{"); }else if( lemp->vardest ){ cp = lemp->vardest; if( cp==0 ) return; tplt_linedir(out,lemp->vardestln,lemp->filename); fprintf(out,"{"); }else{ assert( 0 ); /* Cannot happen */ } for(; *cp; cp++){ if( *cp=='$' && cp[1]=='$' ){ fprintf(out,"(yypminor->yy%d)",sp->dtnum); cp++; continue; } if( *cp=='\n' ) linecnt++; fputc(*cp,out); } (*lineno) += 3 + linecnt; fprintf(out,"}\n"); tplt_linedir(out,*lineno,lemp->outname); return; } /* ** Return TRUE (non-zero) if the given symbol has a destructor. */ int has_destructor(sp, lemp) struct symbol *sp; struct lemon *lemp; { int ret; if( sp->type==TERMINAL ){ ret = lemp->tokendest!=0; }else{ ret = lemp->vardest!=0 || sp->destructor!=0; } return ret; } /* ** Append text to a dynamically allocated string. If zText is 0 then ** reset the string to be empty again. Always return the complete text ** of the string (which is overwritten with each call). ** ** n bytes of zText are stored. If n==0 then all of zText up to the first ** \000 terminator is stored. zText can contain up to two instances of ** %d. The values of p1 and p2 are written into the first and second ** %d. ** ** If n==-1, then the previous character is overwritten. */ PRIVATE char *append_str(char *zText, int n, int p1, int p2){ static char *z = 0; static int alloced = 0; static int used = 0; int c; char zInt[40]; if( zText==0 ){ used = 0; return z; } if( n<=0 ){ if( n<0 ){ used += n; assert( used>=0 ); } n = strlen(zText); } if( n+sizeof(zInt)*2+used >= alloced ){ alloced = n + sizeof(zInt)*2 + used + 200; z = realloc(z, alloced); } if( z==0 ) return ""; while( n-- > 0 ){ c = *(zText++); if( c=='%' && zText[0]=='d' ){ sprintf(zInt, "%d", p1); p1 = p2; strcpy(&z[used], zInt); used += strlen(&z[used]); zText++; n--; }else{ z[used++] = c; } } z[used] = 0; return z; } /* ** zCode is a string that is the action associated with a rule. Expand ** the symbols in this string so that the refer to elements of the parser ** stack. */ PRIVATE void translate_code(struct lemon *lemp, struct rule *rp){ char *cp, *xp; int i; char lhsused = 0; /* True if the LHS element has been used */ char used[MAXRHS]; /* True for each RHS element which is used */ for(i=0; inrhs; i++) used[i] = 0; lhsused = 0; append_str(0,0,0,0); for(cp=rp->code; *cp; cp++){ if( isalpha(*cp) && (cp==rp->code || (!isalnum(cp[-1]) && cp[-1]!='_')) ){ char saved; for(xp= &cp[1]; isalnum(*xp) || *xp=='_'; xp++); saved = *xp; *xp = 0; if( rp->lhsalias && strcmp(cp,rp->lhsalias)==0 ){ append_str("yygotominor.yy%d",0,rp->lhs->dtnum,0); cp = xp; lhsused = 1; }else{ for(i=0; inrhs; i++){ if( rp->rhsalias[i] && strcmp(cp,rp->rhsalias[i])==0 ){ if( cp!=rp->code && cp[-1]=='@' ){ /* If the argument is of the form @X then substituted ** the token number of X, not the value of X */ append_str("yymsp[%d].major",-1,i-rp->nrhs+1,0); }else{ struct symbol *sp = rp->rhs[i]; int dtnum; if( sp->type==MULTITERMINAL ){ dtnum = sp->subsym[0]->dtnum; }else{ dtnum = sp->dtnum; } append_str("yymsp[%d].minor.yy%d",0,i-rp->nrhs+1, dtnum); } cp = xp; used[i] = 1; break; } } } *xp = saved; } append_str(cp, 1, 0, 0); } /* End loop */ /* Check to make sure the LHS has been used */ if( rp->lhsalias && !lhsused ){ ErrorMsg(lemp->filename,rp->ruleline, "Label \"%s\" for \"%s(%s)\" is never used.", rp->lhsalias,rp->lhs->name,rp->lhsalias); lemp->errorcnt++; } /* Generate destructor code for RHS symbols which are not used in the ** reduce code */ for(i=0; inrhs; i++){ if( rp->rhsalias[i] && !used[i] ){ ErrorMsg(lemp->filename,rp->ruleline, "Label %s for \"%s(%s)\" is never used.", rp->rhsalias[i],rp->rhs[i]->name,rp->rhsalias[i]); lemp->errorcnt++; }else if( rp->rhsalias[i]==0 ){ if( has_destructor(rp->rhs[i],lemp) ){ append_str(" yy_destructor(%d,&yymsp[%d].minor);\n", 0, rp->rhs[i]->index,i-rp->nrhs+1); }else{ /* No destructor defined for this term */ } } } cp = append_str(0,0,0,0); rp->code = Strsafe(cp); } /* ** Generate code which executes when the rule "rp" is reduced. Write ** the code to "out". Make sure lineno stays up-to-date. */ PRIVATE void emit_code(out,rp,lemp,lineno) FILE *out; struct rule *rp; struct lemon *lemp; int *lineno; { char *cp; int linecnt = 0; /* Generate code to do the reduce action */ if( rp->code ){ tplt_linedir(out,rp->line,lemp->filename); fprintf(out,"{%s",rp->code); for(cp=rp->code; *cp; cp++){ if( *cp=='\n' ) linecnt++; } /* End loop */ (*lineno) += 3 + linecnt; fprintf(out,"}\n"); tplt_linedir(out,*lineno,lemp->outname); } /* End if( rp->code ) */ return; } /* ** Print the definition of the union used for the parser's data stack. ** This union contains fields for every possible data type for tokens ** and nonterminals. In the process of computing and printing this ** union, also set the ".dtnum" field of every terminal and nonterminal ** symbol. */ void print_stack_union(out,lemp,plineno,mhflag) FILE *out; /* The output stream */ struct lemon *lemp; /* The main info structure for this parser */ int *plineno; /* Pointer to the line number */ int mhflag; /* True if generating makeheaders output */ { int lineno = *plineno; /* The line number of the output */ char **types; /* A hash table of datatypes */ int arraysize; /* Size of the "types" array */ int maxdtlength; /* Maximum length of any ".datatype" field. */ char *stddt; /* Standardized name for a datatype */ int i,j; /* Loop counters */ int hash; /* For hashing the name of a type */ char *name; /* Name of the parser */ /* Allocate and initialize types[] and allocate stddt[] */ arraysize = lemp->nsymbol * 2; types = (char**)malloc( arraysize * sizeof(char*) ); for(i=0; ivartype ){ maxdtlength = strlen(lemp->vartype); } for(i=0; insymbol; i++){ int len; struct symbol *sp = lemp->symbols[i]; if( sp->datatype==0 ) continue; len = strlen(sp->datatype); if( len>maxdtlength ) maxdtlength = len; } stddt = (char*)malloc( maxdtlength*2 + 1 ); if( types==0 || stddt==0 ){ fprintf(stderr,"Out of memory.\n"); exit(1); } /* Build a hash table of datatypes. The ".dtnum" field of each symbol ** is filled in with the hash index plus 1. A ".dtnum" value of 0 is ** used for terminal symbols. If there is no %default_type defined then ** 0 is also used as the .dtnum value for nonterminals which do not specify ** a datatype using the %type directive. */ for(i=0; insymbol; i++){ struct symbol *sp = lemp->symbols[i]; char *cp; if( sp==lemp->errsym ){ sp->dtnum = arraysize+1; continue; } if( sp->type!=NONTERMINAL || (sp->datatype==0 && lemp->vartype==0) ){ sp->dtnum = 0; continue; } cp = sp->datatype; if( cp==0 ) cp = lemp->vartype; j = 0; while( isspace(*cp) ) cp++; while( *cp ) stddt[j++] = *cp++; while( j>0 && isspace(stddt[j-1]) ) j--; stddt[j] = 0; hash = 0; for(j=0; stddt[j]; j++){ hash = hash*53 + stddt[j]; } hash = (hash & 0x7fffffff)%arraysize; while( types[hash] ){ if( strcmp(types[hash],stddt)==0 ){ sp->dtnum = hash + 1; break; } hash++; if( hash>=arraysize ) hash = 0; } if( types[hash]==0 ){ sp->dtnum = hash + 1; types[hash] = (char*)malloc( strlen(stddt)+1 ); if( types[hash]==0 ){ fprintf(stderr,"Out of memory.\n"); exit(1); } strcpy(types[hash],stddt); } } /* Print out the definition of YYTOKENTYPE and YYMINORTYPE */ name = lemp->name ? lemp->name : "Parse"; lineno = *plineno; if( mhflag ){ fprintf(out,"#if INTERFACE\n"); lineno++; } fprintf(out,"#define %sTOKENTYPE %s\n",name, lemp->tokentype?lemp->tokentype:"void*"); lineno++; if( mhflag ){ fprintf(out,"#endif\n"); lineno++; } fprintf(out,"typedef union {\n"); lineno++; fprintf(out," %sTOKENTYPE yy0;\n",name); lineno++; for(i=0; ierrsym->dtnum); lineno++; free(stddt); free(types); fprintf(out,"} YYMINORTYPE;\n"); lineno++; *plineno = lineno; } /* ** Return the name of a C datatype able to represent values between ** lwr and upr, inclusive. */ static const char *minimum_size_type(int lwr, int upr){ if( lwr>=0 ){ if( upr<=255 ){ return "unsigned char"; }else if( upr<65535 ){ return "unsigned short int"; }else{ return "unsigned int"; } }else if( lwr>=-127 && upr<=127 ){ return "signed char"; }else if( lwr>=-32767 && upr<32767 ){ return "short"; }else{ return "int"; } } /* ** Each state contains a set of token transaction and a set of ** nonterminal transactions. Each of these sets makes an instance ** of the following structure. An array of these structures is used ** to order the creation of entries in the yy_action[] table. */ struct axset { struct state *stp; /* A pointer to a state */ int isTkn; /* True to use tokens. False for non-terminals */ int nAction; /* Number of actions */ }; /* ** Compare to axset structures for sorting purposes */ static int axset_compare(const void *a, const void *b){ struct axset *p1 = (struct axset*)a; struct axset *p2 = (struct axset*)b; return p2->nAction - p1->nAction; } /* Generate C source code for the parser */ void ReportTable(lemp, mhflag) struct lemon *lemp; int mhflag; /* Output in makeheaders format if true */ { FILE *out, *in; char line[LINESIZE]; int lineno; struct state *stp; struct action *ap; struct rule *rp; struct acttab *pActtab; int i, j, n; char *name; int mnTknOfst, mxTknOfst; int mnNtOfst, mxNtOfst; struct axset *ax; in = tplt_open(lemp); if( in==0 ) return; out = file_open(lemp,".c","wb"); if( out==0 ){ fclose(in); return; } lineno = 1; tplt_xfer(lemp->name,in,out,&lineno); /* Generate the include code, if any */ tplt_print(out,lemp,lemp->include,lemp->includeln,&lineno); if( mhflag ){ char *name = file_makename(lemp, ".h"); fprintf(out,"#include \"%s\"\n", name); lineno++; free(name); } tplt_xfer(lemp->name,in,out,&lineno); /* Generate #defines for all tokens */ if( mhflag ){ char *prefix; fprintf(out,"#if INTERFACE\n"); lineno++; if( lemp->tokenprefix ) prefix = lemp->tokenprefix; else prefix = ""; for(i=1; interminal; i++){ fprintf(out,"#define %s%-30s %2d\n",prefix,lemp->symbols[i]->name,i); lineno++; } fprintf(out,"#endif\n"); lineno++; } tplt_xfer(lemp->name,in,out,&lineno); /* Generate the defines */ fprintf(out,"#define YYCODETYPE %s\n", minimum_size_type(0, lemp->nsymbol+5)); lineno++; fprintf(out,"#define YYNOCODE %d\n",lemp->nsymbol+1); lineno++; fprintf(out,"#define YYACTIONTYPE %s\n", minimum_size_type(0, lemp->nstate+lemp->nrule+5)); lineno++; print_stack_union(out,lemp,&lineno,mhflag); if( lemp->stacksize ){ if( atoi(lemp->stacksize)<=0 ){ ErrorMsg(lemp->filename,0, "Illegal stack size: [%s]. The stack size should be an integer constant.", lemp->stacksize); lemp->errorcnt++; lemp->stacksize = "100"; } fprintf(out,"#define YYSTACKDEPTH %s\n",lemp->stacksize); lineno++; }else{ fprintf(out,"#define YYSTACKDEPTH 100\n"); lineno++; } if( mhflag ){ fprintf(out,"#if INTERFACE\n"); lineno++; } name = lemp->name ? lemp->name : "Parse"; if( lemp->arg && lemp->arg[0] ){ int i; i = strlen(lemp->arg); while( i>=1 && isspace(lemp->arg[i-1]) ) i--; while( i>=1 && (isalnum(lemp->arg[i-1]) || lemp->arg[i-1]=='_') ) i--; fprintf(out,"#define %sARG_SDECL %s;\n",name,lemp->arg); lineno++; fprintf(out,"#define %sARG_PDECL ,%s\n",name,lemp->arg); lineno++; fprintf(out,"#define %sARG_FETCH %s = yypParser->%s\n", name,lemp->arg,&lemp->arg[i]); lineno++; fprintf(out,"#define %sARG_STORE yypParser->%s = %s\n", name,&lemp->arg[i],&lemp->arg[i]); lineno++; }else{ fprintf(out,"#define %sARG_SDECL\n",name); lineno++; fprintf(out,"#define %sARG_PDECL\n",name); lineno++; fprintf(out,"#define %sARG_FETCH\n",name); lineno++; fprintf(out,"#define %sARG_STORE\n",name); lineno++; } if( mhflag ){ fprintf(out,"#endif\n"); lineno++; } fprintf(out,"#define YYNSTATE %d\n",lemp->nstate); lineno++; fprintf(out,"#define YYNRULE %d\n",lemp->nrule); lineno++; fprintf(out,"#define YYERRORSYMBOL %d\n",lemp->errsym->index); lineno++; fprintf(out,"#define YYERRSYMDT yy%d\n",lemp->errsym->dtnum); lineno++; if( lemp->has_fallback ){ fprintf(out,"#define YYFALLBACK 1\n"); lineno++; } tplt_xfer(lemp->name,in,out,&lineno); /* Generate the action table and its associates: ** ** yy_action[] A single table containing all actions. ** yy_lookahead[] A table containing the lookahead for each entry in ** yy_action. Used to detect hash collisions. ** yy_shift_ofst[] For each state, the offset into yy_action for ** shifting terminals. ** yy_reduce_ofst[] For each state, the offset into yy_action for ** shifting non-terminals after a reduce. ** yy_default[] Default action for each state. */ /* Compute the actions on all states and count them up */ ax = malloc( sizeof(ax[0])*lemp->nstate*2 ); if( ax==0 ){ fprintf(stderr,"malloc failed\n"); exit(1); } for(i=0; instate; i++){ stp = lemp->sorted[i]; ax[i*2].stp = stp; ax[i*2].isTkn = 1; ax[i*2].nAction = stp->nTknAct; ax[i*2+1].stp = stp; ax[i*2+1].isTkn = 0; ax[i*2+1].nAction = stp->nNtAct; } mxTknOfst = mnTknOfst = 0; mxNtOfst = mnNtOfst = 0; /* Compute the action table. In order to try to keep the size of the ** action table to a minimum, the heuristic of placing the largest action ** sets first is used. */ qsort(ax, lemp->nstate*2, sizeof(ax[0]), axset_compare); pActtab = acttab_alloc(); for(i=0; instate*2 && ax[i].nAction>0; i++){ stp = ax[i].stp; if( ax[i].isTkn ){ for(ap=stp->ap; ap; ap=ap->next){ int action; if( ap->sp->index>=lemp->nterminal ) continue; action = compute_action(lemp, ap); if( action<0 ) continue; acttab_action(pActtab, ap->sp->index, action); } stp->iTknOfst = acttab_insert(pActtab); if( stp->iTknOfstiTknOfst; if( stp->iTknOfst>mxTknOfst ) mxTknOfst = stp->iTknOfst; }else{ for(ap=stp->ap; ap; ap=ap->next){ int action; if( ap->sp->indexnterminal ) continue; if( ap->sp->index==lemp->nsymbol ) continue; action = compute_action(lemp, ap); if( action<0 ) continue; acttab_action(pActtab, ap->sp->index, action); } stp->iNtOfst = acttab_insert(pActtab); if( stp->iNtOfstiNtOfst; if( stp->iNtOfst>mxNtOfst ) mxNtOfst = stp->iNtOfst; } } free(ax); /* Output the yy_action table */ fprintf(out,"static const YYACTIONTYPE yy_action[] = {\n"); lineno++; n = acttab_size(pActtab); for(i=j=0; insymbol + lemp->nrule + 2; if( j==0 ) fprintf(out," /* %5d */ ", i); fprintf(out, " %4d,", action); if( j==9 || i==n-1 ){ fprintf(out, "\n"); lineno++; j = 0; }else{ j++; } } fprintf(out, "};\n"); lineno++; /* Output the yy_lookahead table */ fprintf(out,"static const YYCODETYPE yy_lookahead[] = {\n"); lineno++; for(i=j=0; insymbol; if( j==0 ) fprintf(out," /* %5d */ ", i); fprintf(out, " %4d,", la); if( j==9 || i==n-1 ){ fprintf(out, "\n"); lineno++; j = 0; }else{ j++; } } fprintf(out, "};\n"); lineno++; /* Output the yy_shift_ofst[] table */ fprintf(out, "#define YY_SHIFT_USE_DFLT (%d)\n", mnTknOfst-1); lineno++; n = lemp->nstate; while( n>0 && lemp->sorted[n-1]->iTknOfst==NO_OFFSET ) n--; fprintf(out, "#define YY_SHIFT_MAX %d\n", n-1); lineno++; fprintf(out, "static const %s yy_shift_ofst[] = {\n", minimum_size_type(mnTknOfst-1, mxTknOfst)); lineno++; for(i=j=0; isorted[i]; ofst = stp->iTknOfst; if( ofst==NO_OFFSET ) ofst = mnTknOfst - 1; if( j==0 ) fprintf(out," /* %5d */ ", i); fprintf(out, " %4d,", ofst); if( j==9 || i==n-1 ){ fprintf(out, "\n"); lineno++; j = 0; }else{ j++; } } fprintf(out, "};\n"); lineno++; /* Output the yy_reduce_ofst[] table */ fprintf(out, "#define YY_REDUCE_USE_DFLT (%d)\n", mnNtOfst-1); lineno++; n = lemp->nstate; while( n>0 && lemp->sorted[n-1]->iNtOfst==NO_OFFSET ) n--; fprintf(out, "#define YY_REDUCE_MAX %d\n", n-1); lineno++; fprintf(out, "static const %s yy_reduce_ofst[] = {\n", minimum_size_type(mnNtOfst-1, mxNtOfst)); lineno++; for(i=j=0; isorted[i]; ofst = stp->iNtOfst; if( ofst==NO_OFFSET ) ofst = mnNtOfst - 1; if( j==0 ) fprintf(out," /* %5d */ ", i); fprintf(out, " %4d,", ofst); if( j==9 || i==n-1 ){ fprintf(out, "\n"); lineno++; j = 0; }else{ j++; } } fprintf(out, "};\n"); lineno++; /* Output the default action table */ fprintf(out, "static const YYACTIONTYPE yy_default[] = {\n"); lineno++; n = lemp->nstate; for(i=j=0; isorted[i]; if( j==0 ) fprintf(out," /* %5d */ ", i); fprintf(out, " %4d,", stp->iDflt); if( j==9 || i==n-1 ){ fprintf(out, "\n"); lineno++; j = 0; }else{ j++; } } fprintf(out, "};\n"); lineno++; tplt_xfer(lemp->name,in,out,&lineno); /* Generate the table of fallback tokens. */ if( lemp->has_fallback ){ for(i=0; interminal; i++){ struct symbol *p = lemp->symbols[i]; if( p->fallback==0 ){ fprintf(out, " 0, /* %10s => nothing */\n", p->name); }else{ fprintf(out, " %3d, /* %10s => %s */\n", p->fallback->index, p->name, p->fallback->name); } lineno++; } } tplt_xfer(lemp->name, in, out, &lineno); /* Generate a table containing the symbolic name of every symbol */ for(i=0; insymbol; i++){ sprintf(line,"\"%s\",",lemp->symbols[i]->name); fprintf(out," %-15s",line); if( (i&3)==3 ){ fprintf(out,"\n"); lineno++; } } if( (i&3)!=0 ){ fprintf(out,"\n"); lineno++; } tplt_xfer(lemp->name,in,out,&lineno); /* Generate a table containing a text string that describes every ** rule in the rule set of the grammer. This information is used ** when tracing REDUCE actions. */ for(i=0, rp=lemp->rule; rp; rp=rp->next, i++){ assert( rp->index==i ); fprintf(out," /* %3d */ \"%s ::=", i, rp->lhs->name); for(j=0; jnrhs; j++){ struct symbol *sp = rp->rhs[j]; fprintf(out," %s", sp->name); if( sp->type==MULTITERMINAL ){ int k; for(k=1; knsubsym; k++){ fprintf(out,"|%s",sp->subsym[k]->name); } } } fprintf(out,"\",\n"); lineno++; } tplt_xfer(lemp->name,in,out,&lineno); /* Generate code which executes every time a symbol is popped from ** the stack while processing errors or while destroying the parser. ** (In other words, generate the %destructor actions) */ if( lemp->tokendest ){ for(i=0; insymbol; i++){ struct symbol *sp = lemp->symbols[i]; if( sp==0 || sp->type!=TERMINAL ) continue; fprintf(out," case %d:\n",sp->index); lineno++; } for(i=0; insymbol && lemp->symbols[i]->type!=TERMINAL; i++); if( insymbol ){ emit_destructor_code(out,lemp->symbols[i],lemp,&lineno); fprintf(out," break;\n"); lineno++; } } if( lemp->vardest ){ struct symbol *dflt_sp = 0; for(i=0; insymbol; i++){ struct symbol *sp = lemp->symbols[i]; if( sp==0 || sp->type==TERMINAL || sp->index<=0 || sp->destructor!=0 ) continue; fprintf(out," case %d:\n",sp->index); lineno++; dflt_sp = sp; } if( dflt_sp!=0 ){ emit_destructor_code(out,dflt_sp,lemp,&lineno); fprintf(out," break;\n"); lineno++; } } for(i=0; insymbol; i++){ struct symbol *sp = lemp->symbols[i]; if( sp==0 || sp->type==TERMINAL || sp->destructor==0 ) continue; fprintf(out," case %d:\n",sp->index); lineno++; /* Combine duplicate destructors into a single case */ for(j=i+1; jnsymbol; j++){ struct symbol *sp2 = lemp->symbols[j]; if( sp2 && sp2->type!=TERMINAL && sp2->destructor && sp2->dtnum==sp->dtnum && strcmp(sp->destructor,sp2->destructor)==0 ){ fprintf(out," case %d:\n",sp2->index); lineno++; sp2->destructor = 0; } } emit_destructor_code(out,lemp->symbols[i],lemp,&lineno); fprintf(out," break;\n"); lineno++; } tplt_xfer(lemp->name,in,out,&lineno); /* Generate code which executes whenever the parser stack overflows */ tplt_print(out,lemp,lemp->overflow,lemp->overflowln,&lineno); tplt_xfer(lemp->name,in,out,&lineno); /* Generate the table of rule information ** ** Note: This code depends on the fact that rules are number ** sequentually beginning with 0. */ for(rp=lemp->rule; rp; rp=rp->next){ fprintf(out," { %d, %d },\n",rp->lhs->index,rp->nrhs); lineno++; } tplt_xfer(lemp->name,in,out,&lineno); /* Generate code which execution during each REDUCE action */ for(rp=lemp->rule; rp; rp=rp->next){ if( rp->code ) translate_code(lemp, rp); } for(rp=lemp->rule; rp; rp=rp->next){ struct rule *rp2; if( rp->code==0 ) continue; fprintf(out," case %d:\n",rp->index); lineno++; for(rp2=rp->next; rp2; rp2=rp2->next){ if( rp2->code==rp->code ){ fprintf(out," case %d:\n",rp2->index); lineno++; rp2->code = 0; } } emit_code(out,rp,lemp,&lineno); fprintf(out," break;\n"); lineno++; } tplt_xfer(lemp->name,in,out,&lineno); /* Generate code which executes if a parse fails */ tplt_print(out,lemp,lemp->failure,lemp->failureln,&lineno); tplt_xfer(lemp->name,in,out,&lineno); /* Generate code which executes when a syntax error occurs */ tplt_print(out,lemp,lemp->error,lemp->errorln,&lineno); tplt_xfer(lemp->name,in,out,&lineno); /* Generate code which executes when the parser accepts its input */ tplt_print(out,lemp,lemp->accept,lemp->acceptln,&lineno); tplt_xfer(lemp->name,in,out,&lineno); /* Append any addition code the user desires */ tplt_print(out,lemp,lemp->extracode,lemp->extracodeln,&lineno); fclose(in); fclose(out); return; } /* Generate a header file for the parser */ void ReportHeader(lemp) struct lemon *lemp; { FILE *out, *in; char *prefix; char line[LINESIZE]; char pattern[LINESIZE]; int i; if( lemp->tokenprefix ) prefix = lemp->tokenprefix; else prefix = ""; in = file_open(lemp,".h","rb"); if( in ){ for(i=1; interminal && fgets(line,LINESIZE,in); i++){ sprintf(pattern,"#define %s%-30s %2d\n",prefix,lemp->symbols[i]->name,i); if( strcmp(line,pattern) ) break; } fclose(in); if( i==lemp->nterminal ){ /* No change in the file. Don't rewrite it. */ return; } } out = file_open(lemp,".h","wb"); if( out ){ for(i=1; interminal; i++){ fprintf(out,"#define %s%-30s %2d\n",prefix,lemp->symbols[i]->name,i); } fclose(out); } return; } /* Reduce the size of the action tables, if possible, by making use ** of defaults. ** ** In this version, we take the most frequent REDUCE action and make ** it the default. */ void CompressTables(lemp) struct lemon *lemp; { struct state *stp; struct action *ap, *ap2; struct rule *rp, *rp2, *rbest; int nbest, n; int i; for(i=0; instate; i++){ stp = lemp->sorted[i]; nbest = 0; rbest = 0; for(ap=stp->ap; ap; ap=ap->next){ if( ap->type!=REDUCE ) continue; rp = ap->x.rp; if( rp==rbest ) continue; n = 1; for(ap2=ap->next; ap2; ap2=ap2->next){ if( ap2->type!=REDUCE ) continue; rp2 = ap2->x.rp; if( rp2==rbest ) continue; if( rp2==rp ) n++; } if( n>nbest ){ nbest = n; rbest = rp; } } /* Do not make a default if the number of rules to default ** is not at least 1 */ if( nbest<1 ) continue; /* Combine matching REDUCE actions into a single default */ for(ap=stp->ap; ap; ap=ap->next){ if( ap->type==REDUCE && ap->x.rp==rbest ) break; } assert( ap ); ap->sp = Symbol_new("{default}"); for(ap=ap->next; ap; ap=ap->next){ if( ap->type==REDUCE && ap->x.rp==rbest ) ap->type = NOT_USED; } stp->ap = Action_sort(stp->ap); } } /* ** Compare two states for sorting purposes. The smaller state is the ** one with the most non-terminal actions. If they have the same number ** of non-terminal actions, then the smaller is the one with the most ** token actions. */ static int stateResortCompare(const void *a, const void *b){ const struct state *pA = *(const struct state**)a; const struct state *pB = *(const struct state**)b; int n; n = pB->nNtAct - pA->nNtAct; if( n==0 ){ n = pB->nTknAct - pA->nTknAct; } return n; } /* ** Renumber and resort states so that states with fewer choices ** occur at the end. Except, keep state 0 as the first state. */ void ResortStates(lemp) struct lemon *lemp; { int i; struct state *stp; struct action *ap; for(i=0; instate; i++){ stp = lemp->sorted[i]; stp->nTknAct = stp->nNtAct = 0; stp->iDflt = lemp->nstate + lemp->nrule; stp->iTknOfst = NO_OFFSET; stp->iNtOfst = NO_OFFSET; for(ap=stp->ap; ap; ap=ap->next){ if( compute_action(lemp,ap)>=0 ){ if( ap->sp->indexnterminal ){ stp->nTknAct++; }else if( ap->sp->indexnsymbol ){ stp->nNtAct++; }else{ stp->iDflt = compute_action(lemp, ap); } } } } qsort(&lemp->sorted[1], lemp->nstate-1, sizeof(lemp->sorted[0]), stateResortCompare); for(i=0; instate; i++){ lemp->sorted[i]->statenum = i; } } /***************** From the file "set.c" ************************************/ /* ** Set manipulation routines for the LEMON parser generator. */ static int size = 0; /* Set the set size */ void SetSize(n) int n; { size = n+1; } /* Allocate a new set */ char *SetNew(){ char *s; int i; s = (char*)malloc( size ); if( s==0 ){ extern void memory_error(); memory_error(); } for(i=0; isize = 1024; x1a->count = 0; x1a->tbl = (x1node*)malloc( (sizeof(x1node) + sizeof(x1node*))*1024 ); if( x1a->tbl==0 ){ free(x1a); x1a = 0; }else{ int i; x1a->ht = (x1node**)&(x1a->tbl[1024]); for(i=0; i<1024; i++) x1a->ht[i] = 0; } } } /* Insert a new record into the array. Return TRUE if successful. ** Prior data with the same key is NOT overwritten */ int Strsafe_insert(data) char *data; { x1node *np; int h; int ph; if( x1a==0 ) return 0; ph = strhash(data); h = ph & (x1a->size-1); np = x1a->ht[h]; while( np ){ if( strcmp(np->data,data)==0 ){ /* An existing entry with the same key is found. */ /* Fail because overwrite is not allows. */ return 0; } np = np->next; } if( x1a->count>=x1a->size ){ /* Need to make the hash table bigger */ int i,size; struct s_x1 array; array.size = size = x1a->size*2; array.count = x1a->count; array.tbl = (x1node*)malloc( (sizeof(x1node) + sizeof(x1node*))*size ); if( array.tbl==0 ) return 0; /* Fail due to malloc failure */ array.ht = (x1node**)&(array.tbl[size]); for(i=0; icount; i++){ x1node *oldnp, *newnp; oldnp = &(x1a->tbl[i]); h = strhash(oldnp->data) & (size-1); newnp = &(array.tbl[i]); if( array.ht[h] ) array.ht[h]->from = &(newnp->next); newnp->next = array.ht[h]; newnp->data = oldnp->data; newnp->from = &(array.ht[h]); array.ht[h] = newnp; } free(x1a->tbl); *x1a = array; } /* Insert the new data */ h = ph & (x1a->size-1); np = &(x1a->tbl[x1a->count++]); np->data = data; if( x1a->ht[h] ) x1a->ht[h]->from = &(np->next); np->next = x1a->ht[h]; x1a->ht[h] = np; np->from = &(x1a->ht[h]); return 1; } /* Return a pointer to data assigned to the given key. Return NULL ** if no such key. */ char *Strsafe_find(key) char *key; { int h; x1node *np; if( x1a==0 ) return 0; h = strhash(key) & (x1a->size-1); np = x1a->ht[h]; while( np ){ if( strcmp(np->data,key)==0 ) break; np = np->next; } return np ? np->data : 0; } /* Return a pointer to the (terminal or nonterminal) symbol "x". ** Create a new symbol if this is the first time "x" has been seen. */ struct symbol *Symbol_new(x) char *x; { struct symbol *sp; sp = Symbol_find(x); if( sp==0 ){ sp = (struct symbol *)malloc( sizeof(struct symbol) ); MemoryCheck(sp); sp->name = Strsafe(x); sp->type = isupper(*x) ? TERMINAL : NONTERMINAL; sp->rule = 0; sp->fallback = 0; sp->prec = -1; sp->assoc = UNK; sp->firstset = 0; sp->lambda = B_FALSE; sp->destructor = 0; sp->datatype = 0; Symbol_insert(sp,sp->name); } return sp; } /* Compare two symbols for working purposes ** ** Symbols that begin with upper case letters (terminals or tokens) ** must sort before symbols that begin with lower case letters ** (non-terminals). Other than that, the order does not matter. ** ** We find experimentally that leaving the symbols in their original ** order (the order they appeared in the grammar file) gives the ** smallest parser tables in SQLite. */ int Symbolcmpp(struct symbol **a, struct symbol **b){ int i1 = (**a).index + 10000000*((**a).name[0]>'Z'); int i2 = (**b).index + 10000000*((**b).name[0]>'Z'); return i1-i2; } /* There is one instance of the following structure for each ** associative array of type "x2". */ struct s_x2 { int size; /* The number of available slots. */ /* Must be a power of 2 greater than or */ /* equal to 1 */ int count; /* Number of currently slots filled */ struct s_x2node *tbl; /* The data stored here */ struct s_x2node **ht; /* Hash table for lookups */ }; /* There is one instance of this structure for every data element ** in an associative array of type "x2". */ typedef struct s_x2node { struct symbol *data; /* The data */ char *key; /* The key */ struct s_x2node *next; /* Next entry with the same hash */ struct s_x2node **from; /* Previous link */ } x2node; /* There is only one instance of the array, which is the following */ static struct s_x2 *x2a; /* Allocate a new associative array */ void Symbol_init(){ if( x2a ) return; x2a = (struct s_x2*)malloc( sizeof(struct s_x2) ); if( x2a ){ x2a->size = 128; x2a->count = 0; x2a->tbl = (x2node*)malloc( (sizeof(x2node) + sizeof(x2node*))*128 ); if( x2a->tbl==0 ){ free(x2a); x2a = 0; }else{ int i; x2a->ht = (x2node**)&(x2a->tbl[128]); for(i=0; i<128; i++) x2a->ht[i] = 0; } } } /* Insert a new record into the array. Return TRUE if successful. ** Prior data with the same key is NOT overwritten */ int Symbol_insert(data,key) struct symbol *data; char *key; { x2node *np; int h; int ph; if( x2a==0 ) return 0; ph = strhash(key); h = ph & (x2a->size-1); np = x2a->ht[h]; while( np ){ if( strcmp(np->key,key)==0 ){ /* An existing entry with the same key is found. */ /* Fail because overwrite is not allows. */ return 0; } np = np->next; } if( x2a->count>=x2a->size ){ /* Need to make the hash table bigger */ int i,size; struct s_x2 array; array.size = size = x2a->size*2; array.count = x2a->count; array.tbl = (x2node*)malloc( (sizeof(x2node) + sizeof(x2node*))*size ); if( array.tbl==0 ) return 0; /* Fail due to malloc failure */ array.ht = (x2node**)&(array.tbl[size]); for(i=0; icount; i++){ x2node *oldnp, *newnp; oldnp = &(x2a->tbl[i]); h = strhash(oldnp->key) & (size-1); newnp = &(array.tbl[i]); if( array.ht[h] ) array.ht[h]->from = &(newnp->next); newnp->next = array.ht[h]; newnp->key = oldnp->key; newnp->data = oldnp->data; newnp->from = &(array.ht[h]); array.ht[h] = newnp; } free(x2a->tbl); *x2a = array; } /* Insert the new data */ h = ph & (x2a->size-1); np = &(x2a->tbl[x2a->count++]); np->key = key; np->data = data; if( x2a->ht[h] ) x2a->ht[h]->from = &(np->next); np->next = x2a->ht[h]; x2a->ht[h] = np; np->from = &(x2a->ht[h]); return 1; } /* Return a pointer to data assigned to the given key. Return NULL ** if no such key. */ struct symbol *Symbol_find(key) char *key; { int h; x2node *np; if( x2a==0 ) return 0; h = strhash(key) & (x2a->size-1); np = x2a->ht[h]; while( np ){ if( strcmp(np->key,key)==0 ) break; np = np->next; } return np ? np->data : 0; } /* Return the n-th data. Return NULL if n is out of range. */ struct symbol *Symbol_Nth(n) int n; { struct symbol *data; if( x2a && n>0 && n<=x2a->count ){ data = x2a->tbl[n-1].data; }else{ data = 0; } return data; } /* Return the size of the array */ int Symbol_count() { return x2a ? x2a->count : 0; } /* Return an array of pointers to all data in the table. ** The array is obtained from malloc. Return NULL if memory allocation ** problems, or if the array is empty. */ struct symbol **Symbol_arrayof() { struct symbol **array; int i,size; if( x2a==0 ) return 0; size = x2a->count; array = (struct symbol **)malloc( sizeof(struct symbol *)*size ); if( array ){ for(i=0; itbl[i].data; } return array; } /* Compare two configurations */ int Configcmp(a,b) struct config *a; struct config *b; { int x; x = a->rp->index - b->rp->index; if( x==0 ) x = a->dot - b->dot; return x; } /* Compare two states */ PRIVATE int statecmp(a,b) struct config *a; struct config *b; { int rc; for(rc=0; rc==0 && a && b; a=a->bp, b=b->bp){ rc = a->rp->index - b->rp->index; if( rc==0 ) rc = a->dot - b->dot; } if( rc==0 ){ if( a ) rc = 1; if( b ) rc = -1; } return rc; } /* Hash a state */ PRIVATE int statehash(a) struct config *a; { int h=0; while( a ){ h = h*571 + a->rp->index*37 + a->dot; a = a->bp; } return h; } /* Allocate a new state structure */ struct state *State_new() { struct state *new; new = (struct state *)malloc( sizeof(struct state) ); MemoryCheck(new); return new; } /* There is one instance of the following structure for each ** associative array of type "x3". */ struct s_x3 { int size; /* The number of available slots. */ /* Must be a power of 2 greater than or */ /* equal to 1 */ int count; /* Number of currently slots filled */ struct s_x3node *tbl; /* The data stored here */ struct s_x3node **ht; /* Hash table for lookups */ }; /* There is one instance of this structure for every data element ** in an associative array of type "x3". */ typedef struct s_x3node { struct state *data; /* The data */ struct config *key; /* The key */ struct s_x3node *next; /* Next entry with the same hash */ struct s_x3node **from; /* Previous link */ } x3node; /* There is only one instance of the array, which is the following */ static struct s_x3 *x3a; /* Allocate a new associative array */ void State_init(){ if( x3a ) return; x3a = (struct s_x3*)malloc( sizeof(struct s_x3) ); if( x3a ){ x3a->size = 128; x3a->count = 0; x3a->tbl = (x3node*)malloc( (sizeof(x3node) + sizeof(x3node*))*128 ); if( x3a->tbl==0 ){ free(x3a); x3a = 0; }else{ int i; x3a->ht = (x3node**)&(x3a->tbl[128]); for(i=0; i<128; i++) x3a->ht[i] = 0; } } } /* Insert a new record into the array. Return TRUE if successful. ** Prior data with the same key is NOT overwritten */ int State_insert(data,key) struct state *data; struct config *key; { x3node *np; int h; int ph; if( x3a==0 ) return 0; ph = statehash(key); h = ph & (x3a->size-1); np = x3a->ht[h]; while( np ){ if( statecmp(np->key,key)==0 ){ /* An existing entry with the same key is found. */ /* Fail because overwrite is not allows. */ return 0; } np = np->next; } if( x3a->count>=x3a->size ){ /* Need to make the hash table bigger */ int i,size; struct s_x3 array; array.size = size = x3a->size*2; array.count = x3a->count; array.tbl = (x3node*)malloc( (sizeof(x3node) + sizeof(x3node*))*size ); if( array.tbl==0 ) return 0; /* Fail due to malloc failure */ array.ht = (x3node**)&(array.tbl[size]); for(i=0; icount; i++){ x3node *oldnp, *newnp; oldnp = &(x3a->tbl[i]); h = statehash(oldnp->key) & (size-1); newnp = &(array.tbl[i]); if( array.ht[h] ) array.ht[h]->from = &(newnp->next); newnp->next = array.ht[h]; newnp->key = oldnp->key; newnp->data = oldnp->data; newnp->from = &(array.ht[h]); array.ht[h] = newnp; } free(x3a->tbl); *x3a = array; } /* Insert the new data */ h = ph & (x3a->size-1); np = &(x3a->tbl[x3a->count++]); np->key = key; np->data = data; if( x3a->ht[h] ) x3a->ht[h]->from = &(np->next); np->next = x3a->ht[h]; x3a->ht[h] = np; np->from = &(x3a->ht[h]); return 1; } /* Return a pointer to data assigned to the given key. Return NULL ** if no such key. */ struct state *State_find(key) struct config *key; { int h; x3node *np; if( x3a==0 ) return 0; h = statehash(key) & (x3a->size-1); np = x3a->ht[h]; while( np ){ if( statecmp(np->key,key)==0 ) break; np = np->next; } return np ? np->data : 0; } /* Return an array of pointers to all data in the table. ** The array is obtained from malloc. Return NULL if memory allocation ** problems, or if the array is empty. */ struct state **State_arrayof() { struct state **array; int i,size; if( x3a==0 ) return 0; size = x3a->count; array = (struct state **)malloc( sizeof(struct state *)*size ); if( array ){ for(i=0; itbl[i].data; } return array; } /* Hash a configuration */ PRIVATE int confighash(a) struct config *a; { int h=0; h = h*571 + a->rp->index*37 + a->dot; return h; } /* There is one instance of the following structure for each ** associative array of type "x4". */ struct s_x4 { int size; /* The number of available slots. */ /* Must be a power of 2 greater than or */ /* equal to 1 */ int count; /* Number of currently slots filled */ struct s_x4node *tbl; /* The data stored here */ struct s_x4node **ht; /* Hash table for lookups */ }; /* There is one instance of this structure for every data element ** in an associative array of type "x4". */ typedef struct s_x4node { struct config *data; /* The data */ struct s_x4node *next; /* Next entry with the same hash */ struct s_x4node **from; /* Previous link */ } x4node; /* There is only one instance of the array, which is the following */ static struct s_x4 *x4a; /* Allocate a new associative array */ void Configtable_init(){ if( x4a ) return; x4a = (struct s_x4*)malloc( sizeof(struct s_x4) ); if( x4a ){ x4a->size = 64; x4a->count = 0; x4a->tbl = (x4node*)malloc( (sizeof(x4node) + sizeof(x4node*))*64 ); if( x4a->tbl==0 ){ free(x4a); x4a = 0; }else{ int i; x4a->ht = (x4node**)&(x4a->tbl[64]); for(i=0; i<64; i++) x4a->ht[i] = 0; } } } /* Insert a new record into the array. Return TRUE if successful. ** Prior data with the same key is NOT overwritten */ int Configtable_insert(data) struct config *data; { x4node *np; int h; int ph; if( x4a==0 ) return 0; ph = confighash(data); h = ph & (x4a->size-1); np = x4a->ht[h]; while( np ){ if( Configcmp(np->data,data)==0 ){ /* An existing entry with the same key is found. */ /* Fail because overwrite is not allows. */ return 0; } np = np->next; } if( x4a->count>=x4a->size ){ /* Need to make the hash table bigger */ int i,size; struct s_x4 array; array.size = size = x4a->size*2; array.count = x4a->count; array.tbl = (x4node*)malloc( (sizeof(x4node) + sizeof(x4node*))*size ); if( array.tbl==0 ) return 0; /* Fail due to malloc failure */ array.ht = (x4node**)&(array.tbl[size]); for(i=0; icount; i++){ x4node *oldnp, *newnp; oldnp = &(x4a->tbl[i]); h = confighash(oldnp->data) & (size-1); newnp = &(array.tbl[i]); if( array.ht[h] ) array.ht[h]->from = &(newnp->next); newnp->next = array.ht[h]; newnp->data = oldnp->data; newnp->from = &(array.ht[h]); array.ht[h] = newnp; } free(x4a->tbl); *x4a = array; } /* Insert the new data */ h = ph & (x4a->size-1); np = &(x4a->tbl[x4a->count++]); np->data = data; if( x4a->ht[h] ) x4a->ht[h]->from = &(np->next); np->next = x4a->ht[h]; x4a->ht[h] = np; np->from = &(x4a->ht[h]); return 1; } /* Return a pointer to data assigned to the given key. Return NULL ** if no such key. */ struct config *Configtable_find(key) struct config *key; { int h; x4node *np; if( x4a==0 ) return 0; h = confighash(key) & (x4a->size-1); np = x4a->ht[h]; while( np ){ if( Configcmp(np->data,key)==0 ) break; np = np->next; } return np ? np->data : 0; } /* Remove all data from the table. Pass each data to the function "f" ** as it is removed. ("f" may be null to avoid this step.) */ void Configtable_clear(f) int(*f)(/* struct config * */); { int i; if( x4a==0 || x4a->count==0 ) return; if( f ) for(i=0; icount; i++) (*f)(x4a->tbl[i].data); for(i=0; isize; i++) x4a->ht[i] = 0; x4a->count = 0; return; } tkHTML-4ee7aaa953d6cb59/tools/lempar.c000064400000000000000000000562551151224263100167160ustar00nobodynobody/* Driver template for the LEMON parser generator. ** The author disclaims copyright to this source code. */ /* First off, code is include which follows the "include" declaration ** in the input file. */ #include %% /* Next is all token values, in a form suitable for use by makeheaders. ** This section will be null unless lemon is run with the -m switch. */ /* ** These constants (all generated automatically by the parser generator) ** specify the various kinds of tokens (terminals) that the parser ** understands. ** ** Each symbol here is a terminal symbol in the grammar. */ %% /* Make sure the INTERFACE macro is defined. */ #ifndef INTERFACE # define INTERFACE 1 #endif /* The next thing included is series of defines which control ** various aspects of the generated parser. ** YYCODETYPE is the data type used for storing terminal ** and nonterminal numbers. "unsigned char" is ** used if there are fewer than 250 terminals ** and nonterminals. "int" is used otherwise. ** YYNOCODE is a number of type YYCODETYPE which corresponds ** to no legal terminal or nonterminal number. This ** number is used to fill in empty slots of the hash ** table. ** YYFALLBACK If defined, this indicates that one or more tokens ** have fall-back values which should be used if the ** original value of the token will not parse. ** YYACTIONTYPE is the data type used for storing terminal ** and nonterminal numbers. "unsigned char" is ** used if there are fewer than 250 rules and ** states combined. "int" is used otherwise. ** ParseTOKENTYPE is the data type used for minor tokens given ** directly to the parser from the tokenizer. ** YYMINORTYPE is the data type used for all minor tokens. ** This is typically a union of many types, one of ** which is ParseTOKENTYPE. The entry in the union ** for base tokens is called "yy0". ** YYSTACKDEPTH is the maximum depth of the parser's stack. ** ParseARG_SDECL A static variable declaration for the %extra_argument ** ParseARG_PDECL A parameter declaration for the %extra_argument ** ParseARG_STORE Code to store %extra_argument into yypParser ** ParseARG_FETCH Code to extract %extra_argument from yypParser ** YYNSTATE the combined number of states. ** YYNRULE the number of rules in the grammar ** YYERRORSYMBOL is the code number of the error symbol. If not ** defined, then do no error processing. */ %% #define YY_NO_ACTION (YYNSTATE+YYNRULE+2) #define YY_ACCEPT_ACTION (YYNSTATE+YYNRULE+1) #define YY_ERROR_ACTION (YYNSTATE+YYNRULE) /* Next are that tables used to determine what action to take based on the ** current state and lookahead token. These tables are used to implement ** functions that take a state number and lookahead value and return an ** action integer. ** ** Suppose the action integer is N. Then the action is determined as ** follows ** ** 0 <= N < YYNSTATE Shift N. That is, push the lookahead ** token onto the stack and goto state N. ** ** YYNSTATE <= N < YYNSTATE+YYNRULE Reduce by rule N-YYNSTATE. ** ** N == YYNSTATE+YYNRULE A syntax error has occurred. ** ** N == YYNSTATE+YYNRULE+1 The parser accepts its input. ** ** N == YYNSTATE+YYNRULE+2 No such action. Denotes unused ** slots in the yy_action[] table. ** ** The action table is constructed as a single large table named yy_action[]. ** Given state S and lookahead X, the action is computed as ** ** yy_action[ yy_shift_ofst[S] + X ] ** ** If the index value yy_shift_ofst[S]+X is out of range or if the value ** yy_lookahead[yy_shift_ofst[S]+X] is not equal to X or if yy_shift_ofst[S] ** is equal to YY_SHIFT_USE_DFLT, it means that the action is not in the table ** and that yy_default[S] should be used instead. ** ** The formula above is for computing the action when the lookahead is ** a terminal symbol. If the lookahead is a non-terminal (as occurs after ** a reduce action) then the yy_reduce_ofst[] array is used in place of ** the yy_shift_ofst[] array and YY_REDUCE_USE_DFLT is used in place of ** YY_SHIFT_USE_DFLT. ** ** The following are the tables generated in this section: ** ** yy_action[] A single table containing all actions. ** yy_lookahead[] A table containing the lookahead for each entry in ** yy_action. Used to detect hash collisions. ** yy_shift_ofst[] For each state, the offset into yy_action for ** shifting terminals. ** yy_reduce_ofst[] For each state, the offset into yy_action for ** shifting non-terminals after a reduce. ** yy_default[] Default action for each state. */ %% #define YY_SZ_ACTTAB (sizeof(yy_action)/sizeof(yy_action[0])) /* The next table maps tokens into fallback tokens. If a construct ** like the following: ** ** %fallback ID X Y Z. ** ** appears in the grammer, then ID becomes a fallback token for X, Y, ** and Z. Whenever one of the tokens X, Y, or Z is input to the parser ** but it does not parse, the type of the token is changed to ID and ** the parse is retried before an error is thrown. */ #ifdef YYFALLBACK static const YYCODETYPE yyFallback[] = { %% }; #endif /* YYFALLBACK */ /* The following structure represents a single element of the ** parser's stack. Information stored includes: ** ** + The state number for the parser at this level of the stack. ** ** + The value of the token stored at this level of the stack. ** (In other words, the "major" token.) ** ** + The semantic value stored at this level of the stack. This is ** the information used by the action routines in the grammar. ** It is sometimes called the "minor" token. */ struct yyStackEntry { int stateno; /* The state-number */ int major; /* The major token value. This is the code ** number for the token at this stack level */ YYMINORTYPE minor; /* The user-supplied minor token value. This ** is the value of the token */ }; typedef struct yyStackEntry yyStackEntry; /* The state of the parser is completely contained in an instance of ** the following structure */ struct yyParser { int yyidx; /* Index of top element in stack */ int yyerrcnt; /* Shifts left before out of the error */ ParseARG_SDECL /* A place to hold %extra_argument */ yyStackEntry yystack[YYSTACKDEPTH]; /* The parser's stack */ }; typedef struct yyParser yyParser; #ifndef NDEBUG #include static FILE *yyTraceFILE = 0; static char *yyTracePrompt = 0; #endif /* NDEBUG */ #ifndef NDEBUG /* ** Turn parser tracing on by giving a stream to which to write the trace ** and a prompt to preface each trace message. Tracing is turned off ** by making either argument NULL ** ** Inputs: **
        **
      • A FILE* to which trace output should be written. ** If NULL, then tracing is turned off. **
      • A prefix string written at the beginning of every ** line of trace output. If NULL, then tracing is ** turned off. **
      ** ** Outputs: ** None. */ void ParseTrace(FILE *TraceFILE, char *zTracePrompt){ yyTraceFILE = TraceFILE; yyTracePrompt = zTracePrompt; if( yyTraceFILE==0 ) yyTracePrompt = 0; else if( yyTracePrompt==0 ) yyTraceFILE = 0; } #endif /* NDEBUG */ #ifndef NDEBUG /* For tracing shifts, the names of all terminals and nonterminals ** are required. The following table supplies these names */ static const char *const yyTokenName[] = { %% }; #endif /* NDEBUG */ #ifndef NDEBUG /* For tracing reduce actions, the names of all rules are required. */ static const char *const yyRuleName[] = { %% }; #endif /* NDEBUG */ /* ** This function returns the symbolic name associated with a token ** value. */ const char *ParseTokenName(int tokenType){ #ifndef NDEBUG if( tokenType>0 && tokenType<(sizeof(yyTokenName)/sizeof(yyTokenName[0])) ){ return yyTokenName[tokenType]; }else{ return "Unknown"; } #else return ""; #endif } /* ** This function allocates a new parser. ** The only argument is a pointer to a function which works like ** malloc. ** ** Inputs: ** A pointer to the function used to allocate memory. ** ** Outputs: ** A pointer to a parser. This pointer is used in subsequent calls ** to Parse and ParseFree. */ void *ParseAlloc(void *(*mallocProc)(size_t)){ yyParser *pParser; pParser = (yyParser*)(*mallocProc)( (size_t)sizeof(yyParser) ); if( pParser ){ pParser->yyidx = -1; } return pParser; } /* The following function deletes the value associated with a ** symbol. The symbol can be either a terminal or nonterminal. ** "yymajor" is the symbol code, and "yypminor" is a pointer to ** the value. */ static void yy_destructor(YYCODETYPE yymajor, YYMINORTYPE *yypminor){ switch( yymajor ){ /* Here is inserted the actions which take place when a ** terminal or non-terminal is destroyed. This can happen ** when the symbol is popped from the stack during a ** reduce or during error processing or when a parser is ** being destroyed before it is finished parsing. ** ** Note: during a reduce, the only symbols destroyed are those ** which appear on the RHS of the rule, but which are not used ** inside the C code. */ %% default: break; /* If no destructor action specified: do nothing */ } } /* ** Pop the parser's stack once. ** ** If there is a destructor routine associated with the token which ** is popped from the stack, then call it. ** ** Return the major token number for the symbol popped. */ static int yy_pop_parser_stack(yyParser *pParser){ YYCODETYPE yymajor; yyStackEntry *yytos = &pParser->yystack[pParser->yyidx]; if( pParser->yyidx<0 ) return 0; #ifndef NDEBUG if( yyTraceFILE && pParser->yyidx>=0 ){ fprintf(yyTraceFILE,"%sPopping %s\n", yyTracePrompt, yyTokenName[yytos->major]); } #endif yymajor = yytos->major; yy_destructor( yymajor, &yytos->minor); pParser->yyidx--; return yymajor; } /* ** Deallocate and destroy a parser. Destructors are all called for ** all stack elements before shutting the parser down. ** ** Inputs: **
        **
      • A pointer to the parser. This should be a pointer ** obtained from ParseAlloc. **
      • A pointer to a function used to reclaim memory obtained ** from malloc. **
      */ void ParseFree( void *p, /* The parser to be deleted */ void (*freeProc)(void*) /* Function used to reclaim memory */ ){ yyParser *pParser = (yyParser*)p; if( pParser==0 ) return; while( pParser->yyidx>=0 ) yy_pop_parser_stack(pParser); (*freeProc)((void*)pParser); } /* ** Find the appropriate action for a parser given the terminal ** look-ahead token iLookAhead. ** ** If the look-ahead token is YYNOCODE, then check to see if the action is ** independent of the look-ahead. If it is, return the action, otherwise ** return YY_NO_ACTION. */ static int yy_find_shift_action( yyParser *pParser, /* The parser */ int iLookAhead /* The look-ahead token */ ){ int i; int stateno = pParser->yystack[pParser->yyidx].stateno; if( stateno>YY_SHIFT_MAX || (i = yy_shift_ofst[stateno])==YY_SHIFT_USE_DFLT ){ return yy_default[stateno]; } if( iLookAhead==YYNOCODE ){ return YY_NO_ACTION; } i += iLookAhead; if( i<0 || i>=YY_SZ_ACTTAB || yy_lookahead[i]!=iLookAhead ){ #ifdef YYFALLBACK int iFallback; /* Fallback token */ if( iLookAhead %s\n", yyTracePrompt, yyTokenName[iLookAhead], yyTokenName[iFallback]); } #endif return yy_find_shift_action(pParser, iFallback); } #endif return yy_default[stateno]; }else{ return yy_action[i]; } } /* ** Find the appropriate action for a parser given the non-terminal ** look-ahead token iLookAhead. ** ** If the look-ahead token is YYNOCODE, then check to see if the action is ** independent of the look-ahead. If it is, return the action, otherwise ** return YY_NO_ACTION. */ static int yy_find_reduce_action( int stateno, /* Current state number */ int iLookAhead /* The look-ahead token */ ){ int i; /* int stateno = pParser->yystack[pParser->yyidx].stateno; */ if( stateno>YY_REDUCE_MAX || (i = yy_reduce_ofst[stateno])==YY_REDUCE_USE_DFLT ){ return yy_default[stateno]; } if( iLookAhead==YYNOCODE ){ return YY_NO_ACTION; } i += iLookAhead; if( i<0 || i>=YY_SZ_ACTTAB || yy_lookahead[i]!=iLookAhead ){ return yy_default[stateno]; }else{ return yy_action[i]; } } /* ** Perform a shift action. */ static void yy_shift( yyParser *yypParser, /* The parser to be shifted */ int yyNewState, /* The new state to shift in */ int yyMajor, /* The major token to shift in */ YYMINORTYPE *yypMinor /* Pointer ot the minor token to shift in */ ){ yyStackEntry *yytos; yypParser->yyidx++; if( yypParser->yyidx>=YYSTACKDEPTH ){ ParseARG_FETCH; yypParser->yyidx--; #ifndef NDEBUG if( yyTraceFILE ){ fprintf(yyTraceFILE,"%sStack Overflow!\n",yyTracePrompt); } #endif while( yypParser->yyidx>=0 ) yy_pop_parser_stack(yypParser); /* Here code is inserted which will execute if the parser ** stack every overflows */ %% ParseARG_STORE; /* Suppress warning about unused %extra_argument var */ return; } yytos = &yypParser->yystack[yypParser->yyidx]; yytos->stateno = yyNewState; yytos->major = yyMajor; yytos->minor = *yypMinor; #ifndef NDEBUG if( yyTraceFILE && yypParser->yyidx>0 ){ int i; fprintf(yyTraceFILE,"%sShift %d\n",yyTracePrompt,yyNewState); fprintf(yyTraceFILE,"%sStack:",yyTracePrompt); for(i=1; i<=yypParser->yyidx; i++) fprintf(yyTraceFILE," %s",yyTokenName[yypParser->yystack[i].major]); fprintf(yyTraceFILE,"\n"); } #endif } /* The following table contains information about every rule that ** is used during the reduce. */ static const struct { YYCODETYPE lhs; /* Symbol on the left-hand side of the rule */ unsigned char nrhs; /* Number of right-hand side symbols in the rule */ } yyRuleInfo[] = { %% }; static void yy_accept(yyParser*); /* Forward Declaration */ /* ** Perform a reduce action and the shift that must immediately ** follow the reduce. */ static void yy_reduce( yyParser *yypParser, /* The parser */ int yyruleno /* Number of the rule by which to reduce */ ){ int yygoto; /* The next state */ int yyact; /* The next action */ YYMINORTYPE yygotominor; /* The LHS of the rule reduced */ yyStackEntry *yymsp; /* The top of the parser's stack */ int yysize; /* Amount to pop the stack */ ParseARG_FETCH; yymsp = &yypParser->yystack[yypParser->yyidx]; #ifndef NDEBUG if( yyTraceFILE && yyruleno>=0 && yyruleno ** { ... } // User supplied code ** #line ** break; */ %% }; yygoto = yyRuleInfo[yyruleno].lhs; yysize = yyRuleInfo[yyruleno].nrhs; yypParser->yyidx -= yysize; yyact = yy_find_reduce_action(yymsp[-yysize].stateno,yygoto); if( yyact < YYNSTATE ){ #ifdef NDEBUG /* If we are not debugging and the reduce action popped at least ** one element off the stack, then we can push the new element back ** onto the stack here, and skip the stack overflow test in yy_shift(). ** That gives a significant speed improvement. */ if( yysize ){ yypParser->yyidx++; yymsp -= yysize-1; yymsp->stateno = yyact; yymsp->major = yygoto; yymsp->minor = yygotominor; }else #endif { yy_shift(yypParser,yyact,yygoto,&yygotominor); } }else if( yyact == YYNSTATE + YYNRULE + 1 ){ yy_accept(yypParser); } } /* ** The following code executes when the parse fails */ static void yy_parse_failed( yyParser *yypParser /* The parser */ ){ ParseARG_FETCH; #ifndef NDEBUG if( yyTraceFILE ){ fprintf(yyTraceFILE,"%sFail!\n",yyTracePrompt); } #endif while( yypParser->yyidx>=0 ) yy_pop_parser_stack(yypParser); /* Here code is inserted which will be executed whenever the ** parser fails */ %% ParseARG_STORE; /* Suppress warning about unused %extra_argument variable */ } /* ** The following code executes when a syntax error first occurs. */ static void yy_syntax_error( yyParser *yypParser, /* The parser */ int yymajor, /* The major type of the error token */ YYMINORTYPE yyminor /* The minor type of the error token */ ){ ParseARG_FETCH; #define TOKEN (yyminor.yy0) %% ParseARG_STORE; /* Suppress warning about unused %extra_argument variable */ } /* ** The following is executed when the parser accepts */ static void yy_accept( yyParser *yypParser /* The parser */ ){ ParseARG_FETCH; #ifndef NDEBUG if( yyTraceFILE ){ fprintf(yyTraceFILE,"%sAccept!\n",yyTracePrompt); } #endif while( yypParser->yyidx>=0 ) yy_pop_parser_stack(yypParser); /* Here code is inserted which will be executed whenever the ** parser accepts */ %% ParseARG_STORE; /* Suppress warning about unused %extra_argument variable */ } /* The main parser program. ** The first argument is a pointer to a structure obtained from ** "ParseAlloc" which describes the current state of the parser. ** The second argument is the major token number. The third is ** the minor token. The fourth optional argument is whatever the ** user wants (and specified in the grammar) and is available for ** use by the action routines. ** ** Inputs: **
        **
      • A pointer to the parser (an opaque structure.) **
      • The major token number. **
      • The minor token number. **
      • An option argument of a grammar-specified type. **
      ** ** Outputs: ** None. */ void Parse( void *yyp, /* The parser */ int yymajor, /* The major token code number */ ParseTOKENTYPE yyminor /* The value for the token */ ParseARG_PDECL /* Optional %extra_argument parameter */ ){ YYMINORTYPE yyminorunion; int yyact; /* The parser action. */ int yyendofinput; /* True if we are at the end of input */ int yyerrorhit = 0; /* True if yymajor has invoked an error */ yyParser *yypParser; /* The parser */ /* (re)initialize the parser, if necessary */ yypParser = (yyParser*)yyp; if( yypParser->yyidx<0 ){ /* if( yymajor==0 ) return; // not sure why this was here... */ yypParser->yyidx = 0; yypParser->yyerrcnt = -1; yypParser->yystack[0].stateno = 0; yypParser->yystack[0].major = 0; } yyminorunion.yy0 = yyminor; yyendofinput = (yymajor==0); ParseARG_STORE; #ifndef NDEBUG if( yyTraceFILE ){ fprintf(yyTraceFILE,"%sInput %s\n",yyTracePrompt,yyTokenName[yymajor]); } #endif do{ yyact = yy_find_shift_action(yypParser,yymajor); if( yyactyyerrcnt--; if( yyendofinput && yypParser->yyidx>=0 ){ yymajor = 0; }else{ yymajor = YYNOCODE; } }else if( yyact < YYNSTATE + YYNRULE ){ yy_reduce(yypParser,yyact-YYNSTATE); }else if( yyact == YY_ERROR_ACTION ){ int yymx; #ifndef NDEBUG if( yyTraceFILE ){ fprintf(yyTraceFILE,"%sSyntax Error!\n",yyTracePrompt); } #endif #ifdef YYERRORSYMBOL /* A syntax error has occurred. ** The response to an error depends upon whether or not the ** grammar defines an error token "ERROR". ** ** This is what we do if the grammar does define ERROR: ** ** * Call the %syntax_error function. ** ** * Begin popping the stack until we enter a state where ** it is legal to shift the error symbol, then shift ** the error symbol. ** ** * Set the error count to three. ** ** * Begin accepting and shifting new tokens. No new error ** processing will occur until three tokens have been ** shifted successfully. ** */ if( yypParser->yyerrcnt<0 ){ yy_syntax_error(yypParser,yymajor,yyminorunion); } yymx = yypParser->yystack[yypParser->yyidx].major; if( yymx==YYERRORSYMBOL || yyerrorhit ){ #ifndef NDEBUG if( yyTraceFILE ){ fprintf(yyTraceFILE,"%sDiscard input token %s\n", yyTracePrompt,yyTokenName[yymajor]); } #endif yy_destructor(yymajor,&yyminorunion); yymajor = YYNOCODE; }else{ while( yypParser->yyidx >= 0 && yymx != YYERRORSYMBOL && (yyact = yy_find_reduce_action( yypParser->yystack[yypParser->yyidx].stateno, YYERRORSYMBOL)) >= YYNSTATE ){ yy_pop_parser_stack(yypParser); } if( yypParser->yyidx < 0 || yymajor==0 ){ yy_destructor(yymajor,&yyminorunion); yy_parse_failed(yypParser); yymajor = YYNOCODE; }else if( yymx!=YYERRORSYMBOL ){ YYMINORTYPE u2; u2.YYERRSYMDT = 0; yy_shift(yypParser,yyact,YYERRORSYMBOL,&u2); } } yypParser->yyerrcnt = 3; yyerrorhit = 1; #else /* YYERRORSYMBOL is not defined */ /* This is what we do if the grammar does not define ERROR: ** ** * Report an error message, and throw away the input token. ** ** * If the input token is $, then fail the parse. ** ** As before, subsequent error messages are suppressed until ** three input tokens have been successfully shifted. */ if( yypParser->yyerrcnt<=0 ){ yy_syntax_error(yypParser,yymajor,yyminorunion); } yypParser->yyerrcnt = 3; yy_destructor(yymajor,&yyminorunion); if( yyendofinput ){ yy_parse_failed(yypParser); } yymajor = YYNOCODE; #endif }else{ yy_accept(yypParser); yymajor = YYNOCODE; } }while( yymajor!=YYNOCODE && yypParser->yyidx>=0 ); return; } tkHTML-4ee7aaa953d6cb59/tools/makeheaders.c000064400000000000000000002612761151224263100177100ustar00nobodynobody/* ** This program scans C and C++ source files and automatically generates ** appropriate header files. ** %Z% %P% %I% %G% %Z% */ #include #include #include #include #include #include #ifndef WIN32 # include #else # include #endif /* ** Macros for debugging. */ #ifdef DEBUG static int debugMask = 0; # define debug0(F,M) if( (F)&debugMask ){ fprintf(stderr,M); } # define debug1(F,M,A) if( (F)&debugMask ){ fprintf(stderr,M,A); } # define debug2(F,M,A,B) if( (F)&debugMask ){ fprintf(stderr,M,A,B); } # define debug3(F,M,A,B,C) if( (F)&debugMask ){ fprintf(stderr,M,A,B,C); } # define PARSER 0x00000001 # define DECL_DUMP 0x00000002 # define TOKENIZER 0x00000004 #else # define debug0(Flags, Format) # define debug1(Flags, Format, A) # define debug2(Flags, Format, A, B) # define debug3(Flags, Format, A, B, C) #endif /* ** The following macros are purely for the purpose of testing this ** program on itself. They don't really contribute to the code. */ #define INTERFACE 1 #define EXPORT_INTERFACE 1 #define EXPORT /* ** Each token in a source file is represented by an instance of ** the following structure. Tokens are collected onto a list. */ typedef struct Token Token; struct Token { const char *zText; /* The text of the token */ int nText; /* Number of characters in the token's text */ int eType; /* The type of this token */ int nLine; /* The line number on which the token starts */ Token *pComment; /* Most recent block comment before this token */ Token *pNext; /* Next token on the list */ Token *pPrev; /* Previous token on the list */ }; /* ** During tokenization, information about the state of the input ** stream is held in an instance of the following structure */ typedef struct InStream InStream; struct InStream { const char *z; /* Complete text of the input */ int i; /* Next character to read from the input */ int nLine; /* The line number for character z[i] */ }; /* ** Each declaration in the C or C++ source files is parsed out and stored as ** an instance of the following structure. ** ** A "forward declaration" is a declaration that an object exists that ** doesn't tell about the objects structure. A typical forward declaration ** is: ** ** struct Xyzzy; ** ** Not every object has a forward declaration. If it does, thought, the ** forward declaration will be contained in the zFwd field for C and ** the zFwdCpp for C++. The zDecl field contains the complete ** declaration text. */ typedef struct Decl Decl; struct Decl { char *zName; /* Name of the object being declared. The appearance ** of this name is a source file triggers the declaration ** to be added to the header for that file. */ char *zFile; /* File from which extracted. */ char *zIf; /* Surround the declaration with this #if */ char *zFwd; /* A forward declaration. NULL if there is none. */ char *zFwdCpp; /* Use this forward declaration for C++. */ char *zDecl; /* A full declaration of this object */ struct Include *pInclude; /* #includes that come before this declaration */ int flags; /* See the "Properties" below */ Token *pComment; /* A block comment associated with this declaration */ Token tokenCode; /* Implementation of functions and procedures */ Decl *pSameName; /* Next declaration with the same "zName" */ Decl *pSameHash; /* Next declaration with same hash but different zName */ Decl *pNext; /* Next declaration with a different name */ }; /* ** Properties associated with declarations. ** ** DP_Forward and DP_Declared are used during the generation of a single ** header file in order to prevent duplicate declarations and definitions. ** DP_Forward is set after the object has been given a forward declaration ** and DP_Declared is set after the object gets a full declarations. ** (Example: A forward declaration is "typedef struct Abc Abc;" and the ** full declaration is "struct Abc { int a; float b; };".) ** ** The DP_Export and DP_Local flags are more permanent. They mark objects ** that have EXPORT scope and LOCAL scope respectively. If both of these ** marks are missing, then the object has library scope. The meanings of ** the scopes are as follows: ** ** LOCAL scope The object is only usable within the file in ** which it is declared. ** ** library scope The object is visible and usable within other ** files in the same project. By if the project is ** a library, then the object is not visible to users ** of the library. (i.e. the object does not appear ** in the output when using the -H option.) ** ** EXPORT scope The object is visible and usable everywhere. ** ** The DP_Flag is a temporary use flag that is used during processing to ** prevent an infinite loop. It's use is localized. ** ** The DP_Cplusplus, DP_ExternCReqd and DP_ExternReqd flags are permanent ** and are used to specify what type of declaration the object requires. */ #define DP_Forward 0x001 /* Has a forward declaration in this file */ #define DP_Declared 0x002 /* Has a full declaration in this file */ #define DP_Export 0x004 /* Export this declaration */ #define DP_Local 0x008 /* Declare in its home file only */ #define DP_Flag 0x010 /* Use to mark a subset of a Decl list ** for special processing */ #define DP_Cplusplus 0x020 /* Has C++ linkage and cannot appear in a ** C header file */ #define DP_ExternCReqd 0x040 /* Prepend 'extern "C"' in a C++ header. ** Prepend nothing in a C header */ #define DP_ExternReqd 0x080 /* Prepend 'extern "C"' in a C++ header if ** DP_Cplusplus is not also set. If DP_Cplusplus ** is set or this is a C header then ** prepend 'extern' */ /* ** Convenience macros for dealing with declaration properties */ #define DeclHasProperty(D,P) (((D)->flags&(P))==(P)) #define DeclHasAnyProperty(D,P) (((D)->flags&(P))!=0) #define DeclSetProperty(D,P) (D)->flags |= (P) #define DeclClearProperty(D,P) (D)->flags &= ~(P) /* ** These are state properties of the parser. Each of the values is ** distinct from the DP_ values above so that both can be used in ** the same "flags" field. ** ** Be careful not to confuse PS_Export with DP_Export or ** PS_Local with DP_Local. Their names are similar, but the meanings ** of these flags are very different. */ #define PS_Extern 0x000800 /* "extern" has been seen */ #define PS_Export 0x001000 /* If between "#if EXPORT_INTERFACE" ** and "#endif" */ #define PS_Export2 0x002000 /* If "EXPORT" seen */ #define PS_Typedef 0x004000 /* If "typedef" has been seen */ #define PS_Static 0x008000 /* If "static" has been seen */ #define PS_Interface 0x010000 /* If within #if INTERFACE..#endif */ #define PS_Method 0x020000 /* If "::" token has been seen */ #define PS_Local 0x040000 /* If within #if LOCAL_INTERFACE..#endif */ #define PS_Local2 0x080000 /* If "LOCAL" seen. */ /* ** The following set of flags are ORed into the "flags" field of ** a Decl in order to identify what type of object is being ** declared. */ #define TY_Class 0x00100000 #define TY_Subroutine 0x00200000 #define TY_Macro 0x00400000 #define TY_Typedef 0x00800000 #define TY_Variable 0x01000000 #define TY_Structure 0x02000000 #define TY_Union 0x04000000 #define TY_Enumeration 0x08000000 #define TY_Defunct 0x10000000 /* Used to erase a declaration */ /* ** Each nested #if (or #ifdef or #ifndef) is stored in a stack of ** instances of the following structure. */ typedef struct Ifmacro Ifmacro; struct Ifmacro { int nLine; /* Line number where this macro occurs */ char *zCondition; /* Text of the condition for this macro */ Ifmacro *pNext; /* Next down in the stack */ int flags; /* Can hold PS_Export, PS_Interface or PS_Local flags */ }; /* ** When parsing a file, we need to keep track of what other files have ** be #include-ed. For each #include found, we create an instance of ** the following structure. */ typedef struct Include Include; struct Include { char *zFile; /* The name of file include. Includes "" or <> */ char *zIf; /* If not NULL, #include should be enclosed in #if */ char *zLabel; /* A unique label used to test if this #include has * appeared already in a file or not */ Include *pNext; /* Previous include file, or NULL if this is the first */ }; /* ** Identifiers found in a source file that might be used later to provoke ** the copying of a declaration into the corresponding header file are ** stored in a hash table as instances of the following structure. */ typedef struct Ident Ident; struct Ident { char *zName; /* The text of this identifier */ Ident *pCollide; /* Next identifier with the same hash */ Ident *pNext; /* Next identifier in a list of them all */ }; /* ** A complete table of identifiers is stored in an instance of ** the next structure. */ #define IDENT_HASH_SIZE 2237 typedef struct IdentTable IdentTable; struct IdentTable { Ident *pList; /* List of all identifiers in this table */ Ident *apTable[IDENT_HASH_SIZE]; /* The hash table */ }; /* ** The following structure holds all information for a single ** source file named on the command line of this program. */ typedef struct InFile InFile; struct InFile { char *zSrc; /* Name of input file */ char *zHdr; /* Name of the generated .h file for this input. ** Will be NULL if input is to be scanned only */ int flags; /* One or more DP_, PS_ and/or TY_ flags */ InFile *pNext; /* Next input file in the list of them all */ IdentTable idTable; /* All identifiers in this input file */ }; /* ** An unbounded string is able to grow without limit. We use these ** to construct large in-memory strings from lots of smaller components. */ typedef struct String String; struct String { int nAlloc; /* Number of bytes allocated */ int nUsed; /* Number of bytes used (not counting null terminator) */ char *zText; /* Text of the string */ }; /* ** The following structure contains a lot of state information used ** while generating a .h file. We put the information in this structure ** and pass around a pointer to this structure, rather than pass around ** all of the information separately. This helps reduce the number of ** arguments to generator functions. */ typedef struct GenState GenState; struct GenState { String *pStr; /* Write output to this string */ IdentTable *pTable; /* A table holding the zLabel of every #include that * has already been generated. Used to avoid * generating duplicate #includes. */ const char *zIf; /* If not NULL, then we are within a #if with * this argument. */ int nErr; /* Number of errors */ const char *zFilename; /* Name of the source file being scanned */ int flags; /* Various flags (DP_ and PS_ flags above) */ }; /* ** The following text line appears at the top of every file generated ** by this program. By recognizing this line, the program can be sure ** never to read a file that it generated itself. */ const char zTopLine[] = "/* \aThis file was automatically generated. Do not edit! */\n"; #define nTopLine (sizeof(zTopLine)-1) /* ** The name of the file currently being parsed. */ static char *zFilename; /* ** The stack of #if macros for the file currently being parsed. */ static Ifmacro *ifStack = 0; /* ** A list of all files that have been #included so far in a file being ** parsed. */ static Include *includeList = 0; /* ** The last block comment seen. */ static Token *blockComment = 0; /* ** The following flag is set if the -doc flag appears on the ** command line. */ static int doc_flag = 0; /* ** If the following flag is set, then makeheaders will attempt to ** generate prototypes for static functions and procedures. */ static int proto_static = 0; /* ** A list of all declarations. The list is held together using the ** pNext field of the Decl structure. */ static Decl *pDeclFirst; /* First on the list */ static Decl *pDeclLast; /* Last on the list */ /* ** A hash table of all declarations */ #define DECL_HASH_SIZE 3371 static Decl *apTable[DECL_HASH_SIZE]; /* ** The TEST macro must be defined to something. Make sure this is the ** case. */ #ifndef TEST # define TEST 0 #endif #ifdef NOT_USED /* ** We do our own assertion macro so that we can have more control ** over debugging. */ #define Assert(X) if(!(X)){ CantHappen(__LINE__); } #define CANT_HAPPEN CantHappen(__LINE__) static void CantHappen(int iLine){ fprintf(stderr,"Assertion failed on line %d\n",iLine); *(char*)1 = 0; /* Force a core-dump */ } #endif /* ** Memory allocation functions that are guaranteed never to return NULL. */ static void *SafeMalloc(int nByte){ void *p = malloc( nByte ); if( p==0 ){ fprintf(stderr,"Out of memory. Can't allocate %d bytes.\n",nByte); exit(1); } return p; } static void SafeFree(void *pOld){ if( pOld ){ free(pOld); } } static void *SafeRealloc(void *pOld, int nByte){ void *p; if( pOld==0 ){ p = SafeMalloc(nByte); }else{ p = realloc(pOld, nByte); if( p==0 ){ fprintf(stderr, "Out of memory. Can't enlarge an allocation to %d bytes\n",nByte); exit(1); } } return p; } static char *StrDup(const char *zSrc, int nByte){ char *zDest; if( nByte<=0 ){ nByte = strlen(zSrc); } zDest = SafeMalloc( nByte + 1 ); strncpy(zDest,zSrc,nByte); zDest[nByte] = 0; return zDest; } /* ** Return TRUE if the character X can be part of an identifier */ #define ISALNUM(X) ((X)=='_' || isalnum(X)) /* ** Routines for dealing with unbounded strings. */ static void StringInit(String *pStr){ pStr->nAlloc = 0; pStr->nUsed = 0; pStr->zText = 0; } static void StringReset(String *pStr){ SafeFree(pStr->zText); StringInit(pStr); } static void StringAppend(String *pStr, const char *zText, int nByte){ if( nByte<=0 ){ nByte = strlen(zText); } if( pStr->nUsed + nByte >= pStr->nAlloc ){ if( pStr->nAlloc==0 ){ pStr->nAlloc = nByte + 100; pStr->zText = SafeMalloc( pStr->nAlloc ); }else{ pStr->nAlloc = pStr->nAlloc*2 + nByte; pStr->zText = SafeRealloc(pStr->zText, pStr->nAlloc); } } strncpy(&pStr->zText[pStr->nUsed],zText,nByte); pStr->nUsed += nByte; pStr->zText[pStr->nUsed] = 0; } #define StringGet(S) ((S)->zText?(S)->zText:"") /* ** Compute a hash on a string. The number returned is a non-negative ** value between 0 and 2**31 - 1 */ static int Hash(const char *z, int n){ int h = 0; if( n<=0 ){ n = strlen(z); } while( n-- ){ h = h ^ (h<<5) ^ *z++; } if( h<0 ) h = -h; return h; } /* ** Given an identifier name, try to find a declaration for that ** identifier in the hash table. If found, return a pointer to ** the Decl structure. If not found, return 0. */ static Decl *FindDecl(const char *zName, int len){ int h; Decl *p; if( len<=0 ){ len = strlen(zName); } h = Hash(zName,len) % DECL_HASH_SIZE; p = apTable[h]; while( p && (strncmp(p->zName,zName,len)!=0 || p->zName[len]!=0) ){ p = p->pSameHash; } return p; } /* ** Install the given declaration both in the hash table and on ** the list of all declarations. */ static void InstallDecl(Decl *pDecl){ int h; Decl *pOther; h = Hash(pDecl->zName,0) % DECL_HASH_SIZE; pOther = apTable[h]; while( pOther && strcmp(pDecl->zName,pOther->zName)!=0 ){ pOther = pOther->pSameHash; } if( pOther ){ pDecl->pSameName = pOther->pSameName; pOther->pSameName = pDecl; }else{ pDecl->pSameName = 0; pDecl->pSameHash = apTable[h]; apTable[h] = pDecl; } pDecl->pNext = 0; if( pDeclFirst==0 ){ pDeclFirst = pDeclLast = pDecl; }else{ pDeclLast->pNext = pDecl; pDeclLast = pDecl; } } /* ** Look at the current ifStack. If anything declared at the current ** position must be surrounded with ** ** #if STUFF ** #endif ** ** Then this routine computes STUFF and returns a pointer to it. Memory ** to hold the value returned is obtained from malloc(). */ static char *GetIfString(void){ Ifmacro *pIf; char *zResult = 0; int hasIf = 0; String str; for(pIf = ifStack; pIf; pIf=pIf->pNext){ if( pIf->zCondition==0 || *pIf->zCondition==0 ) continue; if( !hasIf ){ hasIf = 1; StringInit(&str); }else{ StringAppend(&str," && ",4); } StringAppend(&str,pIf->zCondition,0); } if( hasIf ){ zResult = StrDup(StringGet(&str),0); StringReset(&str); }else{ zResult = 0; } return zResult; } /* ** Create a new declaration and put it in the hash table. Also ** return a pointer to it so that we can fill in the zFwd and zDecl ** fields, and so forth. */ static Decl *CreateDecl( const char *zName, /* Name of the object being declared. */ int nName /* Length of the name */ ){ Decl *pDecl; pDecl = SafeMalloc( sizeof(Decl) + nName + 1); memset(pDecl,0,sizeof(Decl)); pDecl->zName = (char*)&pDecl[1]; sprintf(pDecl->zName,"%.*s",nName,zName); pDecl->zFile = zFilename; pDecl->pInclude = includeList; pDecl->zIf = GetIfString(); InstallDecl(pDecl); return pDecl; } /* ** Insert a new identifier into an table of identifiers. Return TRUE if ** a new identifier was inserted and return FALSE if the identifier was ** already in the table. */ static int IdentTableInsert( IdentTable *pTable, /* The table into which we will insert */ const char *zId, /* Name of the identifiers */ int nId /* Length of the identifier name */ ){ int h; Ident *pId; if( nId<=0 ){ nId = strlen(zId); } h = Hash(zId,nId) % IDENT_HASH_SIZE; for(pId = pTable->apTable[h]; pId; pId=pId->pCollide){ if( strncmp(zId,pId->zName,nId)==0 && pId->zName[nId]==0 ){ /* printf("Already in table: %.*s\n",nId,zId); */ return 0; } } pId = SafeMalloc( sizeof(Ident) + nId + 1 ); pId->zName = (char*)&pId[1]; sprintf(pId->zName,"%.*s",nId,zId); pId->pNext = pTable->pList; pTable->pList = pId; pId->pCollide = pTable->apTable[h]; pTable->apTable[h] = pId; /* printf("Add to table: %.*s\n",nId,zId); */ return 1; } /* ** Check to see if the given value is in the given IdentTable. Return ** true if it is and false if it is not. */ static int IdentTableTest( IdentTable *pTable, /* The table in which to search */ const char *zId, /* Name of the identifiers */ int nId /* Length of the identifier name */ ){ int h; Ident *pId; if( nId<=0 ){ nId = strlen(zId); } h = Hash(zId,nId) % IDENT_HASH_SIZE; for(pId = pTable->apTable[h]; pId; pId=pId->pCollide){ if( strncmp(zId,pId->zName,nId)==0 && pId->zName[nId]==0 ){ return 1; } } return 0; } /* ** Remove every identifier from the given table. Reset the table to ** its initial state. */ static void IdentTableReset(IdentTable *pTable){ Ident *pId, *pNext; for(pId = pTable->pList; pId; pId = pNext){ pNext = pId->pNext; SafeFree(pId); } memset(pTable,0,sizeof(IdentTable)); } #ifdef DEBUG /* ** Print the name of every identifier in the given table, one per line */ static void IdentTablePrint(IdentTable *pTable, FILE *pOut){ Ident *pId; for(pId = pTable->pList; pId; pId = pId->pNext){ fprintf(pOut,"%s\n",pId->zName); } } #endif /* ** Read an entire file into memory. Return a pointer to the memory. ** ** The memory is obtained from SafeMalloc and must be freed by the ** calling function. ** ** If the read fails for any reason, 0 is returned. */ static char *ReadFile(const char *zFilename){ struct stat sStat; FILE *pIn; char *zBuf; int n; if( stat(zFilename,&sStat)!=0 #ifndef WIN32 || !S_ISREG(sStat.st_mode) #endif ){ return 0; } pIn = fopen(zFilename,"r"); if( pIn==0 ){ return 0; } zBuf = SafeMalloc( sStat.st_size + 1 ); n = fread(zBuf,1,sStat.st_size,pIn); zBuf[n] = 0; fclose(pIn); return zBuf; } /* ** Write the contents of a string into a file. Return the number of ** errors */ static int WriteFile(const char *zFilename, const char *zOutput){ FILE *pOut; pOut = fopen(zFilename,"w"); if( pOut==0 ){ return 1; } fwrite(zOutput,1,strlen(zOutput),pOut); fclose(pOut); return 0; } /* ** Major token types */ #define TT_Space 1 /* Contiguous white space */ #define TT_Id 2 /* An identifier */ #define TT_Preprocessor 3 /* Any C preprocessor directive */ #define TT_Comment 4 /* Either C or C++ style comment */ #define TT_Number 5 /* Any numeric constant */ #define TT_String 6 /* String or character constants. ".." or '.' */ #define TT_Braces 7 /* All text between { and a matching } */ #define TT_EOF 8 /* End of file */ #define TT_Error 9 /* An error condition */ #define TT_BlockComment 10 /* A C-Style comment at the left margin that * spans multple lines */ #define TT_Other 0 /* None of the above */ /* ** Get a single low-level token from the input file. Update the ** file pointer so that it points to the first character beyond the ** token. ** ** A "low-level token" is any token except TT_Braces. A TT_Braces token ** consists of many smaller tokens and is assembled by a routine that ** calls this one. ** ** The function returns the number of errors. An error is an ** unterminated string or character literal or an unterminated ** comment. ** ** Profiling shows that this routine consumes about half the ** CPU time on a typical run of makeheaders. */ static int GetToken(InStream *pIn, Token *pToken){ int i; const char *z; int cStart; int c; int startLine; /* Line on which a structure begins */ int nlisc = 0; /* True if there is a new-line in a ".." or '..' */ int nErr = 0; /* Number of errors seen */ z = pIn->z; i = pIn->i; pToken->nLine = pIn->nLine; pToken->zText = &z[i]; switch( z[i] ){ case 0: pToken->eType = TT_EOF; pToken->nText = 0; break; case '#': if( i==0 || z[i-1]=='\n' || (i>1 && z[i-1]=='\r' && z[i-2]=='\n')){ /* We found a preprocessor statement */ pToken->eType = TT_Preprocessor; i++; while( z[i]!=0 && z[i]!='\n' ){ if( z[i]=='\\' ){ i++; if( z[i]=='\n' ) pIn->nLine++; } i++; } pToken->nText = i - pIn->i; }else{ /* Just an operator */ pToken->eType = TT_Other; pToken->nText = 1; } break; case ' ': case '\t': case '\r': case '\f': case '\n': while( isspace(z[i]) ){ if( z[i]=='\n' ) pIn->nLine++; i++; } pToken->eType = TT_Space; pToken->nText = i - pIn->i; break; case '\\': pToken->nText = 2; pToken->eType = TT_Other; if( z[i+1]=='\n' ){ pIn->nLine++; pToken->eType = TT_Space; }else if( z[i+1]==0 ){ pToken->nText = 1; } break; case '\'': case '\"': cStart = z[i]; startLine = pIn->nLine; do{ i++; c = z[i]; if( c=='\n' ){ if( !nlisc ){ fprintf(stderr, "%s:%d: (warning) Newline in string or character literal.\n", zFilename, pIn->nLine); nlisc = 1; } pIn->nLine++; } if( c=='\\' ){ i++; c = z[i]; if( c=='\n' ){ pIn->nLine++; } }else if( c==cStart ){ i++; c = 0; }else if( c==0 ){ fprintf(stderr, "%s:%d: Unterminated string or character literal.\n", zFilename, startLine); nErr++; } }while( c ); pToken->eType = TT_String; pToken->nText = i - pIn->i; break; case '/': if( z[i+1]=='/' ){ /* C++ style comment */ while( z[i] && z[i]!='\n' ){ i++; } pToken->eType = TT_Comment; pToken->nText = i - pIn->i; }else if( z[i+1]=='*' ){ /* C style comment */ int isBlockComment = i==0 || z[i-1]=='\n'; i += 2; startLine = pIn->nLine; while( z[i] && (z[i]!='*' || z[i+1]!='/') ){ if( z[i]=='\n' ){ pIn->nLine++; if( isBlockComment ){ if( z[i+1]=='*' || z[i+2]=='*' ){ isBlockComment = 2; }else{ isBlockComment = 0; } } } i++; } if( z[i] ){ i += 2; }else{ isBlockComment = 0; fprintf(stderr,"%s:%d: Unterminated comment\n", zFilename, startLine); nErr++; } pToken->eType = isBlockComment==2 ? TT_BlockComment : TT_Comment; pToken->nText = i - pIn->i; }else{ /* A divide operator */ pToken->eType = TT_Other; pToken->nText = 1; } break; case '0': if( z[i+1]=='x' || z[i+1]=='X' ){ /* A hex constant */ i += 2; while( isxdigit(z[i]) ){ i++; } }else{ /* An octal constant */ while( isdigit(z[i]) ){ i++; } } pToken->eType = TT_Number; pToken->nText = i - pIn->i; break; case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': while( isdigit(z[i]) ){ i++; } if( (c=z[i])=='.' ){ i++; while( isdigit(z[i]) ){ i++; } c = z[i]; if( c=='e' || c=='E' ){ i++; if( ((c=z[i])=='+' || c=='-') && isdigit(z[i+1]) ){ i++; } while( isdigit(z[i]) ){ i++; } c = z[i]; } if( c=='f' || c=='F' || c=='l' || c=='L' ){ i++; } }else if( c=='e' || c=='E' ){ i++; if( ((c=z[i])=='+' || c=='-') && isdigit(z[i+1]) ){ i++; } while( isdigit(z[i]) ){ i++; } }else if( c=='L' || c=='l' ){ i++; c = z[i]; if( c=='u' || c=='U' ){ i++; } }else if( c=='u' || c=='U' ){ i++; c = z[i]; if( c=='l' || c=='L' ){ i++; } } pToken->eType = TT_Number; pToken->nText = i - pIn->i; break; case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g': case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n': case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u': case 'v': case 'w': case 'x': case 'y': case 'z': case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U': case 'V': case 'W': case 'X': case 'Y': case 'Z': case '_': while( isalnum(z[i]) || z[i]=='_' ){ i++; }; pToken->eType = TT_Id; pToken->nText = i - pIn->i; break; default: pToken->eType = TT_Other; pToken->nText = 1; break; } pIn->i += pToken->nText; return nErr; } /* ** This routine recovers the next token from the input file which is ** not a space or a comment or any text between an "#if 0" and "#endif". ** ** This routine returns the number of errors encountered. An error ** is an unterminated token or unmatched "#if 0". ** ** Profiling shows that this routine uses about a quarter of the ** CPU time in a typical run. */ static int GetNonspaceToken(InStream *pIn, Token *pToken){ int nIf = 0; int inZero = 0; const char *z; int value; int startLine; int nErr = 0; startLine = pIn->nLine; while( 1 ){ nErr += GetToken(pIn,pToken); /* printf("%04d: Type=%d nIf=%d [%.*s]\n", pToken->nLine,pToken->eType,nIf,pToken->nText, pToken->eType!=TT_Space ? pToken->zText : ""); */ pToken->pComment = blockComment; switch( pToken->eType ){ case TT_Comment: case TT_Space: break; case TT_BlockComment: if( doc_flag ){ blockComment = SafeMalloc( sizeof(Token) ); *blockComment = *pToken; } break; case TT_EOF: if( nIf ){ fprintf(stderr,"%s:%d: Unterminated \"#if\"\n", zFilename, startLine); nErr++; } return nErr; case TT_Preprocessor: z = &pToken->zText[1]; while( *z==' ' || *z=='\t' ) z++; if( sscanf(z,"if %d",&value)==1 && value==0 ){ nIf++; inZero = 1; }else if( inZero ){ if( strncmp(z,"if",2)==0 ){ nIf++; }else if( strncmp(z,"endif",5)==0 ){ nIf--; if( nIf==0 ) inZero = 0; } }else{ return nErr; } break; default: if( !inZero ){ return nErr; } break; } } /* NOT REACHED */ } /* ** This routine looks for identifiers (strings of contiguous alphanumeric ** characters) within a preprocessor directive and adds every such string ** found to the given identifier table */ static void FindIdentifiersInMacro(Token *pToken, IdentTable *pTable){ Token sToken; InStream sIn; int go = 1; sIn.z = pToken->zText; sIn.i = 1; sIn.nLine = 1; while( go && sIn.i < pToken->nText ){ GetToken(&sIn,&sToken); switch( sToken.eType ){ case TT_Id: IdentTableInsert(pTable,sToken.zText,sToken.nText); break; case TT_EOF: go = 0; break; default: break; } } } /* ** This routine gets the next token. Everything contained within ** {...} is collapsed into a single TT_Braces token. Whitespace is ** omitted. ** ** If pTable is not NULL, then insert every identifier seen into the ** IdentTable. This includes any identifiers seen inside of {...}. ** ** The number of errors encountered is returned. An error is an ** unterminated token. */ static int GetBigToken(InStream *pIn, Token *pToken, IdentTable *pTable){ const char *z, *zStart; int iStart; int nBrace; int c; int nLine; int nErr; nErr = GetNonspaceToken(pIn,pToken); switch( pToken->eType ){ case TT_Id: if( pTable!=0 ){ IdentTableInsert(pTable,pToken->zText,pToken->nText); } return nErr; case TT_Preprocessor: if( pTable!=0 ){ FindIdentifiersInMacro(pToken,pTable); } return nErr; case TT_Other: if( pToken->zText[0]=='{' ) break; return nErr; default: return nErr; } z = pIn->z; iStart = pIn->i; zStart = pToken->zText; nLine = pToken->nLine; nBrace = 1; while( nBrace ){ nErr += GetNonspaceToken(pIn,pToken); /* printf("%04d: nBrace=%d [%.*s]\n",pToken->nLine,nBrace, pToken->nText,pToken->zText); */ switch( pToken->eType ){ case TT_EOF: fprintf(stderr,"%s:%d: Unterminated \"{\"\n", zFilename, nLine); nErr++; pToken->eType = TT_Error; return nErr; case TT_Id: if( pTable ){ IdentTableInsert(pTable,pToken->zText,pToken->nText); } break; case TT_Preprocessor: if( pTable!=0 ){ FindIdentifiersInMacro(pToken,pTable); } break; case TT_Other: if( (c = pToken->zText[0])=='{' ){ nBrace++; }else if( c=='}' ){ nBrace--; } break; default: break; } } pToken->eType = TT_Braces; pToken->nText = 1 + pIn->i - iStart; pToken->zText = zStart; pToken->nLine = nLine; return nErr; } /* ** This routine frees up a list of Tokens. The pComment tokens are ** not cleared by this. So we leak a little memory when using the -doc ** option. So what. */ static void FreeTokenList(Token *pList){ Token *pNext; while( pList ){ pNext = pList->pNext; SafeFree(pList); pList = pNext; } } /* ** Tokenize an entire file. Return a pointer to the list of tokens. ** ** Space for each token is obtained from a separate malloc() call. The ** calling function is responsible for freeing this space. ** ** If pTable is not NULL, then fill the table with all identifiers seen in ** the input file. */ static Token *TokenizeFile(const char *zFile, IdentTable *pTable){ InStream sIn; Token *pFirst = 0, *pLast = 0, *pNew; int nErr = 0; sIn.z = zFile; sIn.i = 0; sIn.nLine = 1; blockComment = 0; while( sIn.z[sIn.i]!=0 ){ pNew = SafeMalloc( sizeof(Token) ); nErr += GetBigToken(&sIn,pNew,pTable); debug3(TOKENIZER, "Token on line %d: [%.*s]\n", pNew->nLine, pNew->nText<50 ? pNew->nText : 50, pNew->zText); if( pFirst==0 ){ pFirst = pLast = pNew; pNew->pPrev = 0; }else{ pLast->pNext = pNew; pNew->pPrev = pLast; pLast = pNew; } if( pNew->eType==TT_EOF ) break; } if( pLast ) pLast->pNext = 0; blockComment = 0; if( nErr ){ FreeTokenList(pFirst); pFirst = 0; } return pFirst; } #if TEST==1 /* ** Use the following routine to test or debug the tokenizer. */ void main(int argc, char **argv){ char *zFile; Token *pList, *p; IdentTable sTable; if( argc!=2 ){ fprintf(stderr,"Usage: %s filename\n",*argv); exit(1); } memset(&sTable,0,sizeof(sTable)); zFile = ReadFile(argv[1]); if( zFile==0 ){ fprintf(stderr,"Can't read file \"%s\"\n",argv[1]); exit(1); } pList = TokenizeFile(zFile,&sTable); for(p=pList; p; p=p->pNext){ int j; switch( p->eType ){ case TT_Space: printf("%4d: Space\n",p->nLine); break; case TT_Id: printf("%4d: Id %.*s\n",p->nLine,p->nText,p->zText); break; case TT_Preprocessor: printf("%4d: Preprocessor %.*s\n",p->nLine,p->nText,p->zText); break; case TT_Comment: printf("%4d: Comment\n",p->nLine); break; case TT_BlockComment: printf("%4d: Block Comment\n",p->nLine); break; case TT_Number: printf("%4d: Number %.*s\n",p->nLine,p->nText,p->zText); break; case TT_String: printf("%4d: String %.*s\n",p->nLine,p->nText,p->zText); break; case TT_Other: printf("%4d: Other %.*s\n",p->nLine,p->nText,p->zText); break; case TT_Braces: for(j=0; jnText && j<30 && p->zText[j]!='\n'; j++){} printf("%4d: Braces %.*s...}\n",p->nLine,j,p->zText); break; case TT_EOF: printf("%4d: End of file\n",p->nLine); break; default: printf("%4d: type %d\n",p->nLine,p->eType); break; } } FreeTokenList(pList); SafeFree(zFile); IdentTablePrint(&sTable,stdout); } #endif #ifdef DEBUG /* ** For debugging purposes, write out a list of tokens. */ static void PrintTokens(Token *pFirst, Token *pLast){ int needSpace = 0; int c; pLast = pLast->pNext; while( pFirst!=pLast ){ switch( pFirst->eType ){ case TT_Preprocessor: printf("\n%.*s\n",pFirst->nText,pFirst->zText); needSpace = 0; break; case TT_Id: case TT_Number: printf("%s%.*s", needSpace ? " " : "", pFirst->nText, pFirst->zText); needSpace = 1; break; default: c = pFirst->zText[0]; printf("%s%.*s", (needSpace && (c=='*' || c=='{')) ? " " : "", pFirst->nText, pFirst->zText); needSpace = pFirst->zText[0]==','; break; } pFirst = pFirst->pNext; } } #endif /* ** Convert a sequence of tokens into a string and return a pointer ** to that string. Space to hold the string is obtained from malloc() ** and must be freed by the calling function. ** ** The characters ";\n" are always appended. */ static char *TokensToString(Token *pFirst, Token *pLast){ char *zReturn; String str; int needSpace = 0; int c; StringInit(&str); pLast = pLast->pNext; while( pFirst!=pLast ){ switch( pFirst->eType ){ case TT_Preprocessor: StringAppend(&str,"\n",1); StringAppend(&str,pFirst->zText,pFirst->nText); StringAppend(&str,"\n",1); needSpace = 0; break; case TT_Id: if( pFirst->nText==6 && pFirst->zText[0]=='E' && strncmp(pFirst->zText,"EXPORT",6)==0 ){ break; } /* Fall thru to the next case */ case TT_Number: if( needSpace ){ StringAppend(&str," ",1); } StringAppend(&str,pFirst->zText,pFirst->nText); needSpace = 1; break; default: c = pFirst->zText[0]; if( needSpace && (c=='*' || c=='{') ){ StringAppend(&str," ",1); } StringAppend(&str,pFirst->zText,pFirst->nText); /* needSpace = pFirst->zText[0]==','; */ needSpace = 0; break; } pFirst = pFirst->pNext; } StringAppend(&str,";\n",2); zReturn = StrDup(StringGet(&str),0); StringReset(&str); return zReturn; } /* ** This routine is called when we see one of the keywords "struct", ** "enum", "union" or "class". This might be the beginning of a ** type declaration. This routine will process the declaration and ** remove the declaration tokens from the input stream. ** ** If this is a type declaration that is immediately followed by a ** semicolon (in other words it isn't also a variable definition) ** then set *pReset to ';'. Otherwise leave *pReset at 0. The ** *pReset flag causes the parser to skip ahead to the next token ** that begins with the value placed in the *pReset flag, if that ** value is different from 0. */ static int ProcessTypeDecl(Token *pList, int flags, int *pReset){ Token *pName, *pEnd; Decl *pDecl; String str; int need_to_collapse = 1; *pReset = 0; if( pList==0 || pList->pNext==0 || pList->pNext->eType!=TT_Id ){ return 0; } pName = pList->pNext; /* Catch the case of "struct Foo;" and skip it. */ if( pName->pNext && pName->pNext->zText[0]==';' ){ *pReset = ';'; return 0; } for(pEnd=pName->pNext; pEnd && pEnd->eType!=TT_Braces; pEnd=pEnd->pNext){ switch( pEnd->zText[0] ){ case '(': case '*': case '[': case '=': case ';': return 0; } } if( pEnd==0 ){ return 0; } /* ** At this point, we know we have a type declaration that is bounded ** by pList and pEnd and has the name pName. */ /* ** If the braces are followed immedately by a semicolon, then we are ** dealing a type declaration only. There is not variable definition ** following the type declaration. So reset... */ if( pEnd->pNext==0 || pEnd->pNext->zText[0]==';' ){ *pReset = ';'; need_to_collapse = 0; }else{ need_to_collapse = 1; } if( proto_static==0 && (flags & (PS_Local|PS_Export|PS_Interface))==0 ){ /* Ignore these objects unless they are explicitly declared as interface, ** or unless the "-local" command line option was specified. */ *pReset = ';'; return 0; } #ifdef DEBUG if( debugMask & PARSER ){ printf("**** Found type: %.*s %.*s...\n", pList->nText, pList->zText, pName->nText, pName->zText); PrintTokens(pList,pEnd); printf(";\n"); } #endif pDecl = CreateDecl(pName->zText,pName->nText); if( (flags & PS_Static) || !(flags & (PS_Interface|PS_Export)) ){ DeclSetProperty(pDecl,DP_Local); } switch( *pList->zText ){ case 'c': DeclSetProperty(pDecl,TY_Class); break; case 's': DeclSetProperty(pDecl,TY_Structure); break; case 'e': DeclSetProperty(pDecl,TY_Enumeration); break; case 'u': DeclSetProperty(pDecl,TY_Union); break; default: /* Can't Happen */ break; } /* The object has a full declaration only if it is contained within ** "#if INTERFACE...#endif" or "#if EXPORT_INTERFACE...#endif" or ** "#if LOCAL_INTERFACE...#endif". Otherwise, we only give it a ** forward declaration. */ if( flags & (PS_Local | PS_Export | PS_Interface) ){ pDecl->zDecl = TokensToString(pList,pEnd); }else{ pDecl->zDecl = 0; } pDecl->pComment = pList->pComment; StringInit(&str); StringAppend(&str,"typedef ",0); StringAppend(&str,pList->zText,pList->nText); StringAppend(&str," ",0); StringAppend(&str,pName->zText,pName->nText); StringAppend(&str," ",0); StringAppend(&str,pName->zText,pName->nText); StringAppend(&str,";\n",2); pDecl->zFwd = StrDup(StringGet(&str),0); StringReset(&str); StringInit(&str); StringAppend(&str,pList->zText,pList->nText); StringAppend(&str," ",0); StringAppend(&str,pName->zText,pName->nText); StringAppend(&str,";\n",2); pDecl->zFwdCpp = StrDup(StringGet(&str),0); StringReset(&str); if( flags & PS_Export ){ DeclSetProperty(pDecl,DP_Export); }else if( flags & PS_Local ){ DeclSetProperty(pDecl,DP_Local); } /* Here's something weird. ANSI-C doesn't allow a forward declaration ** of an enumeration. So we have to build the typedef into the ** definition. */ if( pDecl->zDecl && DeclHasProperty(pDecl, TY_Enumeration) ){ StringInit(&str); StringAppend(&str,pDecl->zDecl,0); StringAppend(&str,pDecl->zFwd,0); SafeFree(pDecl->zDecl); SafeFree(pDecl->zFwd); pDecl->zFwd = 0; pDecl->zDecl = StrDup(StringGet(&str),0); StringReset(&str); } if( pName->pNext->zText[0]==':' ){ DeclSetProperty(pDecl,DP_Cplusplus); } if( pName->nText==5 && strncmp(pName->zText,"class",5)==0 ){ DeclSetProperty(pDecl,DP_Cplusplus); } /* ** Remove all but pList and pName from the input stream. */ if( need_to_collapse ){ while( pEnd!=pName ){ Token *pPrev = pEnd->pPrev; pPrev->pNext = pEnd->pNext; pEnd->pNext->pPrev = pPrev; SafeFree(pEnd); pEnd = pPrev; } } return 0; } /* ** Given a list of tokens that declare something (a function, procedure, ** variable or typedef) find the token which contains the name of the ** thing being declared. ** ** Algorithm: ** ** The name is: ** ** 1. The first identifier that is followed by a "[", or ** ** 2. The first identifier that is followed by a "(" where the ** "(" is followed by another identifier, or ** ** 3. The first identifier followed by "::", or ** ** 4. If none of the above, then the last identifier. ** ** In all of the above, certain reserved words (like "char") are ** not considered identifiers. */ static Token *FindDeclName(Token *pFirst, Token *pLast){ Token *pName = 0; Token *p; int c; if( pFirst==0 || pLast==0 ){ return 0; } pLast = pLast->pNext; for(p=pFirst; p && p!=pLast; p=p->pNext){ if( p->eType==TT_Id ){ static IdentTable sReserved; static int isInit = 0; static char *aWords[] = { "char", "class", "const", "double", "enum", "extern", "EXPORT", "ET_PROC", "float", "int", "long", "register", "static", "struct", "sizeof", "signed", "typedef", "union", "volatile", "virtual", "void", }; if( !isInit ){ int i; for(i=0; izText,p->nText) ){ pName = p; } }else if( p==pFirst ){ continue; }else if( (c=p->zText[0])=='[' && pName ){ break; }else if( c=='(' && p->pNext && p->pNext->eType==TT_Id && pName ){ break; }else if( c==':' && p->zText[1]==':' && pName ){ break; } } return pName; } /* ** This routine is called when we see a function or procedure definition. ** We make an entry in the declaration table that is a prototype for this ** function or procedure. */ static int ProcessProcedureDef(Token *pFirst, Token *pLast, int flags){ Token *pName; Decl *pDecl; Token *pCode; if( pFirst==0 || pLast==0 ){ return 0; } if( flags & PS_Method ){ return 0; } if( (flags & PS_Static)!=0 && !proto_static ){ return 0; } pCode = pLast; while( pLast && pLast!=pFirst && pLast->zText[0]!=')' ){ pLast = pLast->pPrev; } if( pLast==0 || pLast==pFirst || pFirst->pNext==pLast ){ fprintf(stderr,"%s:%d: Unrecognized syntax.\n", zFilename, pFirst->nLine); return 1; } if( flags & (PS_Interface|PS_Export|PS_Local) ){ fprintf(stderr,"%s:%d: Missing \"inline\" on function or procedure.\n", zFilename, pFirst->nLine); return 1; } pName = FindDeclName(pFirst,pLast); if( pName==0 ){ fprintf(stderr,"%s:%d: Malformed function or procedure definition.\n", zFilename, pFirst->nLine); return 1; } /* ** At this point we've isolated a procedure declaration between pFirst ** and pLast with the name pName. */ #ifdef DEBUG if( debugMask & PARSER ){ printf("**** Found routine: %.*s on line %d...\n", pName->nText, pName->zText, pFirst->nLine); PrintTokens(pFirst,pLast); printf(";\n"); } #endif pDecl = CreateDecl(pName->zText,pName->nText); pDecl->pComment = pFirst->pComment; if( pCode && pCode->eType==TT_Braces ){ pDecl->tokenCode = *pCode; } DeclSetProperty(pDecl,TY_Subroutine); pDecl->zDecl = TokensToString(pFirst,pLast); if( (flags & (PS_Static|PS_Local2))!=0 ){ DeclSetProperty(pDecl,DP_Local); }else if( (flags & (PS_Export2))!=0 ){ DeclSetProperty(pDecl,DP_Export); } if( flags & DP_Cplusplus ){ DeclSetProperty(pDecl,DP_Cplusplus); }else{ DeclSetProperty(pDecl,DP_ExternCReqd); } return 0; } /* ** This routine is called whenever we see the "inline" keyword. We ** need to seek-out the inline function or procedure and make a ** declaration out of the entire definition. */ static int ProcessInlineProc(Token *pFirst, int flags, int *pReset){ Token *pName; Token *pEnd; Decl *pDecl; for(pEnd=pFirst; pEnd; pEnd = pEnd->pNext){ if( pEnd->zText[0]=='{' || pEnd->zText[0]==';' ){ *pReset = pEnd->zText[0]; break; } } if( pEnd==0 ){ *pReset = ';'; fprintf(stderr,"%s:%d: incomplete inline procedure definition\n", zFilename, pFirst->nLine); return 1; } pName = FindDeclName(pFirst,pEnd); if( pName==0 ){ fprintf(stderr,"%s:%d: malformed inline procedure definition\n", zFilename, pFirst->nLine); return 1; } #ifdef DEBUG if( debugMask & PARSER ){ printf("**** Found inline routine: %.*s on line %d...\n", pName->nText, pName->zText, pFirst->nLine); PrintTokens(pFirst,pEnd); printf("\n"); } #endif pDecl = CreateDecl(pName->zText,pName->nText); pDecl->pComment = pFirst->pComment; DeclSetProperty(pDecl,TY_Subroutine); pDecl->zDecl = TokensToString(pFirst,pEnd); if( (flags & (PS_Static|PS_Local|PS_Local2)) ){ DeclSetProperty(pDecl,DP_Local); }else if( flags & (PS_Export|PS_Export2) ){ DeclSetProperty(pDecl,DP_Export); } if( flags & DP_Cplusplus ){ DeclSetProperty(pDecl,DP_Cplusplus); }else{ DeclSetProperty(pDecl,DP_ExternCReqd); } return 0; } /* ** Determine if the tokens between pFirst and pEnd form a variable ** definition or a function prototype. Return TRUE if we are dealing ** with a variable defintion and FALSE for a prototype. ** ** pEnd is the token that ends the object. It can be either a ';' or ** a '='. If it is '=', then assume we have a variable definition. ** ** If pEnd is ';', then the determination is more difficult. We have ** to search for an occurance of an ID followed immediately by '('. ** If found, we have a prototype. Otherwise we are dealing with a ** variable definition. */ static int isVariableDef(Token *pFirst, Token *pEnd){ if( pEnd && pEnd->zText[0]=='=' ){ return 1; } while( pFirst && pFirst!=pEnd && pFirst->pNext && pFirst->pNext!=pEnd ){ if( pFirst->eType==TT_Id && pFirst->pNext->zText[0]=='(' ){ return 0; } pFirst = pFirst->pNext; } return 1; } /* ** This routine is called whenever we encounter a ";" or "=". The stuff ** between pFirst and pLast constitutes either a typedef or a global ** variable definition. Do the right thing. */ static int ProcessDecl(Token *pFirst, Token *pEnd, int flags){ Token *pName; Decl *pDecl; int isLocal = 0; int isVar; int nErr = 0; if( pFirst==0 || pEnd==0 ){ return 0; } if( flags & PS_Typedef ){ if( (flags & (PS_Export2|PS_Local2))!=0 ){ fprintf(stderr,"%s:%d: \"EXPORT\" or \"LOCAL\" ignored before typedef.\n", zFilename, pFirst->nLine); nErr++; } if( (flags & (PS_Interface|PS_Export|PS_Local|DP_Cplusplus))==0 ){ /* It is illegal to duplicate a typedef in C (but OK in C++). ** So don't record typedefs that aren't within a C++ file or ** within #if INTERFACE..#endif */ return nErr; } if( (flags & (PS_Interface|PS_Export|PS_Local))==0 && proto_static==0 ){ /* Ignore typedefs that are not with "#if INTERFACE..#endif" unless ** the "-local" command line option is used. */ return nErr; } if( (flags & (PS_Interface|PS_Export))==0 ){ /* typedefs are always local, unless within #if INTERFACE..#endif */ isLocal = 1; } }else if( flags & (PS_Static|PS_Local2) ){ if( proto_static==0 && (flags & PS_Local2)==0 ){ /* Don't record static variables unless the "-local" command line ** option was specified or the "LOCAL" keyword is used. */ return nErr; } while( pFirst!=0 && pFirst->pNext!=pEnd && ((pFirst->nText==6 && strncmp(pFirst->zText,"static",6)==0) || (pFirst->nText==5 && strncmp(pFirst->zText,"LOCAL",6)==0)) ){ /* Lose the initial "static" or local from local variables. ** We'll prepend "extern" later. */ pFirst = pFirst->pNext; isLocal = 1; } if( pFirst==0 || !isLocal ){ return nErr; } }else if( flags & PS_Method ){ /* Methods are declared by their class. Don't declare separately. */ return nErr; } isVar = (flags & (PS_Typedef|PS_Method))==0 && isVariableDef(pFirst,pEnd); if( isVar && (flags & (PS_Interface|PS_Export|PS_Local))!=0 && (flags & PS_Extern)==0 ){ fprintf(stderr,"%s:%d: Can't define a variable in this context\n", zFilename, pFirst->nLine); nErr++; } pName = FindDeclName(pFirst,pEnd->pPrev); if( pName==0 ){ fprintf(stderr,"%s:%d: Can't find a name for the object declared here.\n", zFilename, pFirst->nLine); return nErr+1; } #ifdef DEBUG if( debugMask & PARSER ){ if( flags & PS_Typedef ){ printf("**** Found typedef %.*s at line %d...\n", pName->nText, pName->zText, pName->nLine); }else if( isVar ){ printf("**** Found variable %.*s at line %d...\n", pName->nText, pName->zText, pName->nLine); }else{ printf("**** Found prototype %.*s at line %d...\n", pName->nText, pName->zText, pName->nLine); } PrintTokens(pFirst,pEnd->pPrev); printf(";\n"); } #endif pDecl = CreateDecl(pName->zText,pName->nText); if( (flags & PS_Typedef) ){ DeclSetProperty(pDecl, TY_Typedef); }else if( isVar ){ DeclSetProperty(pDecl,DP_ExternReqd | TY_Variable); if( !(flags & DP_Cplusplus) ){ DeclSetProperty(pDecl,DP_ExternCReqd); } }else{ DeclSetProperty(pDecl, TY_Subroutine); if( !(flags & DP_Cplusplus) ){ DeclSetProperty(pDecl,DP_ExternCReqd); } } pDecl->pComment = pFirst->pComment; pDecl->zDecl = TokensToString(pFirst,pEnd->pPrev); if( isLocal || (flags & (PS_Local||PS_Local2))!=0 ){ DeclSetProperty(pDecl,DP_Local); }else if( flags & (PS_Export|PS_Export2) ){ DeclSetProperty(pDecl,DP_Export); } if( flags & DP_Cplusplus ){ DeclSetProperty(pDecl,DP_Cplusplus); } return nErr; } /* ** Push an if condition onto the if stack */ static void PushIfMacro( const char *zPrefix, /* A prefix, like "define" or "!" */ const char *zText, /* The condition */ int nText, /* Number of characters in zText */ int nLine, /* Line number where this macro occurs */ int flags /* Either 0, PS_Interface, PS_Export or PS_Local */ ){ Ifmacro *pIf; int nByte; nByte = sizeof(Ifmacro); if( zText ){ if( zPrefix ){ nByte += strlen(zPrefix) + 2; } nByte += nText + 1; } pIf = SafeMalloc( nByte ); if( zText ){ pIf->zCondition = (char*)&pIf[1]; if( zPrefix ){ sprintf(pIf->zCondition,"%s(%.*s)",zPrefix,nText,zText); }else{ sprintf(pIf->zCondition,"%.*s",nText,zText); } }else{ pIf->zCondition = 0; } pIf->nLine = nLine; pIf->flags = flags; pIf->pNext = ifStack; ifStack = pIf; } /* ** This routine is called to handle all preprocessor directives. ** ** This routine will recompute the value of *pPresetFlags to be the ** logical or of all flags on all nested #ifs. The #ifs that set flags ** are as follows: ** ** conditional flag set ** ------------------------ -------------------- ** #if INTERFACE PS_Interface ** #if EXPORT_INTERFACE PS_Export ** #if LOCAL_INTERFACE PS_Local ** ** For example, if after processing the preprocessor token given ** by pToken there is an "#if INTERFACE" on the preprocessor ** stack, then *pPresetFlags will be set to PS_Interface. */ static int ParsePreprocessor(Token *pToken, int flags, int *pPresetFlags){ const char *zCmd; int nCmd; const char *zArg; int nArg; int nErr = 0; Ifmacro *pIf; zCmd = &pToken->zText[1]; while( isspace(*zCmd) && *zCmd!='\n' ){ zCmd++; } if( !isalpha(*zCmd) ){ return 0; } nCmd = 1; while( isalpha(zCmd[nCmd]) ){ nCmd++; } if( nCmd==5 && strncmp(zCmd,"endif",5)==0 ){ /* ** Pop the if stack */ pIf = ifStack; if( pIf==0 ){ fprintf(stderr,"%s:%d: extra '#endif'.\n",zFilename,pToken->nLine); return 1; } ifStack = pIf->pNext; SafeFree(pIf); }else if( nCmd==6 && strncmp(zCmd,"define",6)==0 ){ /* ** Record a #define if we are in PS_Interface or PS_Export */ Decl *pDecl; if( !(flags & (PS_Local|PS_Interface|PS_Export)) ){ return 0; } zArg = &zCmd[6]; while( *zArg && isspace(*zArg) && *zArg!='\n' ){ zArg++; } if( *zArg==0 || *zArg=='\n' ){ return 0; } for(nArg=0; ISALNUM(zArg[nArg]); nArg++){} if( nArg==0 ){ return 0; } pDecl = CreateDecl(zArg,nArg); pDecl->pComment = pToken->pComment; DeclSetProperty(pDecl,TY_Macro); pDecl->zDecl = SafeMalloc( pToken->nText + 2 ); sprintf(pDecl->zDecl,"%.*s\n",pToken->nText,pToken->zText); if( flags & PS_Export ){ DeclSetProperty(pDecl,DP_Export); }else if( flags & PS_Local ){ DeclSetProperty(pDecl,DP_Local); } }else if( nCmd==7 && strncmp(zCmd,"include",7)==0 ){ /* ** Record an #include if we are in PS_Interface or PS_Export */ Include *pInclude; char *zIf; if( !(flags & (PS_Interface|PS_Export)) ){ return 0; } zArg = &zCmd[7]; while( *zArg && isspace(*zArg) ){ zArg++; } for(nArg=0; !isspace(zArg[nArg]); nArg++){} if( (zArg[0]=='"' && zArg[nArg-1]!='"') ||(zArg[0]=='<' && zArg[nArg-1]!='>') ){ fprintf(stderr,"%s:%d: malformed #include statement.\n", zFilename,pToken->nLine); return 1; } zIf = GetIfString(); if( zIf ){ pInclude = SafeMalloc( sizeof(Include) + nArg*2 + strlen(zIf) + 10 ); pInclude->zFile = (char*)&pInclude[1]; pInclude->zLabel = &pInclude->zFile[nArg+1]; sprintf(pInclude->zFile,"%.*s",nArg,zArg); sprintf(pInclude->zLabel,"%.*s:%s",nArg,zArg,zIf); pInclude->zIf = &pInclude->zLabel[nArg+1]; SafeFree(zIf); }else{ pInclude = SafeMalloc( sizeof(Include) + nArg + 1 ); pInclude->zFile = (char*)&pInclude[1]; sprintf(pInclude->zFile,"%.*s",nArg,zArg); pInclude->zIf = 0; pInclude->zLabel = pInclude->zFile; } pInclude->pNext = includeList; includeList = pInclude; }else if( nCmd==2 && strncmp(zCmd,"if",2)==0 ){ /* ** Push an #if. Watch for the special cases of INTERFACE ** and EXPORT_INTERFACE and LOCAL_INTERFACE */ zArg = &zCmd[2]; while( *zArg && isspace(*zArg) && *zArg!='\n' ){ zArg++; } if( *zArg==0 || *zArg=='\n' ){ return 0; } nArg = pToken->nText + (int)pToken->zText - (int)zArg; if( nArg==9 && strncmp(zArg,"INTERFACE",9)==0 ){ PushIfMacro(0,0,0,pToken->nLine,PS_Interface); }else if( nArg==16 && strncmp(zArg,"EXPORT_INTERFACE",16)==0 ){ PushIfMacro(0,0,0,pToken->nLine,PS_Export); }else if( nArg==15 && strncmp(zArg,"LOCAL_INTERFACE",15)==0 ){ PushIfMacro(0,0,0,pToken->nLine,PS_Local); }else{ PushIfMacro(0,zArg,nArg,pToken->nLine,0); } }else if( nCmd==5 && strncmp(zCmd,"ifdef",5)==0 ){ /* ** Push an #ifdef. */ zArg = &zCmd[5]; while( *zArg && isspace(*zArg) && *zArg!='\n' ){ zArg++; } if( *zArg==0 || *zArg=='\n' ){ return 0; } nArg = pToken->nText + (int)pToken->zText - (int)zArg; PushIfMacro("defined",zArg,nArg,pToken->nLine,0); }else if( nCmd==6 && strncmp(zCmd,"ifndef",6)==0 ){ /* ** Push an #ifndef. */ zArg = &zCmd[6]; while( *zArg && isspace(*zArg) && *zArg!='\n' ){ zArg++; } if( *zArg==0 || *zArg=='\n' ){ return 0; } nArg = pToken->nText + (int)pToken->zText - (int)zArg; PushIfMacro("!defined",zArg,nArg,pToken->nLine,0); }else if( nCmd==4 && strncmp(zCmd,"else",4)==0 ){ /* ** Invert the #if on the top of the stack */ if( ifStack==0 ){ fprintf(stderr,"%s:%d: '#else' without an '#if'\n",zFilename, pToken->nLine); return 1; } pIf = ifStack; if( pIf->zCondition ){ ifStack = ifStack->pNext; PushIfMacro("!",pIf->zCondition,strlen(pIf->zCondition),pIf->nLine,0); SafeFree(pIf); }else{ pIf->flags = 0; } }else{ /* ** This directive can be safely ignored */ return 0; } /* ** Recompute the preset flags */ *pPresetFlags = 0; for(pIf = ifStack; pIf; pIf=pIf->pNext){ *pPresetFlags |= pIf->flags; } return nErr; } /* ** Parse an entire file. Return the number of errors. ** ** pList is a list of tokens in the file. Whitespace tokens have been ** eliminated, and text with {...} has been collapsed into a ** single TT_Brace token. ** ** initFlags are a set of parse flags that should always be set for this ** file. For .c files this is normally 0. For .h files it is PS_Interface. */ static int ParseFile(Token *pList, int initFlags){ int nErr = 0; Token *pStart = 0; int flags = initFlags; int presetFlags = initFlags; int resetFlag = 0; includeList = 0; while( pList ){ switch( pList->eType ){ case TT_EOF: goto end_of_loop; case TT_Preprocessor: nErr += ParsePreprocessor(pList,flags,&presetFlags); pStart = 0; presetFlags |= initFlags; flags = presetFlags; break; case TT_Other: switch( pList->zText[0] ){ case ';': nErr += ProcessDecl(pStart,pList,flags); pStart = 0; flags = presetFlags; break; case '=': nErr += ProcessDecl(pStart,pList,flags); pStart = 0; while( pList && pList->zText[0]!=';' ){ pList = pList->pNext; } if( pList==0 ) goto end_of_loop; flags = presetFlags; break; case ':': if( pList->zText[1]==':' ){ flags |= PS_Method; } break; default: break; } break; case TT_Braces: nErr += ProcessProcedureDef(pStart,pList,flags); pStart = 0; flags = presetFlags; break; case TT_Id: if( pStart==0 ){ pStart = pList; flags = presetFlags; } resetFlag = 0; switch( pList->zText[0] ){ case 'c': if( pList->nText==5 && strncmp(pList->zText,"class",5)==0 ){ nErr += ProcessTypeDecl(pList,flags,&resetFlag); } break; case 'E': if( pList->nText==6 && strncmp(pList->zText,"EXPORT",6)==0 ){ flags |= PS_Export2; /* pStart = 0; */ } break; case 'e': if( pList->nText==4 && strncmp(pList->zText,"enum",4)==0 ){ if( pList->pNext && pList->pNext->eType==TT_Braces ){ pList = pList->pNext; }else{ nErr += ProcessTypeDecl(pList,flags,&resetFlag); } }else if( pList->nText==6 && strncmp(pList->zText,"extern",6)==0 ){ pList = pList->pNext; if( pList && pList->nText==3 && strncmp(pList->zText,"\"C\"",3)==0 ){ pList = pList->pNext; flags &= ~DP_Cplusplus; }else{ flags |= PS_Extern; } pStart = pList; } break; case 'i': if( pList->nText==6 && strncmp(pList->zText,"inline",6)==0 ){ nErr += ProcessInlineProc(pList,flags,&resetFlag); } break; case 'L': if( pList->nText==5 && strncmp(pList->zText,"LOCAL",5)==0 ){ flags |= PS_Local2; pStart = pList; } break; case 's': if( pList->nText==6 && strncmp(pList->zText,"struct",6)==0 ){ if( pList->pNext && pList->pNext->eType==TT_Braces ){ pList = pList->pNext; }else{ nErr += ProcessTypeDecl(pList,flags,&resetFlag); } }else if( pList->nText==6 && strncmp(pList->zText,"static",6)==0 ){ flags |= PS_Static; } break; case 't': if( pList->nText==7 && strncmp(pList->zText,"typedef",7)==0 ){ flags |= PS_Typedef; } break; case 'u': if( pList->nText==5 && strncmp(pList->zText,"union",5)==0 ){ if( pList->pNext && pList->pNext->eType==TT_Braces ){ pList = pList->pNext; }else{ nErr += ProcessTypeDecl(pList,flags,&resetFlag); } } break; default: break; } if( resetFlag!=0 ){ while( pList && pList->zText[0]!=resetFlag ){ pList = pList->pNext; } if( pList==0 ) goto end_of_loop; pStart = 0; flags = presetFlags; } break; case TT_Number: break; default: pStart = pList; flags = presetFlags; break; } pList = pList->pNext; } end_of_loop: /* Verify that all #ifs have a matching "#endif" */ while( ifStack ){ Ifmacro *pIf = ifStack; ifStack = pIf->pNext; fprintf(stderr,"%s:%d: This '#if' has no '#endif'\n",zFilename, pIf->nLine); SafeFree(pIf); } return nErr; } /* ** Reset the DP_Forward and DP_Declared flags on all Decl structures. ** Set both flags for anything that is tagged as local and isn't ** in the file zFilename so that it won't be printing in other files. */ static void ResetDeclFlags(char *zFilename){ Decl *pDecl; for(pDecl = pDeclFirst; pDecl; pDecl = pDecl->pNext){ DeclClearProperty(pDecl,DP_Forward|DP_Declared); if( DeclHasProperty(pDecl,DP_Local) && pDecl->zFile!=zFilename ){ DeclSetProperty(pDecl,DP_Forward|DP_Declared); } } } /* ** Forward declaration of the ScanText() function. */ static void ScanText(const char*, GenState *pState); /* ** The output in pStr is currently within an #if CONTEXT where context ** is equal to *pzIf. (*pzIf might be NULL to indicate that we are ** not within any #if at the moment.) We are getting ready to output ** some text that needs to be within the context of "#if NEW" where ** NEW is zIf. Make an appropriate change to the context. */ static void ChangeIfContext( const char *zIf, /* The desired #if context */ GenState *pState /* Current state of the code generator */ ){ if( zIf==0 ){ if( pState->zIf==0 ) return; StringAppend(pState->pStr,"#endif\n",0); pState->zIf = 0; }else{ if( pState->zIf ){ if( strcmp(zIf,pState->zIf)==0 ) return; StringAppend(pState->pStr,"#endif\n",0); pState->zIf = 0; } ScanText(zIf, pState); if( pState->zIf!=0 ){ StringAppend(pState->pStr,"#endif\n",0); } StringAppend(pState->pStr,"#if ",0); StringAppend(pState->pStr,zIf,0); StringAppend(pState->pStr,"\n",0); pState->zIf = zIf; } } /* ** Add to the string pStr a #include of every file on the list of ** include files pInclude. The table pTable contains all files that ** have already been #included at least once. Don't add any ** duplicates. Update pTable with every new #include that is added. */ static void AddIncludes( Include *pInclude, /* Write every #include on this list */ GenState *pState /* Current state of the code generator */ ){ if( pInclude ){ if( pInclude->pNext ){ AddIncludes(pInclude->pNext,pState); } if( IdentTableInsert(pState->pTable,pInclude->zLabel,0) ){ ChangeIfContext(pInclude->zIf,pState); StringAppend(pState->pStr,"#include ",0); StringAppend(pState->pStr,pInclude->zFile,0); StringAppend(pState->pStr,"\n",1); } } } /* ** Add to the string pStr a declaration for the object described ** in pDecl. ** ** If pDecl has already been declared in this file, detect that ** fact and abort early. Do not duplicate a declaration. ** ** If the needFullDecl flag is false and this object has a forward ** declaration, then supply the forward declaration only. A later ** call to CompleteForwardDeclarations() will finish the declaration ** for us. But if needFullDecl is true, we must supply the full ** declaration now. Some objects do not have a forward declaration. ** For those objects, we must print the full declaration now. ** ** Because it is illegal to duplicate a typedef in C, care is taken ** to insure that typedefs for the same identifier are only issued once. */ static void DeclareObject( Decl *pDecl, /* The thing to be declared */ GenState *pState, /* Current state of the code generator */ int needFullDecl /* Must have the full declaration. A forward * declaration isn't enough */ ){ Decl *p; /* The object to be declared */ int flag; int isCpp; /* True if generating C++ */ int doneTypedef = 0; /* True if a typedef has been done for this object */ /* ** For any object that has a forward declaration, go ahead and do the ** forward declaration first. */ isCpp = (pState->flags & DP_Cplusplus) != 0; for(p=pDecl; p; p=p->pSameName){ if( p->zFwd ){ if( !DeclHasProperty(p,DP_Forward) ){ DeclSetProperty(p,DP_Forward); if( strncmp(p->zFwd,"typedef",7)==0 ){ if( doneTypedef ) continue; doneTypedef = 1; } ChangeIfContext(p->zIf,pState); StringAppend(pState->pStr,isCpp ? p->zFwdCpp : p->zFwd,0); } } } /* ** Early out if everything is already suitably declared. ** ** This is a very important step because it prevents us from ** executing the code the follows in a recursive call to this ** function with the same value for pDecl. */ flag = needFullDecl ? DP_Declared|DP_Forward : DP_Forward; for(p=pDecl; p; p=p->pSameName){ if( !DeclHasProperty(p,flag) ) break; } if( p==0 ){ return; } /* ** Make sure we have all necessary #includes */ for(p=pDecl; p; p=p->pSameName){ AddIncludes(p->pInclude,pState); } /* ** Go ahead an mark everything as being declared, to prevent an ** infinite loop thru the ScanText() function. At the same time, ** we decide which objects need a full declaration and mark them ** with the DP_Flag bit. We are only able to use DP_Flag in this ** way because we know we'll never execute this far into this ** function on a recursive call with the same pDecl. Hence, recursive ** calls to this function (through ScanText()) can never change the ** value of DP_Flag out from under us. */ for(p=pDecl; p; p=p->pSameName){ if( !DeclHasProperty(p,DP_Declared) && (p->zFwd==0 || needFullDecl) && p->zDecl!=0 ){ DeclSetProperty(p,DP_Forward|DP_Declared|DP_Flag); }else{ DeclClearProperty(p,DP_Flag); } } /* ** Call ScanText() recusively (this routine is called from ScanText()) ** to include declarations required to come before these declarations. */ for(p=pDecl; p; p=p->pSameName){ if( DeclHasProperty(p,DP_Flag) ){ if( p->zDecl[0]=='#' ){ ScanText(&p->zDecl[1],pState); }else{ ScanText(p->zDecl,pState); } } } /* ** Output the declarations. Do this in two passes. First ** output everything that isn't a typedef. Then go back and ** get the typedefs by the same name. */ for(p=pDecl; p; p=p->pSameName){ if( DeclHasProperty(p,DP_Flag) && !DeclHasProperty(p,TY_Typedef) ){ if( DeclHasAnyProperty(p,TY_Enumeration) ){ if( doneTypedef ) continue; doneTypedef = 1; } ChangeIfContext(p->zIf,pState); if( !isCpp && DeclHasAnyProperty(p,DP_ExternReqd) ){ StringAppend(pState->pStr,"extern ",0); }else if( isCpp && DeclHasProperty(p,DP_Cplusplus|DP_ExternReqd) ){ StringAppend(pState->pStr,"extern ",0); }else if( isCpp && DeclHasAnyProperty(p,DP_ExternCReqd|DP_ExternReqd) ){ StringAppend(pState->pStr,"extern \"C\" ",0); } StringAppend(pState->pStr,p->zDecl,0); if( !isCpp && DeclHasProperty(p,DP_Cplusplus) ){ fprintf(stderr, "%s: C code ought not reference the C++ object \"%s\"\n", pState->zFilename, p->zName); pState->nErr++; } DeclClearProperty(p,DP_Flag); } } for(p=pDecl; p && !doneTypedef; p=p->pSameName){ if( DeclHasProperty(p,DP_Flag) ){ /* This has to be a typedef */ doneTypedef = 1; ChangeIfContext(p->zIf,pState); StringAppend(pState->pStr,p->zDecl,0); } } } /* ** This routine scans the input text given, and appends to the ** string in pState->pStr the text of any declarations that must ** occur before the text in zText. ** ** If an identifier in zText is immediately followed by '*', then ** only forward declarations are needed for that identifier. If the ** identifier name is not followed immediately by '*', we must supply ** a full declaration. */ static void ScanText( const char *zText, /* The input text to be scanned */ GenState *pState /* Current state of the code generator */ ){ int nextValid = 0; /* True is sNext contains valid data */ InStream sIn; /* The input text */ Token sToken; /* The current token being examined */ Token sNext; /* The next non-space token */ sIn.z = zText; sIn.i = 0; sIn.nLine = 1; while( sIn.z[sIn.i]!=0 ){ if( nextValid ){ sToken = sNext; nextValid = 0; }else{ GetNonspaceToken(&sIn,&sToken); } if( sToken.eType==TT_Id ){ int needFullDecl; /* True if we need to provide the full declaration, ** not just the forward declaration */ Decl *pDecl; /* The declaration having the name in sToken */ /* ** See if there is a declaration in the database with the name given ** by sToken. */ pDecl = FindDecl(sToken.zText,sToken.nText); if( pDecl==0 ) continue; /* ** If we get this far, we've found an identifier that has a ** declaration in the database. Now see if we the full declaration ** or just a forward declaration. */ GetNonspaceToken(&sIn,&sNext); if( sNext.zText[0]=='*' ){ needFullDecl = 0; }else{ needFullDecl = 1; nextValid = sNext.eType==TT_Id; } /* ** Generate the needed declaration. */ DeclareObject(pDecl,pState,needFullDecl); }else if( sToken.eType==TT_Preprocessor ){ sIn.i -= sToken.nText - 1; } } } /* ** Provide a full declaration to any object which so far has had only ** a foward declaration. */ static void CompleteForwardDeclarations(GenState *pState){ Decl *pDecl; int progress; do{ progress = 0; for(pDecl=pDeclFirst; pDecl; pDecl=pDecl->pNext){ if( DeclHasProperty(pDecl,DP_Forward) && !DeclHasProperty(pDecl,DP_Declared) ){ DeclareObject(pDecl,pState,1); progress = 1; assert( DeclHasProperty(pDecl,DP_Declared) ); } } }while( progress ); } /* ** Generate an include file for the given source file. Return the number ** of errors encountered. ** ** if nolocal_flag is true, then we do not generate declarations for ** objected marked DP_Local. */ static int MakeHeader(InFile *pFile, FILE *report, int nolocal_flag){ int nErr = 0; GenState sState; String outStr; IdentTable includeTable; Ident *pId; char *zNewVersion; char *zOldVersion; if( pFile->zHdr==0 || *pFile->zHdr==0 ) return 0; sState.pStr = &outStr; StringInit(&outStr); StringAppend(&outStr,zTopLine,nTopLine); sState.pTable = &includeTable; memset(&includeTable,0,sizeof(includeTable)); sState.zIf = 0; sState.nErr = 0; sState.zFilename = pFile->zSrc; sState.flags = pFile->flags & DP_Cplusplus; ResetDeclFlags(nolocal_flag ? "no" : pFile->zSrc); for(pId = pFile->idTable.pList; pId; pId=pId->pNext){ Decl *pDecl = FindDecl(pId->zName,0); if( pDecl ){ DeclareObject(pDecl,&sState,1); } } CompleteForwardDeclarations(&sState); ChangeIfContext(0,&sState); nErr += sState.nErr; zOldVersion = ReadFile(pFile->zHdr); zNewVersion = StringGet(&outStr); if( report ) fprintf(report,"%s: ",pFile->zHdr); if( zOldVersion==0 ){ if( report ) fprintf(report,"updated\n"); if( WriteFile(pFile->zHdr,zNewVersion) ){ fprintf(stderr,"%s: Can't write to file\n",pFile->zHdr); nErr++; } }else if( strncmp(zOldVersion,zTopLine,nTopLine)!=0 ){ if( report ) fprintf(report,"error!\n"); fprintf(stderr, "%s: Can't overwrite this file because it wasn't previously\n" "%*s generated by 'makeheaders'.\n", pFile->zHdr, strlen(pFile->zHdr), ""); nErr++; }else if( strcmp(zOldVersion,zNewVersion)!=0 ){ if( report ) fprintf(report,"updated\n"); if( WriteFile(pFile->zHdr,zNewVersion) ){ fprintf(stderr,"%s: Can't write to file\n",pFile->zHdr); nErr++; } }else if( report ){ fprintf(report,"unchanged\n"); } SafeFree(zOldVersion); IdentTableReset(&includeTable); StringReset(&outStr); return nErr; } /* ** Generate a global header file -- a header file that contains all ** declarations. If the forExport flag is true, then only those ** objects that are exported are included in the header file. */ static int MakeGlobalHeader(int forExport){ GenState sState; String outStr; IdentTable includeTable; Decl *pDecl; sState.pStr = &outStr; StringInit(&outStr); /* StringAppend(&outStr,zTopLine,nTopLine); */ sState.pTable = &includeTable; memset(&includeTable,0,sizeof(includeTable)); sState.zIf = 0; sState.nErr = 0; sState.zFilename = "(all)"; sState.flags = 0; ResetDeclFlags(0); for(pDecl=pDeclFirst; pDecl; pDecl=pDecl->pNext){ if( forExport==0 || DeclHasProperty(pDecl,DP_Export) ){ DeclareObject(pDecl,&sState,1); } } ChangeIfContext(0,&sState); printf("%s",StringGet(&outStr)); IdentTableReset(&includeTable); StringReset(&outStr); return 0; } #ifdef DEBUG /* ** Return the number of characters in the given string prior to the ** first newline. */ static int ClipTrailingNewline(char *z){ int n = strlen(z); while( n>0 && (z[n-1]=='\n' || z[n-1]=='\r') ){ n--; } return n; } /* ** Dump the entire declaration list for debugging purposes */ static void DumpDeclList(void){ Decl *pDecl; for(pDecl = pDeclFirst; pDecl; pDecl=pDecl->pNext){ printf("**** %s from file %s ****\n",pDecl->zName,pDecl->zFile); if( pDecl->zIf ){ printf("If: [%.*s]\n",ClipTrailingNewline(pDecl->zIf),pDecl->zIf); } if( pDecl->zFwd ){ printf("Decl: [%.*s]\n",ClipTrailingNewline(pDecl->zFwd),pDecl->zFwd); } if( pDecl->zDecl ){ printf("Def: [%.*s]\n",ClipTrailingNewline(pDecl->zDecl),pDecl->zDecl); } if( pDecl->flags ){ static struct { int mask; char *desc; } flagSet[] = { { TY_Class, "class" }, { TY_Enumeration, "enum" }, { TY_Structure, "struct" }, { TY_Union, "union" }, { TY_Variable, "variable" }, { TY_Subroutine, "function" }, { TY_Typedef, "typedef" }, { TY_Macro, "macro" }, { DP_Export, "export" }, { DP_Local, "local" }, { DP_Cplusplus, "C++" }, }; int i; printf("flags:"); for(i=0; iflags ){ printf(" %s", flagSet[i].desc); } } printf("\n"); } if( pDecl->pInclude ){ Include *p; printf("includes:"); for(p=pDecl->pInclude; p; p=p->pNext){ printf(" %s",p->zFile); } printf("\n"); } } } #endif /* ** When the "-doc" command-line option is used, this routine is called ** to print all of the database information to standard output. */ static void DocumentationDump(void){ Decl *pDecl; static struct { int mask; char flag; } flagSet[] = { { TY_Class, 'c' }, { TY_Enumeration, 'e' }, { TY_Structure, 's' }, { TY_Union, 'u' }, { TY_Variable, 'v' }, { TY_Subroutine, 'f' }, { TY_Typedef, 't' }, { TY_Macro, 'm' }, { DP_Export, 'x' }, { DP_Local, 'l' }, { DP_Cplusplus, '+' }, }; for(pDecl = pDeclFirst; pDecl; pDecl=pDecl->pNext){ int i; int nLabel = 0; char *zDecl; char zLabel[50]; for(i=0; izDecl; if( zDecl==0 ) zDecl = pDecl->zFwd; printf("%s %s %s %d %d %d %d %d %d\n", pDecl->zName, zLabel, pDecl->zFile, pDecl->pComment ? (int)pDecl->pComment/sizeof(Token) : 0, pDecl->pComment ? pDecl->pComment->nText+1 : 0, pDecl->zIf ? strlen(pDecl->zIf)+1 : 0, zDecl ? strlen(zDecl) : 0, pDecl->pComment ? pDecl->pComment->nLine : 0, pDecl->tokenCode.nText ? pDecl->tokenCode.nText+1 : 0 ); if( pDecl->pComment ){ printf("%.*s\n",pDecl->pComment->nText, pDecl->pComment->zText); } if( pDecl->zIf ){ printf("%s\n",pDecl->zIf); } if( zDecl ){ printf("%s",zDecl); } if( pDecl->tokenCode.nText ){ printf("%.*s\n",pDecl->tokenCode.nText, pDecl->tokenCode.zText); } } } /* ** Given the complete text of an input file, this routine prints a ** documentation record for the header comment at the beginning of the ** file (if the file has a header comment.) */ void PrintModuleRecord(const char *zFile, const char *zFilename){ int i; static int addr = 5; while( isspace(*zFile) ){ zFile++; } if( *zFile!='/' || zFile[1]!='*' ) return; for(i=2; zFile[i] && (zFile[i-1]!='/' || zFile[i-2]!='*'); i++){} if( zFile[i]==0 ) return; printf("%s M %s %d %d 0 0 0\n%.*s\n", zFilename, zFilename, addr, i+1, i, zFile); addr += 4; } /* ** Given an input argument to the program, construct a new InFile ** object. */ static InFile *CreateInFile(char *zArg, int *pnErr){ int nSrc; char *zSrc; InFile *pFile; int i; /* ** Get the name of the input file to be scanned */ zSrc = zArg; for(nSrc=0; zSrc[nSrc] && zArg[nSrc]!=':'; nSrc++){} pFile = SafeMalloc( sizeof(InFile) ); memset(pFile,0,sizeof(InFile)); pFile->zSrc = StrDup(zSrc,nSrc); /* Figure out if we are dealing with C or C++ code. Assume any ** file with ".c" or ".h" is C code and all else is C++. */ if( nSrc>2 && zSrc[nSrc-2]=='.' && (zSrc[nSrc-1]=='c' || zSrc[nSrc-1]=='h')){ pFile->flags &= ~DP_Cplusplus; }else{ pFile->flags |= DP_Cplusplus; } /* ** If a separate header file is specified, use it */ if( zSrc[nSrc]==':' ){ int nHdr; char *zHdr; zHdr = &zSrc[nSrc+1]; for(nHdr=0; zHdr[nHdr] && zHdr[nHdr]!=':'; nHdr++){} pFile->zHdr = StrDup(zHdr,nHdr); } /* Look for any 'c' or 'C' in the suffix of the file name and change ** that character to 'h' or 'H' respectively. If no 'c' or 'C' is found, ** then assume we are dealing with a header. */ else{ int foundC = 0; int i, j; for(i=0, j=-1; zSrc[i]; i++){ if( zSrc[i]=='/' && zSrc[i+1] ) j = i; } pFile->zHdr = StrDup(&zSrc[j+1], nSrc-(j+1)); for(i = nSrc-1; i>0 && pFile->zHdr[i]!='.'; i--){ if( pFile->zHdr[i]=='c' ){ foundC = 1; pFile->zHdr[i] = 'h'; }else if( pFile->zHdr[i]=='C' ){ foundC = 1; pFile->zHdr[i] = 'H'; } } if( !foundC ){ SafeFree(pFile->zHdr); pFile->zHdr = 0; } } /* ** If pFile->zSrc contains no 'c' or 'C' in its extension, it ** must be a header file. In that case, we need to set the ** PS_Interface flag. */ pFile->flags |= PS_Interface; for(i=nSrc-1; i>0 && zSrc[i]!='.'; i--){ if( zSrc[i]=='c' || zSrc[i]=='C' ){ pFile->flags &= ~PS_Interface; break; } } /* Done! */ return pFile; } /* MS-Windows and MS-DOS both have the following serious OS bug: the ** length of a command line is severely restricted. But this program ** occasionally requires long command lines. Hence the following ** work around. ** ** If the parameters "-f FILENAME" appear anywhere on the command line, ** then the named file is scanned for additional command line arguments. ** These arguments are substituted in place of the "FILENAME" argument ** in the original argument list. ** ** This first parameter to this routine is the index of the "-f" ** parameter in the argv[] array. The argc and argv are passed by ** pointer so that they can be changed. ** ** Parsing of the parameters in the file is very simple. Parameters ** can be separated by any amount of white-space (including newlines ** and carriage returns.) There are now quoting characters of any ** kind. The length of a token is limited to about 1000 characters. */ static void AddParameters(int index, int *pArgc, char ***pArgv){ int argc = *pArgc; /* The original argc value */ char **argv = *pArgv; /* The original argv value */ int newArgc; /* Value for argc after inserting new arguments */ char **zNew; /* The new argv after this routine is done */ char *zFile; /* Name of the input file */ int nNew = 0; /* Number of new entries in the argv[] file */ int nAlloc = 0; /* Space allocated for zNew[] */ int i; /* Loop counter */ int n; /* Number of characters in a new argument */ int c; /* Next character of input */ int startOfLine = 1; /* True if we are where '#' can start a comment */ FILE *in; /* The input file */ char zBuf[1000]; /* A single argument is accumulated here */ if( index+1==argc ) return; zFile = argv[index+1]; in = fopen(zFile,"r"); if( in==0 ){ fprintf(stderr,"Can't open input file \"%s\"\n",zFile); exit(1); } c = ' '; while( c!=EOF ){ while( c!=EOF && isspace(c) ){ if( c=='\n' ){ startOfLine = 1; } c = getc(in); if( startOfLine && c=='#' ){ while( c!=EOF && c!='\n' ){ c = getc(in); } } } n = 0; while( c!=EOF && !isspace(c) ){ if( n0 ){ nNew++; if( nNew + argc > nAlloc ){ if( nAlloc==0 ){ nAlloc = 100 + argc; zNew = malloc( sizeof(char*) * nAlloc ); }else{ nAlloc *= 2; zNew = realloc( zNew, sizeof(char*) * nAlloc ); } } if( zNew ){ int j = nNew + index; zNew[j] = malloc( n + 1 ); if( zNew[j] ){ strcpy( zNew[j], zBuf ); } } } } newArgc = argc + nNew - 1; for(i=0; i<=index; i++){ zNew[i] = argv[i]; } for(i=nNew + index + 1; ipNext = pFile; pTail = pFile; }else{ pFileList = pTail = pFile; } } } } if( h_flag && H_flag ){ h_flag = 0; } if( v_flag ){ report = (h_flag || H_flag) ? stderr : stdout; }else{ report = 0; } if( nErr>0 ){ return nErr; } for(pFile=pFileList; pFile; pFile=pFile->pNext){ char *zFile; zFilename = pFile->zSrc; if( zFilename==0 ) continue; zFile = ReadFile(zFilename); if( zFile==0 ){ fprintf(stderr,"Can't read input file \"%s\"\n",zFilename); nErr++; continue; } if( strncmp(zFile,zTopLine,nTopLine)==0 ){ pFile->zSrc = 0; }else{ if( report ) fprintf(report,"Reading %s...\n",zFilename); pList = TokenizeFile(zFile,&pFile->idTable); if( pList ){ nErr += ParseFile(pList,pFile->flags); FreeTokenList(pList); }else if( zFile[0]==0 ){ fprintf(stderr,"Input file \"%s\" is empty.\n", zFilename); nErr++; }else{ fprintf(stderr,"Errors while processing \"%s\"\n", zFilename); nErr++; } } if( !doc_flag ) SafeFree(zFile); if( doc_flag ) PrintModuleRecord(zFile,zFilename); } if( nErr>0 ){ return nErr; } #ifdef DEBUG if( debugMask & DECL_DUMP ){ DumpDeclList(); return nErr; } #endif if( doc_flag ){ DocumentationDump(); return nErr; } zFilename = "--internal--"; pList = TokenizeFile(zInit,0); if( pList==0 ){ return nErr+1; } ParseFile(pList,PS_Interface); FreeTokenList(pList); if( h_flag || H_flag ){ nErr += MakeGlobalHeader(H_flag); }else{ for(pFile=pFileList; pFile; pFile=pFile->pNext){ if( pFile->zSrc==0 ) continue; nErr += MakeHeader(pFile,report,0); } } return nErr; } #endif tkHTML-4ee7aaa953d6cb59/tools/maketokens.tcl000064400000000000000000000043051151224263100201240ustar00nobodynobody#!/bin/sh # This script is a replacement for the maketokens.sh shell script. # The shell script required GNU awk. This script should work with # any old version of tclsh. # \ exec tclsh "$0" ${1+"$@"} if {$argc!=1} { puts stderr "Usage: $argv0 tokenlist.txt" exit 1 } if {[catch {open [lindex $argv 0] r} f]} { puts stderr "$argv0: can not open \"[lindex $argv 0]\": $f" exit 1 } set tokenlist {} while {![eof $f]} { set line [string trim [gets $f]] if {$line==""} continue if {[string index $line 0]=="#"} continue if {[llength $line]!=2 && [llength $line]!=3} continue lappend tokenlist [lindex $line 0] lappend tokenlist [lindex $line 1] lappend tokenlist [lindex $line 2] } close $f # Open the two files that will be generated. set h_file [open htmltokens2.h w] set c_file [open htmltokens.c w] set warning { /* * DO NOT EDIT! * * The code in this file was automatically generated. See the files * src/tokenlist.txt and tools/maketokens.tcl from the tkhtml source * distribution. */ } puts $h_file $warning puts $c_file $warning puts $h_file { #define Html_Text 1 #define Html_Space 2 #define Html_Unknown 3 #define Html_Block 4 #define HtmlIsMarkup(X) ((X)->base.type>Html_Block) } set count 5 set fmt {#define %-20s %d} foreach {name start end} $tokenlist { set upr [string toupper $name] puts $h_file [format $fmt Html_$upr $count] incr count if {$end!=""} { puts $h_file [format $fmt Html_End$upr $count] incr count } } puts $h_file [format $fmt Html_TypeCount [expr $count-1]] puts $h_file "#define HTML_MARKUP_HASH_SIZE [expr $count+11]" puts $h_file "#define HTML_MARKUP_COUNT [expr $count-5]" puts $c_file "HtmlTokenMap HtmlMarkupMap\[\] = {" set fmt " { %-15s %-25s %-30s }," foreach {name start end} $tokenlist { set upr [string toupper $name] set nm "\"$name\"," set val Html_$upr, if {$start=="0"} { set size "0," } else { set size "sizeof($start)," } puts $c_file [format $fmt $nm $val $size] if {$end==""} continue set nm "\"/$name\"," set val Html_End$upr, if {$end=="0"} { set size "0," } else { set size "sizeof($end)," } puts $c_file [format $fmt $nm $val $size] } puts $c_file "};" close $c_file close $h_file tkHTML-4ee7aaa953d6cb59/tools/manpage_clean000075500000000000000000000002521151224263100177540ustar00nobodynobody#!/bin/sh # Assume call with pwd = 'doc'. # Remove all files generated by 'manpage_regen' rm ../tools/rules/manpages rm *.n rm *.html rm ../htdocs/mp.*.html tkHTML-4ee7aaa953d6cb59/tools/manpage_regen000075500000000000000000000015171151224263100177770ustar00nobodynobody#!/bin/sh # Assume call with pwd = 'doc'. # Phase I ... List known manpages ... rm ../tools/rules/manpages touch ../tools/rules/manpages for i in `ls *.man` do echo $i '-->' manpages ../tools/expand -rules ../tools/rules/manpage.list $i >> ../tools/rules/manpages done # Phase II .. Generate true output ... for i in `ls *.man` do echo $i '-->' `basename $i .man`.n ../tools/expand -rules ../tools/rules/manpage.nroff $i > `basename $i .man`.n echo $i '-->' `basename $i .man`.html ../tools/expand -rules ../tools/rules/manpage.html $i > `basename $i .man`.html echo $i '-->' `basename $i .man`.html ../tools/expand -rules ../tools/rules/manpage.html.site $i > ../htdocs/mp.`basename $i .man`.html echo $i '-->' `basename $i .man`.tmml ../tools/expand -rules ../tools/rules/manpage.tmml $i > `basename $i .man`.tmml done tkHTML-4ee7aaa953d6cb59/tools/mkcsstester.tcl000064400000000000000000000113631151224263100203340ustar00nobodynobody if {[llength $argv]==0} { puts stderr [subst -nocommands { This script is used to generate an html/javascript application to make running through the CSS 2.1 test suite less painful. It can also be used with other (similarly designed) test suites and other browsers. To use, cd into the directory containing the test files and run this script with each test file as an argument. For example, if using the CSS2.1 test suite: $argv0 t*.htm (since all test files in that particular test suite match the pattern t*.htm). This generates 3 files: hv3_csstester.html, hv3_csstester_mainframe.html and hv3_csstester_testlist.html. Then load hv3_csstester.html into the browser and you're away. This has been tested with Hv3, Opera 9 and Firefox 3. }] exit 0 } set TemplateOne { } set TemplateTwo {

      Test Case:

      } set TemplateThree { $table_list_content
      } set TemplateFour {
      } proc write_file {fname content} { set fd [open $fname w] puts -nonewline $fd $content close $fd } # Build up table_list_content: set table_list_content {} set d 1 foreach a $argv { append table_list_content "
      $d. " append table_list_content "$a" incr d } write_file hv3_csstester.html $TemplateOne write_file hv3_csstester_mainframe.html $TemplateTwo write_file hv3_csstester_testlist.html [subst -nocommands $TemplateThree] write_file hv3_csstester_report.html $TemplateFour tkHTML-4ee7aaa953d6cb59/tools/mkinstalldirs000075500000000000000000000012111151224263100200560ustar00nobodynobody#!/bin/sh # mkinstalldirs --- make directory hierarchy # Author: Noah Friedman # Created: 1993-05-16 # Last modified: 1994-03-25 # Public domain errstatus=0 for file in ${1+"$@"} ; do set fnord `echo ":$file" | sed -ne 's/^:\//#/;s/^://;s/\// /g;s/^#/\//;p'` shift pathcomp= for d in ${1+"$@"} ; do pathcomp="$pathcomp$d" case "$pathcomp" in -* ) pathcomp=./$pathcomp ;; esac if test ! -d "$pathcomp"; then echo "mkdir $pathcomp" 1>&2 mkdir "$pathcomp" || errstatus=$? fi pathcomp="$pathcomp/" done done exit $errstatus # mkinstalldirs ends here tkHTML-4ee7aaa953d6cb59/tools/mktclapp.c000064400000000000000000003130171151224263100172410ustar00nobodynobody/* ** Copyright (c) 1998, 1999 D. Richard Hipp ** ** This program is free software; you can redistribute it and/or ** modify it under the terms of the GNU General Public ** License as published by the Free Software Foundation; either ** version 2 of the License, or (at your option) any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ** General Public License for more details. ** ** You should have received a copy of the GNU General Public ** License along with this library; if not, write to the ** Free Software Foundation, Inc., 59 Temple Place - Suite 330, ** Boston, MA 02111-1307, USA. ** ** Author contact information: ** drh@acm.org ** http://www.hwaci.com/drh/ */ #include #include #include #include #include #if defined(_WIN32) || defined(WIN32) # include # if !defined(R_OK) # define R_OK 4 # endif #else # include #endif #include #include /* ** Version information for this program */ static char zVersion[] = "mktclapp version 3.5. July 5, 1999"; /* ** Each new TCL commands discovered while scanning C/C++ source code is ** stored in an instance of the following structure. */ typedef struct EtCmd EtCmd; struct EtCmd { char *zIf; /* Surrounding #if statement */ char *zName; /* Name of the command */ int isObj; /* True if this is a Tcl_Obj command */ EtCmd *pNext; /* Next command on a list of them all */ }; /* ** This is a list of all TCL commands in the scanned source */ static EtCmd *cmdList = 0; /* ** Number of commands and object commands. */ static int nCmd = 0; static int nObjCmd = 0; /* ** Each nested "#if" statement is stored as an instance of the ** following structure. */ typedef struct IfStmt IfStmt; struct IfStmt { char *zArg; /* Argument to the #if. Ex: "defined(DEBUG)" */ int invert; /* True to put a "!" in front */ int line; /* Line number of the original #if */ IfStmt *pNext; /* Next #if statement down on the stack */ }; /* ** The nested #if statements */ static IfStmt *ifStack = 0; /* ** Name of this program. */ static char *Argv0 = "mktclapp"; /* ** Number of errors */ static int nError = 0; /* ** Surround the call to Et_AppInit() with this #if */ static char *seenEtAppInit = "0"; /* ** Surround the call to Et_PreInit() with this #if */ static char *seenEtPreInit = "0"; /* ** Surround the implmentation of main() with the inverse of this #if */ static char *seenMain = "0"; /* ** Allocate memory. Never fail. If not enough memory is available, ** print an error message and abort. */ void *SafeMalloc(int nByte){ void *p = malloc(nByte); if( p==0 ){ fprintf(stderr,"Out of memory. Can't allocate %d bytes\n", nByte); exit(1); } memset(p, 0, nByte); return p; } void *SafeRealloc(void *old, int nByte){ void *p; if( old==0 ) return SafeMalloc(nByte); p = realloc(old, nByte); if( p==0 ){ fprintf(stderr,"Out of memory. Can't allocate %d bytes\n", nByte); exit(1); } return p; } /* ** The opposite of SafeMalloc(). Free memory previously obtained. */ void SafeFree(void *pMem){ if( pMem ) free(pMem); } /* ** Return TRUE if the given character can be part of a C identifier. */ static int IsIdent(int c){ return isalnum(c) || c=='_'; } /* ** Create an "#if" argument that captures the state of all nested ** "#if" statements, ORed with "zExtra". Space to hold ** the returned string is obtained from SafeMalloc and must be ** freed by the calling function. ** ** If the conditional is always TRUE, then NULL is returned. */ static char *IfString(char *zExtra){ int len = 0; IfStmt *p; char *z; int i; int isStackTrue = 1; int isStackFalse = 0; int isExtraFalse = 0; char *zSep; IfStmt *altStack; if( zExtra && *zExtra ){ if( zExtra[1]==0 && zExtra[0]=='0' ){ isExtraFalse = 1; }else if( zExtra[1]==0 && zExtra[0]=='1' ){ return 0; } len = strlen(zExtra) + 10; }else{ len = 1; isExtraFalse = 1; } for(p=ifStack; p; p=p->pNext){ len += strlen(p->zArg) + 6; if( p->zArg[0]=='0' && p->zArg[1]==0 ){ if( !p->invert ){ isStackFalse = 1; isStackTrue = 0; break; } }else if( p->zArg[0]=='1' && p->zArg[1]==0 ){ if( p->invert ){ isStackFalse = 1; isStackTrue = 0; break; } }else{ isStackTrue = 0; } } if( isStackTrue ){ return 0; }else if( isStackFalse && isExtraFalse ){ z = SafeMalloc( 2 ); strcpy(z,"0"); return z; } z = SafeMalloc( len ); if( !isExtraFalse ){ sprintf(z,"(%s) || (",zExtra); i = strlen(z); }else{ i = 0; } zSep = ""; altStack = 0; while( ifStack ){ p = ifStack; ifStack = p->pNext; p->pNext = altStack; altStack = p; } for(p=altStack; p; p=p->pNext){ if( p->zArg[0]=='0' && p->zArg[1]==0 && p->invert ) continue; if( p->zArg[0]=='1' && p->zArg[1]==0 && !p->invert ) continue; if( p->invert ){ sprintf(&z[i],"%s!%s",zSep,p->zArg); }else{ sprintf(&z[i],"%s%s",zSep,p->zArg); } i += strlen(&z[i]); zSep = " && "; } while( altStack ){ p = altStack; altStack = p->pNext; p->pNext = ifStack; ifStack = p; } if( !isExtraFalse ){ sprintf(&z[i],")"); } return z; } /* ** Push a new "#if" onto the if stack. */ static void PushIf(char *zArg, int line, int isNegated, int isDefined){ char *z; IfStmt *p; if( !isDefined ){ int i; z = SafeMalloc( strlen(zArg) + 3 ); for(i=0; zArg[i] && IsIdent(zArg[i]); i++){} if( zArg[i]==0 ){ sprintf(z,"%s",zArg); }else{ sprintf(z,"(%s)",zArg); } }else{ z = SafeMalloc( strlen(zArg) + 10 ); sprintf(z,"defined(%s)",zArg); } p = SafeMalloc( sizeof(IfStmt) ); p->zArg = z; p->line = line; p->invert = isNegated; p->pNext = ifStack; ifStack = p; } /* ** Extract the argument to an #if. Remove all leading and trailing ** space. */ static char *GetArg(const char *fileName, char *z, int *pI, int *pLine){ int i = *pI; int line = *pLine; int start; char *zResult; int j, k; while( isspace(z[i]) && z[i]!='\n' ){ i++; } start = i; if( z[i]=='\n' || z[i]==0 ){ fprintf(stderr,"%s: Missing argument to \"#if\" on line %d\n", fileName, *pLine); nError++; line++; }else{ while( z[i] && z[i]!='\n' ){ if( z[i]=='\\' && z[i+1]!=0 ){ i++; } if( z[i]=='\n' ){ line++; } i++; } } zResult = SafeMalloc( i + 1 - start ); for(j=0, k=start; k0 && isspace(zResult[j-1]) ){ /* Do nothing */ }else if( z[k]=='\\' && z[k+1]=='\n' ){ if( j>0 && !isspace(zResult[j-1]) ){ zResult[j++] = ' '; } k++; }else if( z[k]=='\\' ){ zResult[j++] = z[k++]; } zResult[j++] = z[k]; } zResult[j] = 0; while( j>0 && isspace(zResult[j-1]) ){ j--; zResult[j] = 0; } *pI = i; *pLine = line; return zResult; } /* ** Read the complete text of a file into memory. Return 0 if there ** is any kind of error. */ char *ReadFileIntoMemory(const char *fileName){ FILE *in; /* Input file stream */ char *textBuf; /* A buffer in which to put entire text of input */ int toRead; /* Amount of input file read to read */ int got; /* Amount read so far */ struct stat statBuf; /* Status buffer for the file */ if( stat(fileName,&statBuf)!=0 ){ fprintf(stderr,"%s: no such file: %s\n", Argv0, fileName); return 0; } textBuf = SafeMalloc( statBuf.st_size + 1 ); in = fopen(fileName,"rb"); if( in==0 ){ fprintf(stderr,"%s: can't open for reading: %s\n", Argv0, fileName); SafeFree(textBuf); return 0; } textBuf[statBuf.st_size] = 0; toRead = statBuf.st_size; got = 0; while( toRead ){ int n = fread(&textBuf[got],1,toRead,in); if( n<=0 ) break; toRead -= n; got += n; } fclose(in); textBuf[got] = 0; return textBuf; } /* ** Given the "aaaa" part of the name of an ET_COMMAND_aaaa function, ** compute the name of the corresponding Tcl command. ** ** The name is usually the same, except if there are two underscores ** in the middle of the command, they are changed to colons. This ** feature allows namespaces to be used. Example: The function ** named ** ** ET_COMMAND_space1__proc1(ET_TCLARGS){...} ** ** will generate a TCL command called ** ** space1::proc1 ** ** Space to hold the TCL command name is obtained from malloc(). */ static char *FuncToProc(char *zFunc){ char *zProc; int i; zProc = SafeMalloc( strlen(zFunc) + 1 ); strcpy(zProc, zFunc); for(i=0; zProc[i]; i++){ if( i>0 && zProc[i]=='_' && zProc[i+1]=='_' && isalnum(zProc[i-1]) && isalnum(zProc[i+2]) ){ zProc[i] = ':'; zProc[i+1] = ':'; } } return zProc; } /* ** Scan a source file looking for new TCL commands and/or the Et_AppInit() ** or Et_PreInit() functions. ** ** Skip all comments, and any text contained within "#if 0".."#endif" */ void ScanFile(const char *fileName){ char *z; /* Complete text of the file, NULL terminated. */ int i, j; int inBrace = 0; int line = 1; z = ReadFileIntoMemory(fileName); if( z==0 ){ nError++; return; } for(i=0; z[i]; i++){ switch( z[i] ){ case '\n': line++; break; case '/': /* This might be a comment. If it is, skip it. */ if( z[i+1]=='*' ){ int start = line; i += 2; while( z[i] && (z[i]!='*' || z[i+1]!='/') ){ if( z[i]=='\n' ) line++; i++; } if( z[i]==0 ){ fprintf(stderr,"%s: Unterminated comment beginning on line %d\n", fileName, start); nError++; }else{ i++; } }else if( z[i+1]=='/' ){ while( z[i] && z[i]!='\n' ){ i++; } if( z[i] ){ line++; }; } break; case '\'': { /* Skip character literals */ int start = line; for(i++; z[i] && z[i]!='\''; i++){ if( z[i]=='\n' ){ fprintf(stderr,"%s: Newline in character literal on line %d\n", fileName, start); line++; } if( z[i]=='\\' ) i++; } if( z[i]==0 ){ fprintf(stderr,"%s: unterminate character literal on line %d\n", fileName, start); nError++; } break; } case '"': { /* Skip over a string */ int start = line; for(i++; z[i] && z[i]!='"'; i++){ if( z[i]=='\n' ){ fprintf(stderr,"%s: Newline in string literal on line %d\n", fileName, start); line++; } if( z[i]=='\\' ) i++; } if( z[i]==0 ){ fprintf(stderr,"%s: unterminate string literal on line %d\n", fileName, start); nError++; } break; } case '#': /* This might be a preprocessor macro such as #if 0 or #endif */ if( i>0 && z[i-1]!='\n' ) break; for(j=i+1; isspace(z[j]); j++){} if( strncmp(&z[j],"endif",5)==0 ){ if( ifStack==0 ){ fprintf(stderr,"%s: Unmatched \"#endif\" on line %d\n", fileName, line); nError++; }else{ IfStmt *p = ifStack; ifStack = p->pNext; SafeFree(p->zArg); SafeFree(p); } break; } if( strncmp(&z[j],"else",4)==0 ){ if( ifStack==0 ){ fprintf(stderr,"%s: No \"#if\" to pair with \"#else\" on line %d\n", fileName, line); nError++; }else{ ifStack->invert = !ifStack->invert; } break; } if( z[j]!='i' || z[j+1]!='f' ) break; if( strncmp(&z[j+2],"ndef",4)==0 ){ char *zArg; int start = line; i = j+6; zArg = GetArg(fileName, z,&i,&line); PushIf(zArg,start,1,1); SafeFree(zArg); }else if( strncmp(&z[j+2],"def",3)==0 ){ char *zArg; int start = line; i = j+5; zArg = GetArg(fileName,z,&i,&line); PushIf(zArg,start,0,1); SafeFree(zArg); }else{ char *zArg; int start = line; i = j+2; zArg = GetArg(fileName,z,&i,&line); PushIf(zArg,start,0,0); SafeFree(zArg); } break; case '{': inBrace++; break; case '}': inBrace--; break; case 'm': /* Check main() */ if( inBrace>0 ) break; if( i>0 && IsIdent(z[i-1]) ) break; if( strncmp(&z[i],"main",4)==0 && !IsIdent(z[i+4]) ){ seenMain = IfString(seenMain); } case 'E': /* Check ET_COMMAND_... or Et_AppInit or Et_PreInit */ if( inBrace>0 ) break; if( i>0 && IsIdent(z[i-1]) ) break; if( z[i+1]=='T' && strncmp(&z[i],"ET_COMMAND_",11)==0 ){ EtCmd *p; for(j=i+11; IsIdent(z[j]); j++){} p = SafeMalloc( sizeof(EtCmd) ); p->zIf = IfString(0); p->zName = SafeMalloc( j-(i+9) ); sprintf(p->zName,"%.*s",j-(i+11),&z[i+11]); p->pNext = cmdList; cmdList = p; nCmd++; }else if( z[i+1]=='T' && strncmp(&z[i],"ET_OBJCOMMAND_",14)==0 ){ EtCmd *p; for(j=i+14; IsIdent(z[j]); j++){} p = SafeMalloc( sizeof(EtCmd) ); p->zIf = IfString(0); p->zName = SafeMalloc( j-(i+9) ); p->isObj = 1; sprintf(p->zName,"%.*s",j-(i+14),&z[i+14]); p->pNext = cmdList; cmdList = p; nObjCmd++; }else if( z[i+1]=='t' ){ if( strncmp(&z[i],"Et_AppInit",10)==0 && !IsIdent(z[i+10]) ){ seenEtAppInit = IfString(seenEtAppInit); } if( strncmp(&z[i],"Et_PreInit",10)==0 && !IsIdent(z[i+10]) ){ seenEtPreInit = IfString(seenEtPreInit); } } break; default: /* Do nothing. Continue to the next character */ break; } } SafeFree(z); while( ifStack ){ IfStmt *p = ifStack; fprintf(stderr,"%s: unterminated \"#if\" on line %d\n", fileName, p->line); nError++; ifStack = p->pNext; SafeFree(p->zArg); SafeFree(p); } } /* ** Set a macro according to the value of an #if argument. */ static void SetMacro(char *zMacroName, char *zIf){ if( zIf==0 || *zIf==0 ){ printf("#define %s 1\n",zMacroName); }else if( zIf[0]=='0' && zIf[1]==0 ){ printf("#define %s 0\n",zMacroName); }else{ printf( "#if %s\n" "# define %s 1\n" "#else\n" "# define %s 0\n" "#endif\n", zIf, zMacroName, zMacroName ); } } /* ** Look at the name of the file given and see if it is a Tcl file ** or a C or C++ source file. Return TRUE for TCL and FALSE for ** C or C++. */ static int IsTclFile(char *zFile){ static char *azCSuffix[] = { ".c", ".cc", ".C", ".cpp", ".CPP", ".cxx", ".CXX" }; int len = strlen(zFile); int i; for(i=0; ilen2 && strcmp(&zFile[len-len2],azCSuffix[i])==0 ){ return 0; } } return 1; } /* ** Compress a TCL script by removing comments and excess white-space */ static void CompressTcl(char *z){ int i, j, c; int atLineStart = 1; for(i=j=0; (c=z[i])!=0; i++){ switch( c ){ case ' ': case '\t': if( atLineStart ){ c = 0; } break; case '#': if( atLineStart && !isalpha(z[i+1]) ){ while( z[i] && z[i]!='\n' ){ i++; } c = 0; if( z[i]==0 ){ i--; } }else{ atLineStart = 0; } break; case '\n': if( atLineStart ){ c = 0; }else{ atLineStart = 1; } break; default: atLineStart = 0; break; } if( c!=0 ){ z[j++] = c; } } z[j] = 0; } /* ** Write the text of the given file as a string. Tcl-style comments ** are removed if the doCompress flag is true. */ static void WriteAsString(char *z, int shroud){ int c; int xor; int atLineStart = 1; if( shroud>0 ){ xor = shroud; } putchar('"'); atLineStart = 0; while( (c=*z)!=0 ){ z++; if( c=='\r' && *z=='\n' ) continue; if( shroud>0 && c>=0x20 ){ c ^= xor; xor = (xor+1)&0x1f; } if( atLineStart ){ putchar('"'); atLineStart = 0; } switch( c ){ case '"': case '\\': putchar('\\'); putchar(c); break; case '\n': putchar('\\'); putchar('n'); putchar('"'); putchar('\n'); atLineStart = 1; break; default: if( c<' ' || c>'~' ){ putchar('\\'); putchar( ((c>>6)&3) + '0' ); putchar( ((c>>3)&7) + '0' ); putchar( (c&7) + '0' ); }else{ putchar(c); } break; } } if( !atLineStart ){ putchar('"'); putchar('\n'); } } /* ** The header string. */ static char zHeader[] = "/* Automatically generated code */\n" "/* DO NOT EDIT */\n" "#ifndef ET_TCLARGS\n" "#include \n" "#ifdef __cplusplus\n" "# define ET_EXTERN extern \"C\"\n" "#else\n" "# define ET_EXTERN extern\n" "#endif\n" "ET_EXTERN char *mprintf(const char*,...);\n" "ET_EXTERN char *vmprintf(const char*,...);\n" "ET_EXTERN int Et_EvalF(Tcl_Interp*,const char *,...);\n" "ET_EXTERN int Et_GlobalEvalF(Tcl_Interp*,const char *,...);\n" "ET_EXTERN int Et_DStringAppendF(Tcl_DString*,const char*,...);\n" "ET_EXTERN int Et_ResultF(Tcl_Interp*,const char*,...);\n" "ET_EXTERN Tcl_Interp *Et_Interp;\n" "#if TCL_RELEASE_VERSION>=8\n" "ET_EXTERN int Et_AppendObjF(Tcl_Obj*,const char*,...);\n" "#endif\n" "#define ET_TCLARGS " "ClientData clientData,Tcl_Interp*interp,int argc,char**argv\n" "#define ET_OBJARGS " "ClientData clientData,Tcl_Interp*interp,int objc,Tcl_Obj *CONST objv[]\n" "#endif\n" ; /* ** Print a usage comment and die */ static void Usage(char *argv0){ fprintf(stderr,"Usage: %s arguments...\n", argv0); fprintf(stderr, " -header print a header file and exit\n" " -srcdir DIR Prepend DIR to all relative pathnames\n" " -version print the version number of mktclapp and exit\n" " -notk built a Tcl-only program. No GUI\n" " -autofork automatically fork the program into the background\n" " -strip-tcl remove comments and extra white-space from\n" " subsequent TCL files\n" " -dont-strip-tcl stop stripping TCL files\n" " -tcl-library directory holding the TCL script library\n" " -tk-library directory holding the TK script library\n" " -main-script FILE run the script FILE after initialization\n" " -read-stdin read standard input\n" " -console create a console window\n" " -shroud hide compile-in TCL from view\n" " -enable-obj use TCL Obj commands where possible\n" " -standalone make the \"source\" TCL command only work\n" " for builtin scripts\n" " -f FILE read more command-line parameters from FILE\n" " *.c scan this file for new TCL commands\n" " *.tcl compile this file into the generated C code\n" ); exit(1); } /* ** Read one or more characters form "in" that follow a \ and ** interpret them appropriately. Return the character that ** results from this interpretation. */ static int EscapeChar(FILE *in){ int c, d; c = getc(in); switch( c ){ case 'n': c = '\n'; break; case 'r': c = '\r'; break; case 'f': c = '\f'; break; case 't': c = '\t'; break; case 'b': c = '\b'; break; case 'a': c = '\a'; break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': c -= '0'; d = getc(in); if( d<'0' || d>'7' ){ ungetc(d,in); break; } c = (c<<3) + (d - '0'); if( d<'0' || d>'7' ){ ungetc(d,in); break; } c = (c<<3) + (d - '0'); break; default: break; } return c; } /* MS-Windows and MS-DOS both have the following serious OS bug: the ** length of a command line is severely restricted. But this program ** occasionally requires long command lines. Hence the following ** work around. ** ** If the parameters "-f FILENAME" appear anywhere on the command line, ** then the named file is scanned for additional command line arguments. ** These arguments are substituted in place of the "FILENAME" argument ** in the original argument list. ** ** This first parameter to this routine is the index of the "-f" ** parameter in the argv[] array. The argc and argv are passed by ** pointer so that they can be changed. ** ** Parsing of the parameters in the file is very simple. Parameters ** can be separated by any amount of white-space (including newlines ** and carriage returns.) " and ' can be used for quoting strings ** with embedded spaces. The \ character escapes the following character. ** The length of a token is limited to about 1000 characters. */ static void AddParameters(int index, int *pArgc, char ***pArgv){ int argc = *pArgc; /* The original argc value */ char **argv = *pArgv; /* The original argv value */ int newArgc; /* Value for argc after inserting new arguments */ char **zNew; /* The new argv after this routine is done */ char *zFile; /* Name of the input file */ int nNew = 0; /* Number of new entries in the argv[] file */ int nAlloc = 0; /* Space allocated for zNew[] */ int i; /* Loop counter */ int n; /* Number of characters in a new argument */ int c; /* Next character of input */ int startOfLine = 1; /* True if we are where '#' can start a comment */ FILE *in; /* The input file */ char zBuf[1000]; /* A single argument is accumulated here */ if( index+1==argc ) return; zFile = argv[index+1]; in = fopen(zFile,"r"); if( in==0 ){ fprintf(stderr,"Can't open input file \"%s\"\n",zFile); exit(1); } c = ' '; while( c!=EOF ){ while( c!=EOF && isspace(c) ){ if( c=='\n' ){ startOfLine = 1; } c = getc(in); if( startOfLine && c=='#' ){ while( c!=EOF && c!='\n' ){ c = getc(in); } } } n = 0; if( c=='\'' || c=='"' ){ int quote = c; c = getc(in); startOfLine = 0; while( c!=EOF && c!=quote ){ if( c=='\\' ) c = EscapeChar(in); if( n0 ){ nNew++; if( nNew + argc >= nAlloc ){ if( nAlloc==0 ){ nAlloc = 100 + argc; zNew = malloc( sizeof(char*) * nAlloc ); }else{ nAlloc *= 2; zNew = realloc( zNew, sizeof(char*) * nAlloc ); } } if( zNew ){ int j = nNew + index; zNew[j] = malloc( n + 1 ); if( zNew[j] ){ strcpy( zNew[j], zBuf ); } } } } if( nNew>0 ){ newArgc = argc + nNew - 1; for(i=0; i<=index; i++){ zNew[i] = argv[i]; } }else{ zNew = argv; } for(i=nNew + index + 1; i=2 && strcmp(argv[1],"-header")==0 ){ printf("%s",zHeader); return 0; } if( argc>=2 && strcmp(argv[1],"-version")==0 ){ printf("%s\n",zVersion); return 0; } azTcl = SafeMalloc( sizeof(char*)*(argc + 100) ); aDoCompress = SafeMalloc( sizeof(int)*(argc + 100) ); for(i=1; i=9 && strcmp(&argv[i][len-9],"/tclIndex")==0 ){ aDoCompress[nTcl] = 0; }else{ aDoCompress[nTcl] = doCompress; } nTcl++; } }else{ ScanFile(argv[i]); } } if( nError>0 ) return nError; if( stringify ){ for(i=0; i0 ) enableObj = 1; printf( "/* This code is automatically generated by \"mktclapp\" */\n" "/* DO NOT EDIT */\n" "#include \n" "#define INTERFACE 1\n" "#if INTERFACE\n" "#define ET_TCLARGS " "ClientData clientData,Tcl_Interp*interp,int argc,char**argv\n" "#define ET_OBJARGS " "ClientData clientData,Tcl_Interp*interp,int objc,Tcl_Obj*CONST objv[]\n" "#endif\n" ); printf("#define ET_ENABLE_OBJ %d\n", enableObj); printf("#define ET_ENABLE_TK %d\n", useTk!=0); printf("#define ET_AUTO_FORK %d\n", autoFork!=0); printf("#define ET_STANDALONE %d\n", standalone!=0); SetMacro("ET_HAVE_APPINIT",seenEtAppInit); SetMacro("ET_HAVE_PREINIT",seenEtPreInit); SetMacro("ET_HAVE_MAIN",seenMain); if( zTclLib ){ printf("#define ET_TCL_LIBRARY "); WriteAsString(zTclLib,0); } if( zTkLib ){ printf("#define ET_TK_LIBRARY "); WriteAsString(zTkLib,0); } if( zMainScript ){ printf("#define ET_MAIN_SCRIPT "); WriteAsString(zMainScript,0); } if( shroud>0 ){ shroud = time(0) % 31 + 1; } printf("#define ET_SHROUD_KEY %d\n",shroud); printf("#define ET_READ_STDIN %d\n",readStdin); printf("#define ET_CONSOLE %d\n",console); for(pCmd=cmdList; pCmd; pCmd=pCmd->pNext){ if( pCmd->zIf && pCmd->zIf[0]=='0' && pCmd->zIf[1]==0 ) continue; if( pCmd->isObj ){ printf("extern int ET_OBJCOMMAND_%s(ET_OBJARGS);\n", pCmd->zName); }else{ printf("extern int ET_COMMAND_%s(ET_TCLARGS);\n", pCmd->zName); } } printf( "static struct {\n" " char *zName;\n" " int (*xProc)(ET_TCLARGS);\n" "} Et_CmdSet[] = {\n" ); for(pCmd=cmdList; pCmd; pCmd=pCmd->pNext){ char *zProc; if( pCmd->isObj ) continue; if( pCmd->zIf ){ if( pCmd->zIf[0]=='0' && pCmd->zIf[1]==0 ) continue; printf("#if %s\n",pCmd->zIf); } zProc = FuncToProc(pCmd->zName); printf(" { \"%s\", ET_COMMAND_%s },\n", zProc, pCmd->zName); SafeFree(zProc); if( pCmd->zIf ){ printf("#endif\n"); } } printf("{0, 0}};\n"); if( enableObj ){ char *zProc; printf( "static struct {\n" " char *zName;\n" " int (*xProc)(ET_OBJARGS);\n" "} Et_ObjSet[] = {\n" ); for(pCmd=cmdList; pCmd; pCmd=pCmd->pNext){ if( !pCmd->isObj ) continue; if( pCmd->zIf ){ if( pCmd->zIf[0]=='0' && pCmd->zIf[1]==0 ) continue; printf("#if %s\n",pCmd->zIf); } zProc = FuncToProc(pCmd->zName); printf(" { \"%s\", ET_OBJCOMMAND_%s },\n", zProc, pCmd->zName); SafeFree(zProc); if( pCmd->zIf ){ printf("#endif\n"); } } printf("{0, 0}};\n"); } for(i=0; i\n" "#include \n" "#include \n" "#include \n" "#if ET_ENABLE_TK\n" "# include \n" "#else\n" "# include \n" "#endif\n" "#include \n" "#include \n" "#include \n" "#include \n" "\n" "/*\n" "** ET_WIN32 is true if we are running Tk under windows. The\n" "** module will define __WIN32__ for us if we are compiling\n" "** for windows.\n" "*/\n" "#if defined(__WIN32__) && ET_ENABLE_TK\n" "# define ET_WIN32 1\n" "# include \n" "#else\n" "# define ET_WIN32 0\n" "#endif\n" "\n" "/*\n" "** Always disable ET_AUTO_FORK under windows. Windows doesn't\n" "** fork well.\n" "*/\n" "#if defined(__WIN32__)\n" "# undef ET_AUTO_FORK\n" "# define ET_AUTO_FORK 0\n" "#endif\n" "\n" "/*\n" "** Omit under windows.\n" "*/\n" "#if !defined(__WIN32__)\n" "# include \n" "#endif\n" "\n" "/*\n" "** The Tcl*InsertProc functions allow the system calls \"stat\",\n" "** \"access\" and \"open\" to be overloaded. This in turns allows us\n" "** to substituted compiled-in strings for files in the filesystem.\n" "** But the Tcl*InsertProc functions are only available in Tcl8.0.3\n" "** and later.\n" "**\n" "** Define the ET_HAVE_INSERTPROC macro if and only if we are dealing\n" "** with Tcl8.0.3 or later.\n" "*/\n" "#if TCL_MAJOR_VERSION==8 && (TCL_MINOR_VERSION>0 || TCL_RELEASE_SERIAL>=3)\n" "# define ET_HAVE_INSERTPROC\n" "#endif\n" "\n" "/*\n" "** Don't allow Win32 applications to read from stdin. Nor do\n" "** programs that automatically go into the background. Force\n" "** the use of a console in these cases.\n" "*/\n" "#if (ET_WIN32 || ET_AUTO_FORK) && ET_READ_STDIN\n" "# undef ET_READ_STDIN\n" "# undef ET_CONSOLE\n" "# define ET_READ_STDIN 0\n" "# define ET_CONSOLE 1\n" "#endif\n" "\n" "/*\n" "** The console won't work without Tk.\n" "*/\n" "#if ET_ENABLE_TK==0 && ET_CONSOLE\n" "# undef ET_CONSOLE\n" "# define ET_CONSOLE 0\n" "# undef ET_READ_STDIN\n" "# define ET_READ_STDIN 1\n" "#endif\n" "\n" "/*\n" "** Set ET_HAVE_OBJ to true if we are able to link against the\n" "** new Tcl_Obj interface.\n" "*/\n" "#if ET_ENABLE_OBJ || TCL_MAJOR_VERSION>=8\n" "# define ET_HAVE_OBJ 1\n" "#else\n" "# define ET_HAVE_OBJ 0\n" "#endif\n" "\n" "/*\n" "** The Tcl_GetByteArrayFromObj() only appears in Tcl version 8.1\n" "** and later. Substitute Tcl_GetStringFromObj() in Tcl version 8.0.X\n" "*/\n" "#if ET_HAVE_OBJ && TCL_MINOR_VERSION==0\n" "# define Tcl_GetByteArrayFromObj Tcl_GetStringFromObj\n" "#endif\n" "\n" "/*\n" "** Tcl code to implement the console.\n" "**\n" "** This code is written and tested separately, then run through\n" "** \"mktclapp -stringify\" and then pasted in here.\n" "*/\n" "#if ET_CONSOLE\n" "static char zEtConsole[] = \n" "\"proc console:create {w prompt title} {\\n\"\n" "\"upvar #0 $w.t v\\n\"\n" "\"if {[winfo exists $w]} {destroy $w}\\n\"\n" "\"catch {unset v}\\n\"\n" "\"toplevel $w\\n\"\n" "\"wm title $w $title\\n\"\n" "\"wm iconname $w $title\\n\"\n" "\"frame $w.mb -bd 2 -relief raised\\n\"\n" "\"pack $w.mb -side top -fill x\\n\"\n" "\"menubutton $w.mb.file -text File -menu $w.mb.file.m\\n\"\n" "\"menubutton $w.mb.edit -text Edit -menu $w.mb.edit.m\\n\"\n" "\"pack $w.mb.file $w.mb.edit -side left -padx 8 -pady 1\\n\"\n" "\"set m [menu $w.mb.file.m]\\n\"\n" "\"$m add command -label {Source...} -command \\\"console:SourceFile $w.t\\\"\\n\"\n" "\"$m add command -label {Save As...} -command \\\"console:SaveFile $w.t\\\"\\n\"\n" "\"$m add separator\\n\"\n" "\"$m add command -label {Close} -command \\\"destroy $w\\\"\\n\"\n" "\"$m add command -label {Exit} -command exit\\n\"\n" "\"set m [menu $w.mb.edit.m]\\n\"\n" "\"$m add command -label Cut -command \\\"console:Cut $w.t\\\"\\n\"\n" "\"$m add command -label Copy -command \\\"console:Copy $w.t\\\"\\n\"\n" "\"$m add command -label Paste -command \\\"console:Paste $w.t\\\"\\n\"\n" "\"$m add command -label {Clear Screen} -command \\\"console:Clear $w.t\\\"\\n\"\n" "\"catch {$m config -postcommand \\\"console:EnableEditMenu $w\\\"}\\n\"\n" "\"scrollbar $w.sb -orient vertical -command \\\"$w.t yview\\\"\\n\"\n" "\"pack $w.sb -side right -fill y\\n\"\n" "\"text $w.t -font fixed -yscrollcommand \\\"$w.sb set\\\"\\n\"\n" "\"pack $w.t -side right -fill both -expand 1\\n\"\n" "\"bindtags $w.t Console\\n\"\n" "\"set v(text) $w.t\\n\"\n" "\"set v(history) 0\\n\"\n" "\"set v(historycnt) 0\\n\"\n" "\"set v(current) -1\\n\"\n" "\"set v(prompt) $prompt\\n\"\n" "\"set v(prior) {}\\n\"\n" "\"set v(plength) [string length $v(prompt)]\\n\"\n" "\"set v(x) 0\\n\"\n" "\"set v(y) 0\\n\"\n" "\"$w.t mark set insert end\\n\"\n" "\"$w.t tag config ok -foreground blue\\n\"\n" "\"$w.t tag config err -foreground red\\n\"\n" "\"$w.t insert end $v(prompt)\\n\"\n" "\"$w.t mark set out 1.0\\n\"\n" "\"catch {rename puts console:oldputs$w}\\n\"\n" "\"proc puts args [format {\\n\"\n" "\"if {![winfo exists %s]} {\\n\"\n" "\"rename puts {}\\n\"\n" "\"rename console:oldputs%s puts\\n\"\n" "\"return [uplevel #0 puts $args]\\n\"\n" "\"}\\n\"\n" "\"switch -glob -- \\\"[llength $args] $args\\\" {\\n\"\n" "\"{1 *} {\\n\"\n" "\"set msg [lindex $args 0]\\\\n\\n\"\n" "\"set tag ok\\n\"\n" "\"}\\n\"\n" "\"{2 stdout *} {\\n\"\n" "\"set msg [lindex $args 1]\\\\n\\n\"\n" "\"set tag ok\\n\"\n" "\"}\\n\"\n" "\"{2 stderr *} {\\n\"\n" "\"set msg [lindex $args 1]\\\\n\\n\"\n" "\"set tag err\\n\"\n" "\"}\\n\"\n" "\"{2 -nonewline *} {\\n\"\n" "\"set msg [lindex $args 1]\\n\"\n" "\"set tag ok\\n\"\n" "\"}\\n\"\n" "\"{3 -nonewline stdout *} {\\n\"\n" "\"set msg [lindex $args 2]\\n\"\n" "\"set tag ok\\n\"\n" "\"}\\n\"\n" "\"{3 -nonewline stderr *} {\\n\"\n" "\"set msg [lindex $args 2]\\n\"\n" "\"set tag err\\n\"\n" "\"}\\n\"\n" "\"default {\\n\"\n" "\"uplevel #0 console:oldputs%s $args\\n\"\n" "\"return\\n\"\n" "\"}\\n\"\n" "\"}\\n\"\n" "\"console:Puts %s $msg $tag\\n\"\n" "\"} $w $w $w $w.t]\\n\"\n" "\"after idle \\\"focus $w.t\\\"\\n\"\n" "\"}\\n\"\n" "\"bind Console <1> {console:Button1 %W %x %y}\\n\"\n" "\"bind Console {console:B1Motion %W %x %y}\\n\"\n" "\"bind Console {console:B1Leave %W %x %y}\\n\"\n" "\"bind Console {console:cancelMotor %W}\\n\"\n" "\"bind Console {console:cancelMotor %W}\\n\"\n" "\"bind Console {console:Insert %W %A}\\n\"\n" "\"bind Console {console:Left %W}\\n\"\n" "\"bind Console {console:Left %W}\\n\"\n" "\"bind Console {console:Right %W}\\n\"\n" "\"bind Console {console:Right %W}\\n\"\n" "\"bind Console {console:Backspace %W}\\n\"\n" "\"bind Console {console:Backspace %W}\\n\"\n" "\"bind Console {console:Delete %W}\\n\"\n" "\"bind Console {console:Delete %W}\\n\"\n" "\"bind Console {console:Home %W}\\n\"\n" "\"bind Console {console:Home %W}\\n\"\n" "\"bind Console {console:End %W}\\n\"\n" "\"bind Console {console:End %W}\\n\"\n" "\"bind Console {console:Enter %W}\\n\"\n" "\"bind Console {console:Enter %W}\\n\"\n" "\"bind Console {console:Prior %W}\\n\"\n" "\"bind Console {console:Prior %W}\\n\"\n" "\"bind Console {console:Next %W}\\n\"\n" "\"bind Console {console:Next %W}\\n\"\n" "\"bind Console {console:EraseEOL %W}\\n\"\n" "\"bind Console <> {console:Cut %W}\\n\"\n" "\"bind Console <> {console:Copy %W}\\n\"\n" "\"bind Console <> {console:Paste %W}\\n\"\n" "\"bind Console <> {console:Clear %W}\\n\"\n" "\"proc console:Puts {w t tag} {\\n\"\n" "\"set nc [string length $t]\\n\"\n" "\"set endc [string index $t [expr $nc-1]]\\n\"\n" "\"if {$endc==\\\"\\\\n\\\"} {\\n\"\n" "\"if {[$w index out]<[$w index {insert linestart}]} {\\n\"\n" "\"$w insert out [string range $t 0 [expr $nc-2]] $tag\\n\"\n" "\"$w mark set out {out linestart +1 lines}\\n\"\n" "\"} else {\\n\"\n" "\"$w insert out $t $tag\\n\"\n" "\"}\\n\"\n" "\"} else {\\n\"\n" "\"if {[$w index out]<[$w index {insert linestart}]} {\\n\"\n" "\"$w insert out $t $tag\\n\"\n" "\"} else {\\n\"\n" "\"$w insert out $t\\\\n $tag\\n\"\n" "\"$w mark set out {out -1 char}\\n\"\n" "\"}\\n\"\n" "\"}\\n\"\n" "\"$w yview insert\\n\"\n" "\"}\\n\"\n" "\"proc console:Insert {w a} {\\n\"\n" "\"$w insert insert $a\\n\"\n" "\"$w yview insert\\n\"\n" "\"}\\n\"\n" "\"proc console:Left {w} {\\n\"\n" "\"upvar #0 $w v\\n\"\n" "\"scan [$w index insert] %d.%d row col\\n\"\n" "\"if {$col>$v(plength)} {\\n\"\n" "\"$w mark set insert \\\"insert -1c\\\"\\n\"\n" "\"}\\n\"\n" "\"}\\n\"\n" "\"proc console:Backspace {w} {\\n\"\n" "\"upvar #0 $w v\\n\"\n" "\"scan [$w index insert] %d.%d row col\\n\"\n" "\"if {$col>$v(plength)} {\\n\"\n" "\"$w delete {insert -1c}\\n\"\n" "\"}\\n\"\n" "\"}\\n\"\n" "\"proc console:EraseEOL {w} {\\n\"\n" "\"upvar #0 $w v\\n\"\n" "\"scan [$w index insert] %d.%d row col\\n\"\n" "\"if {$col>=$v(plength)} {\\n\"\n" "\"$w delete insert {insert lineend}\\n\"\n" "\"}\\n\"\n" "\"}\\n\"\n" "\"proc console:Right {w} {\\n\"\n" "\"$w mark set insert \\\"insert +1c\\\"\\n\"\n" "\"}\\n\"\n" "\"proc console:Delete w {\\n\"\n" "\"$w delete insert\\n\"\n" "\"}\\n\"\n" "\"proc console:Home w {\\n\"\n" "\"upvar #0 $w v\\n\"\n" "\"scan [$w index insert] %d.%d row col\\n\"\n" "\"$w mark set insert $row.$v(plength)\\n\"\n" "\"}\\n\"\n" "\"proc console:End w {\\n\"\n" "\"$w mark set insert {insert lineend}\\n\"\n" "\"}\\n\"\n" "\"proc console:Enter w {\\n\"\n" "\"upvar #0 $w v\\n\"\n" "\"scan [$w index insert] %d.%d row col\\n\"\n" "\"set start $row.$v(plength)\\n\"\n" "\"set line [$w get $start \\\"$start lineend\\\"]\\n\"\n" "\"if {$v(historycnt)>0} {\\n\"\n" "\"set last [lindex $v(history) [expr $v(historycnt)-1]]\\n\"\n" "\"if {[string compare $last $line]} {\\n\"\n" "\"lappend v(history) $line\\n\"\n" "\"incr v(historycnt)\\n\"\n" "\"}\\n\"\n" "\"} else {\\n\"\n" "\"set v(history) [list $line]\\n\"\n" "\"set v(historycnt) 1\\n\"\n" "\"}\\n\"\n" "\"set v(current) $v(historycnt)\\n\"\n" "\"$w insert end \\\\n\\n\"\n" "\"$w mark set out end\\n\"\n" "\"if {$v(prior)==\\\"\\\"} {\\n\"\n" "\"set cmd $line\\n\"\n" "\"} else {\\n\"\n" "\"set cmd $v(prior)\\\\n$line\\n\"\n" "\"}\\n\"\n" "\"if {[info complete $cmd]} {\\n\"\n" "\"set rc [catch {uplevel #0 $cmd} res]\\n\"\n" "\"if {![winfo exists $w]} return\\n\"\n" "\"if {$rc} {\\n\"\n" "\"$w insert end $res\\\\n err\\n\"\n" "\"} elseif {[string length $res]>0} {\\n\"\n" "\"$w insert end $res\\\\n ok\\n\"\n" "\"}\\n\"\n" "\"set v(prior) {}\\n\"\n" "\"$w insert end $v(prompt)\\n\"\n" "\"} else {\\n\"\n" "\"set v(prior) $cmd\\n\"\n" "\"regsub -all {[^ ]} $v(prompt) . x\\n\"\n" "\"$w insert end $x\\n\"\n" "\"}\\n\"\n" "\"$w mark set insert end\\n\"\n" "\"$w mark set out {insert linestart}\\n\"\n" "\"$w yview insert\\n\"\n" "\"}\\n\"\n" "\"proc console:Prior w {\\n\"\n" "\"upvar #0 $w v\\n\"\n" "\"if {$v(current)<=0} return\\n\"\n" "\"incr v(current) -1\\n\"\n" "\"set line [lindex $v(history) $v(current)]\\n\"\n" "\"console:SetLine $w $line\\n\"\n" "\"}\\n\"\n" "\"proc console:Next w {\\n\"\n" "\"upvar #0 $w v\\n\"\n" "\"if {$v(current)>=$v(historycnt)} return\\n\"\n" "\"incr v(current) 1\\n\"\n" "\"set line [lindex $v(history) $v(current)]\\n\"\n" "\"console:SetLine $w $line\\n\"\n" "\"}\\n\"\n" "\"proc console:SetLine {w line} {\\n\"\n" "\"upvar #0 $w v\\n\"\n" "\"scan [$w index insert] %d.%d row col\\n\"\n" "\"set start $row.$v(plength)\\n\"\n" "\"$w delete $start end\\n\"\n" "\"$w insert end $line\\n\"\n" "\"$w mark set insert end\\n\"\n" "\"$w yview insert\\n\"\n" "\"}\\n\"\n" "\"proc console:Button1 {w x y} {\\n\"\n" "\"global tkPriv\\n\"\n" "\"upvar #0 $w v\\n\"\n" "\"set v(mouseMoved) 0\\n\"\n" "\"set v(pressX) $x\\n\"\n" "\"set p [console:nearestBoundry $w $x $y]\\n\"\n" "\"scan [$w index insert] %d.%d ix iy\\n\"\n" "\"scan $p %d.%d px py\\n\"\n" "\"if {$px==$ix} {\\n\"\n" "\"$w mark set insert $p\\n\"\n" "\"}\\n\"\n" "\"$w mark set anchor $p\\n\"\n" "\"focus $w\\n\"\n" "\"}\\n\"\n" "\"proc console:nearestBoundry {w x y} {\\n\"\n" "\"set p [$w index @$x,$y]\\n\"\n" "\"set bb [$w bbox $p]\\n\"\n" "\"if {![string compare $bb \\\"\\\"]} {return $p}\\n\"\n" "\"if {($x-[lindex $bb 0])<([lindex $bb 2]/2)} {return $p}\\n\"\n" "\"$w index \\\"$p + 1 char\\\"\\n\"\n" "\"}\\n\"\n" "\"proc console:SelectTo {w x y} {\\n\"\n" "\"upvar #0 $w v\\n\"\n" "\"set cur [console:nearestBoundry $w $x $y]\\n\"\n" "\"if {[catch {$w index anchor}]} {\\n\"\n" "\"$w mark set anchor $cur\\n\"\n" "\"}\\n\"\n" "\"set anchor [$w index anchor]\\n\"\n" "\"if {[$w compare $cur != $anchor] || (abs($v(pressX) - $x) >= 3)} {\\n\"\n" "\"if {$v(mouseMoved)==0} {\\n\"\n" "\"$w tag remove sel 0.0 end\\n\"\n" "\"}\\n\"\n" "\"set v(mouseMoved) 1\\n\"\n" "\"}\\n\"\n" "\"if {[$w compare $cur < anchor]} {\\n\"\n" "\"set first $cur\\n\"\n" "\"set last anchor\\n\"\n" "\"} else {\\n\"\n" "\"set first anchor\\n\"\n" "\"set last $cur\\n\"\n" "\"}\\n\"\n" "\"if {$v(mouseMoved)} {\\n\"\n" "\"$w tag remove sel 0.0 $first\\n\"\n" "\"$w tag add sel $first $last\\n\"\n" "\"$w tag remove sel $last end\\n\"\n" "\"update idletasks\\n\"\n" "\"}\\n\"\n" "\"}\\n\"\n" "\"proc console:B1Motion {w x y} {\\n\"\n" "\"upvar #0 $w v\\n\"\n" "\"set v(y) $y\\n\"\n" "\"set v(x) $x\\n\"\n" "\"console:SelectTo $w $x $y\\n\"\n" "\"}\\n\"\n" "\"proc console:B1Leave {w x y} {\\n\"\n" "\"upvar #0 $w v\\n\"\n" "\"set v(y) $y\\n\"\n" "\"set v(x) $x\\n\"\n" "\"console:motor $w\\n\"\n" "\"}\\n\"\n" "\"proc console:motor w {\\n\"\n" "\"upvar #0 $w v\\n\"\n" "\"if {![winfo exists $w]} return\\n\"\n" "\"if {$v(y)>=[winfo height $w]} {\\n\"\n" "\"$w yview scroll 1 units\\n\"\n" "\"} elseif {$v(y)<0} {\\n\"\n" "\"$w yview scroll -1 units\\n\"\n" "\"} else {\\n\"\n" "\"return\\n\"\n" "\"}\\n\"\n" "\"console:SelectTo $w $v(x) $v(y)\\n\"\n" "\"set v(timer) [after 50 console:motor $w]\\n\"\n" "\"}\\n\"\n" "\"proc console:cancelMotor w {\\n\"\n" "\"upvar #0 $w v\\n\"\n" "\"catch {after cancel $v(timer)}\\n\"\n" "\"catch {unset v(timer)}\\n\"\n" "\"}\\n\"\n" "\"proc console:Copy w {\\n\"\n" "\"if {![catch {set text [$w get sel.first sel.last]}]} {\\n\"\n" "\"clipboard clear -displayof $w\\n\"\n" "\"clipboard append -displayof $w $text\\n\"\n" "\"}\\n\"\n" "\"}\\n\"\n" "\"proc console:canCut w {\\n\"\n" "\"set r [catch {\\n\"\n" "\"scan [$w index sel.first] %d.%d s1x s1y\\n\"\n" "\"scan [$w index sel.last] %d.%d s2x s2y\\n\"\n" "\"scan [$w index insert] %d.%d ix iy\\n\"\n" "\"}]\\n\"\n" "\"if {$r==1} {return 0}\\n\"\n" "\"if {$s1x==$ix && $s2x==$ix} {return 1}\\n\"\n" "\"return 2\\n\"\n" "\"}\\n\"\n" "\"proc console:Cut w {\\n\"\n" "\"if {[console:canCut $w]==1} {\\n\"\n" "\"console:Copy $w\\n\"\n" "\"$w delete sel.first sel.last\\n\"\n" "\"}\\n\"\n" "\"}\\n\"\n" "\"proc console:Paste w {\\n\"\n" "\"if {[console:canCut $w]==1} {\\n\"\n" "\"$w delete sel.first sel.last\\n\"\n" "\"}\\n\"\n" "\"if {[catch {selection get -displayof $w -selection CLIPBOARD} topaste]} {\\n\"\n" "\"return\\n\"\n" "\"}\\n\"\n" "\"set prior 0\\n\"\n" "\"foreach line [split $topaste \\\\n] {\\n\"\n" "\"if {$prior} {\\n\"\n" "\"console:Enter $w\\n\"\n" "\"update\\n\"\n" "\"}\\n\"\n" "\"set prior 1\\n\"\n" "\"$w insert insert $line\\n\"\n" "\"}\\n\"\n" "\"}\\n\"\n" "\"proc console:EnableEditMenu w {\\n\"\n" "\"set m $w.mb.edit.m\\n\"\n" "\"switch [console:canCut $w.t] {\\n\"\n" "\"0 {\\n\"\n" "\"$m entryconf Copy -state disabled\\n\"\n" "\"$m entryconf Cut -state disabled\\n\"\n" "\"}\\n\"\n" "\"1 {\\n\"\n" "\"$m entryconf Copy -state normal\\n\"\n" "\"$m entryconf Cut -state normal\\n\"\n" "\"}\\n\"\n" "\"2 {\\n\"\n" "\"$m entryconf Copy -state normal\\n\"\n" "\"$m entryconf Cut -state disabled\\n\"\n" "\"}\\n\"\n" "\"}\\n\"\n" "\"}\\n\"\n" "\"proc console:SourceFile w {\\n\"\n" "\"set types {\\n\"\n" "\"{{TCL Scripts} {.tcl}}\\n\"\n" "\"{{All Files} *}\\n\"\n" "\"}\\n\"\n" "\"set f [tk_getOpenFile -filetypes $types -title \\\"TCL Script To Source...\\\"]\\n\"\n" "\"if {$f!=\\\"\\\"} {\\n\"\n" "\"uplevel #0 source $f\\n\"\n" "\"}\\n\"\n" "\"}\\n\"\n" "\"proc console:SaveFile w {\\n\"\n" "\"set types {\\n\"\n" "\"{{Text Files} {.txt}}\\n\"\n" "\"{{All Files} *}\\n\"\n" "\"}\\n\"\n" "\"set f [tk_getSaveFile -filetypes $types -title \\\"Write Screen To...\\\"]\\n\"\n" "\"if {$f!=\\\"\\\"} {\\n\"\n" "\"if {[catch {open $f w} fd]} {\\n\"\n" "\"tk_messageBox -type ok -icon error -message $fd\\n\"\n" "\"} else {\\n\"\n" "\"puts $fd [string trimright [$w get 1.0 end] \\\\n]\\n\"\n" "\"close $fd\\n\"\n" "\"}\\n\"\n" "\"}\\n\"\n" "\"}\\n\"\n" "\"proc console:Clear w {\\n\"\n" "\"$w delete 1.0 {insert linestart}\\n\"\n" "\"}\\n\"\n" "\"console:create {.@console} {% } {Tcl/Tk Console}\\n\"\n" ";\n" "#endif\n" "\n" "/*\n" "** The \"printf\" code that follows dates from the 1980's. It is in\n" "** the public domain. The original comments are included here for\n" "** completeness...\n" "**\n" "** The following modules is an enhanced replacement for the \"printf\" programs\n" "** found in the standard library. The following enhancements are\n" "** supported:\n" "**\n" "** + Additional functions. The standard set of \"printf\" functions\n" "** includes printf, fprintf, sprintf, vprintf, vfprintf, and\n" "** vsprintf. This module adds the following:\n" "**\n" "** * snprintf -- Works like sprintf, but has an extra argument\n" "** which is the size of the buffer written to.\n" "**\n" "** * mprintf -- Similar to sprintf. Writes output to memory\n" "** obtained from malloc.\n" "**\n" "** * xprintf -- Calls a function to dispose of output.\n" "**\n" "** * nprintf -- No output, but returns the number of characters\n" "** that would have been output by printf.\n" "**\n" "** * A v- version (ex: vsnprintf) of every function is also\n" "** supplied.\n" "**\n" "** + A few extensions to the formatting notation are supported:\n" "**\n" "** * The \"=\" flag (similar to \"-\") causes the output to be\n" "** be centered in the appropriately sized field.\n" "**\n" "** * The %b field outputs an integer in binary notation.\n" "**\n" "** * The %c field now accepts a precision. The character output\n" "** is repeated by the number of times the precision specifies.\n" "**\n" "** * The %' field works like %c, but takes as its character the\n" "** next character of the format string, instead of the next\n" "** argument. For example, printf(\"%.78'-\") prints 78 minus\n" "** signs, the same as printf(\"%.78c\",'-').\n" "**\n" "** + When compiled using GCC on a SPARC, this version of printf is\n" "** faster than the library printf for SUN OS 4.1.\n" "**\n" "** + All functions are fully reentrant.\n" "**\n" "*/\n" "/*\n" "** Undefine COMPATIBILITY to make some slight changes in the way things\n" "** work. I think the changes are an improvement, but they are not\n" "** backwards compatible.\n" "*/\n" "/* #define COMPATIBILITY / * Compatible with SUN OS 4.1 */\n" "\n" "/*\n" "** Characters that need to be escaped inside a TCL string.\n" "*/\n" "static char NeedEsc[] = {\n" " 1, 1, 1, 1, 1, 1, 1, 1, 'b', 't', 'n', 1, 'f', 'r', 1, 1,\n" " 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n" " 0, 0, '\"', 0, '$', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n" " 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n" " 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n" " 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '[','\\\\', ']', 0, 0,\n" " 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n" " 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1,\n" " 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n" " 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n" " 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n" " 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n" " 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n" " 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n" " 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n" " 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n" "};\n" "\n" "/*\n" "** Conversion types fall into various categories as defined by the\n" "** following enumeration.\n" "*/\n" "enum et_type { /* The type of the format field */\n" " etRADIX, /* Integer types. %d, %x, %o, and so forth */\n" " etFLOAT, /* Floating point. %f */\n" " etEXP, /* Exponentional notation. %e and %E */\n" " etGENERIC, /* Floating or exponential, depending on exponent. %g */\n" " etSIZE, /* Return number of characters processed so far. %n */\n" " etSTRING, /* Strings. %s */\n" " etPERCENT, /* Percent symbol. %% */\n" " etCHARX, /* Characters. %c */\n" " etERROR, /* Used to indicate no such conversion type */\n" "/* The rest are extensions, not normally found in printf() */\n" " etCHARLIT, /* Literal characters. %' */\n" " etTCLESCAPE, /* Strings with special characters escaped. %q */\n" " etMEMSTRING, /* A string which should be deleted after use. %z */\n" " etORDINAL /* 1st, 2nd, 3rd and so forth */\n" "};\n" "\n" "/*\n" "** Each builtin conversion character (ex: the 'd' in \"%d\") is described\n" "** by an instance of the following structure\n" "*/\n" "typedef struct et_info { /* Information about each format field */\n" " int fmttype; /* The format field code letter */\n" " int base; /* The base for radix conversion */\n" " char *charset; /* The character set for conversion */\n" " int flag_signed; /* Is the quantity signed? */\n" " char *prefix; /* Prefix on non-zero values in alt format */\n" " enum et_type type; /* Conversion paradigm */\n" "} et_info;\n" "\n" "/*\n" "** The following table is searched linearly, so it is good to put the\n" "** most frequently used conversion types first.\n" "*/\n" "static et_info fmtinfo[] = {\n" " { 'd', 10, \"0123456789\", 1, 0, etRADIX, },\n" " { 's', 0, 0, 0, 0, etSTRING, }, \n" " { 'q', 0, 0, 0, 0, etTCLESCAPE, },\n" " { 'z', 0, 0, 0, 0, etMEMSTRING, },\n" " { 'c', 0, 0, 0, 0, etCHARX, },\n" " { 'o', 8, \"01234567\", 0, \"0\", etRADIX, },\n" " { 'u', 10, \"0123456789\", 0, 0, etRADIX, },\n" " { 'x', 16, \"0123456789abcdef\", 0, \"x0\", etRADIX, },\n" " { 'X', 16, \"0123456789ABCDEF\", 0, \"X0\", etRADIX, },\n" " { 'r', 10, \"0123456789\", 0, 0, etORDINAL, },\n" " { 'f', 0, 0, 1, 0, etFLOAT, },\n" " { 'e', 0, \"e\", 1, 0, etEXP, },\n" " { 'E', 0, \"E\", 1, 0, etEXP, },\n" " { 'g', 0, \"e\", 1, 0, etGENERIC, },\n" " { 'G', 0, \"E\", 1, 0, etGENERIC, },\n" " { 'i', 10, \"0123456789\", 1, 0, etRADIX, },\n" " { 'n', 0, 0, 0, 0, etSIZE, },\n" " { '%', 0, 0, 0, 0, etPERCENT, },\n" " { 'b', 2, \"01\", 0, \"b0\", etRADIX, }, /* Binary */\n" " { 'p', 10, \"0123456789\", 0, 0, etRADIX, }, /* Pointers */\n" " { '\\'', 0, 0, 0, 0, etCHARLIT, }, /* Literal char */\n" "};\n" "#define etNINFO (sizeof(fmtinfo)/sizeof(fmtinfo[0]))\n" "\n" "/*\n" "** If NOFLOATINGPOINT is defined, then none of the floating point\n" "** conversions will work.\n" "*/\n" "#ifndef etNOFLOATINGPOINT\n" "/*\n" "** \"*val\" is a double such that 0.1 <= *val < 10.0\n" "** Return the ascii code for the leading digit of *val, then\n" "** multiply \"*val\" by 10.0 to renormalize.\n" "**\n" "** Example:\n" "** input: *val = 3.14159\n" "** output: *val = 1.4159 function return = '3'\n" "**\n" "** The counter *cnt is incremented each time. After counter exceeds\n" "** 16 (the number of significant digits in a 64-bit float) '0' is\n" "** always returned.\n" "*/\n" "static int et_getdigit(double *val, int *cnt){\n" " int digit;\n" " double d;\n" " if( (*cnt)++ >= 16 ) return '0';\n" " digit = (int)*val;\n" " d = digit;\n" " digit += '0';\n" " *val = (*val - d)*10.0;\n" " return digit;\n" "}\n" "#endif\n" "\n" "#define etBUFSIZE 1000 /* Size of the output buffer */\n" "\n" "/*\n" "** The root program. All variations call this core.\n" "**\n" "** INPUTS:\n" "** func This is a pointer to a function taking three arguments\n" "** 1. A pointer to anything. Same as the \"arg\" parameter.\n" "** 2. A pointer to the list of characters to be output\n" "** (Note, this list is NOT null terminated.)\n" "** 3. An integer number of characters to be output.\n" "** (Note: This number might be zero.)\n" "**\n" "** arg This is the pointer to anything which will be passed as the\n" "** first argument to \"func\". Use it for whatever you like.\n" "**\n" "** fmt This is the format string, as in the usual print.\n" "**\n" "** ap This is a pointer to a list of arguments. Same as in\n" "** vfprint.\n" "**\n" "** OUTPUTS:\n" "** The return value is the total number of characters sent to\n" "** the function \"func\". Returns -1 on a error.\n" "**\n" "** Note that the order in which automatic variables are declared below\n" "** seems to make a big difference in determining how fast this beast\n" "** will run.\n" "*/\n" "int vxprintf(\n" " void (*func)(void*,char*,int),\n" " void *arg,\n" " const char *format,\n" " va_list ap\n" "){\n" " register const char *fmt; /* The format string. */\n" " register int c; /* Next character in the format string */\n" " register char *bufpt; /* Pointer to the conversion buffer */\n" " register int precision; /* Precision of the current field */\n" " register int length; /* Length of the field */\n" " register int idx; /* A general purpose loop counter */\n" " int count; /* Total number of characters output */\n" " int width; /* Width of the current field */\n" " int flag_leftjustify; /* True if \"-\" flag is present */\n" " int flag_plussign; /* True if \"+\" flag is present */\n" " int flag_blanksign; /* True if \" \" flag is present */\n" " int flag_alternateform; /* True if \"#\" flag is present */\n" " int flag_zeropad; /* True if field width constant starts with zero */\n" " int flag_long; /* True if \"l\" flag is present */\n" " int flag_center; /* True if \"=\" flag is present */\n" " unsigned long longvalue; /* Value for integer types */\n" " double realvalue; /* Value for real types */\n" " et_info *infop; /* Pointer to the appropriate info structure */\n" " char buf[etBUFSIZE]; /* Conversion buffer */\n" " char prefix; /* Prefix character. \"+\" or \"-\" or \" \" or '\\0'. */\n" " int errorflag = 0; /* True if an error is encountered */\n" " enum et_type xtype; /* Conversion paradigm */\n" " char *zMem; /* String to be freed */\n" " char *zExtra; /* Extra memory used for etTCLESCAPE conversions */\n" " static char spaces[] = \" \"\n" " \" \";\n" "#define etSPACESIZE (sizeof(spaces)-1)\n" "#ifndef etNOFLOATINGPOINT\n" " int exp; /* exponent of real numbers */\n" " double rounder; /* Used for rounding floating point values */\n" " int flag_dp; /* True if decimal point should be shown */\n" " int flag_rtz; /* True if trailing zeros should be removed */\n" " int flag_exp; /* True to force display of the exponent */\n" " int nsd; /* Number of significant digits returned */\n" "#endif\n" "\n" " fmt = format; /* Put in a register for speed */\n" " count = length = 0;\n" " bufpt = 0;\n" " for(; (c=(*fmt))!=0; ++fmt){\n" " if( c!='%' ){\n" " register int amt;\n" " bufpt = (char *)fmt;\n" " amt = 1;\n" " while( (c=(*++fmt))!='%' && c!=0 ) amt++;\n" " (*func)(arg,bufpt,amt);\n" " count += amt;\n" " if( c==0 ) break;\n" " }\n" " if( (c=(*++fmt))==0 ){\n" " errorflag = 1;\n" " (*func)(arg,\"%\",1);\n" " count++;\n" " break;\n" " }\n" " /* Find out what flags are present */\n" " flag_leftjustify = flag_plussign = flag_blanksign = \n" " flag_alternateform = flag_zeropad = flag_center = 0;\n" " do{\n" " switch( c ){\n" " case '-': flag_leftjustify = 1; c = 0; break;\n" " case '+': flag_plussign = 1; c = 0; break;\n" " case ' ': flag_blanksign = 1; c = 0; break;\n" " case '#': flag_alternateform = 1; c = 0; break;\n" " case '0': flag_zeropad = 1; c = 0; break;\n" " case '=': flag_center = 1; c = 0; break;\n" " default: break;\n" " }\n" " }while( c==0 && (c=(*++fmt))!=0 );\n" " if( flag_center ) flag_leftjustify = 0;\n" " /* Get the field width */\n" " width = 0;\n" " if( c=='*' ){\n" " width = va_arg(ap,int);\n" " if( width<0 ){\n" " flag_leftjustify = 1;\n" " width = -width;\n" " }\n" " c = *++fmt;\n" " }else{\n" " while( isdigit(c) ){\n" " width = width*10 + c - '0';\n" " c = *++fmt;\n" " }\n" " }\n" " if( width > etBUFSIZE-10 ){\n" " width = etBUFSIZE-10;\n" " }\n" " /* Get the precision */\n" " if( c=='.' ){\n" " precision = 0;\n" " c = *++fmt;\n" " if( c=='*' ){\n" " precision = va_arg(ap,int);\n" "#ifndef etCOMPATIBILITY\n" " /* This is sensible, but SUN OS 4.1 doesn't do it. */\n" " if( precision<0 ) precision = -precision;\n" "#endif\n" " c = *++fmt;\n" " }else{\n" " while( isdigit(c) ){\n" " precision = precision*10 + c - '0';\n" " c = *++fmt;\n" " }\n" " }\n" " /* Limit the precision to prevent overflowing buf[] during conversion */\n" " if( precision>etBUFSIZE-40 ) precision = etBUFSIZE-40;\n" " }else{\n" " precision = -1;\n" " }\n" " /* Get the conversion type modifier */\n" " if( c=='l' ){\n" " flag_long = 1;\n" " c = *++fmt;\n" " }else{\n" " flag_long = 0;\n" " }\n" " /* Fetch the info entry for the field */\n" " infop = 0;\n" " for(idx=0; idxtype;\n" " }\n" " zExtra = 0;\n" "\n" " /*\n" " ** At this point, variables are initialized as follows:\n" " **\n" " ** flag_alternateform TRUE if a '#' is present.\n" " ** flag_plussign TRUE if a '+' is present.\n" " ** flag_leftjustify TRUE if a '-' is present or if the\n" " ** field width was negative.\n" " ** flag_zeropad TRUE if the width began with 0.\n" " ** flag_long TRUE if the letter 'l' (ell) prefixed\n" " ** the conversion character.\n" " ** flag_blanksign TRUE if a ' ' is present.\n" " ** width The specified field width. This is\n" " ** always non-negative. Zero is the default.\n" " ** precision The specified precision. The default\n" " ** is -1.\n" " ** xtype The class of the conversion.\n" " ** infop Pointer to the appropriate info struct.\n" " */\n" " switch( xtype ){\n" " case etORDINAL:\n" " case etRADIX:\n" " if( flag_long ) longvalue = va_arg(ap,long);\n" " else longvalue = va_arg(ap,int);\n" "#ifdef etCOMPATIBILITY\n" " /* For the format %#x, the value zero is printed \"0\" not \"0x0\".\n" " ** I think this is stupid. */\n" " if( longvalue==0 ) flag_alternateform = 0;\n" "#else\n" " /* More sensible: turn off the prefix for octal (to prevent \"00\"),\n" " ** but leave the prefix for hex. */\n" " if( longvalue==0 && infop->base==8 ) flag_alternateform = 0;\n" "#endif\n" " if( infop->flag_signed ){\n" " if( *(long*)&longvalue<0 ){\n" " longvalue = -*(long*)&longvalue;\n" " prefix = '-';\n" " }else if( flag_plussign ) prefix = '+';\n" " else if( flag_blanksign ) prefix = ' ';\n" " else prefix = 0;\n" " }else prefix = 0;\n" " if( flag_zeropad && precision3 || (b>10 && b<14) ){\n" " bufpt[0] = 't';\n" " bufpt[1] = 'h';\n" " }else if( a==1 ){\n" " bufpt[0] = 's';\n" " bufpt[1] = 't';\n" " }else if( a==2 ){\n" " bufpt[0] = 'n';\n" " bufpt[1] = 'd';\n" " }else if( a==3 ){\n" " bufpt[0] = 'r';\n" " bufpt[1] = 'd';\n" " }\n" " }\n" " {\n" " register char *cset; /* Use registers for speed */\n" " register int base;\n" " cset = infop->charset;\n" " base = infop->base;\n" " do{ /* Convert to ascii */\n" " *(--bufpt) = cset[longvalue%base];\n" " longvalue = longvalue/base;\n" " }while( longvalue>0 );\n" " }\n" " length = (long)&buf[etBUFSIZE]-(long)bufpt;\n" " for(idx=precision-length; idx>0; idx--){\n" " *(--bufpt) = '0'; /* Zero pad */\n" " }\n" " if( prefix ) *(--bufpt) = prefix; /* Add sign */\n" " if( flag_alternateform && infop->prefix ){ /* Add \"0\" or \"0x\" */\n" " char *pre, x;\n" " pre = infop->prefix;\n" " if( *bufpt!=pre[0] ){\n" " for(pre=infop->prefix; (x=(*pre))!=0; pre++) *(--bufpt) = x;\n" " }\n" " }\n" " length = (long)&buf[etBUFSIZE]-(long)bufpt;\n" " break;\n" " case etFLOAT:\n" " case etEXP:\n" " case etGENERIC:\n" " realvalue = va_arg(ap,double);\n" "#ifndef etNOFLOATINGPOINT\n" " if( precision<0 ) precision = 6; /* Set default precision */\n" " if( precision>etBUFSIZE-10 ) precision = etBUFSIZE-10;\n" " if( realvalue<0.0 ){\n" " realvalue = -realvalue;\n" " prefix = '-';\n" " }else{\n" " if( flag_plussign ) prefix = '+';\n" " else if( flag_blanksign ) prefix = ' ';\n" " else prefix = 0;\n" " }\n" " if( infop->type==etGENERIC && precision>0 ) precision--;\n" " rounder = 0.0;\n" "#ifdef COMPATIBILITY\n" " /* Rounding works like BSD when the constant 0.4999 is used. Wierd! */\n" " for(idx=precision, rounder=0.4999; idx>0; idx--, rounder*=0.1);\n" "#else\n" " /* It makes more sense to use 0.5 */\n" " for(idx=precision, rounder=0.5; idx>0; idx--, rounder*=0.1);\n" "#endif\n" " if( infop->type==etFLOAT ) realvalue += rounder;\n" " /* Normalize realvalue to within 10.0 > realvalue >= 1.0 */\n" " exp = 0;\n" " if( realvalue>0.0 ){\n" " int k = 0;\n" " while( realvalue>=1e8 && k++<100 ){ realvalue *= 1e-8; exp+=8; }\n" " while( realvalue>=10.0 && k++<100 ){ realvalue *= 0.1; exp++; }\n" " while( realvalue<1e-8 && k++<100 ){ realvalue *= 1e8; exp-=8; }\n" " while( realvalue<1.0 && k++<100 ){ realvalue *= 10.0; exp--; }\n" " if( k>=100 ){\n" " bufpt = \"NaN\";\n" " length = 3;\n" " break;\n" " }\n" " }\n" " bufpt = buf;\n" " /*\n" " ** If the field type is etGENERIC, then convert to either etEXP\n" " ** or etFLOAT, as appropriate.\n" " */\n" " flag_exp = xtype==etEXP;\n" " if( xtype!=etFLOAT ){\n" " realvalue += rounder;\n" " if( realvalue>=10.0 ){ realvalue *= 0.1; exp++; }\n" " }\n" " if( xtype==etGENERIC ){\n" " flag_rtz = !flag_alternateform;\n" " if( exp<-4 || exp>precision ){\n" " xtype = etEXP;\n" " }else{\n" " precision = precision - exp;\n" " xtype = etFLOAT;\n" " }\n" " }else{\n" " flag_rtz = 0;\n" " }\n" " /*\n" " ** The \"exp+precision\" test causes output to be of type etEXP if\n" " ** the precision is too large to fit in buf[].\n" " */\n" " nsd = 0;\n" " if( xtype==etFLOAT && exp+precision0 || flag_alternateform);\n" " if( prefix ) *(bufpt++) = prefix; /* Sign */\n" " if( exp<0 ) *(bufpt++) = '0'; /* Digits before \".\" */\n" " else for(; exp>=0; exp--) *(bufpt++) = et_getdigit(&realvalue,&nsd);\n" " if( flag_dp ) *(bufpt++) = '.'; /* The decimal point */\n" " for(exp++; exp<0 && precision>0; precision--, exp++){\n" " *(bufpt++) = '0';\n" " }\n" " while( (precision--)>0 ) *(bufpt++) = et_getdigit(&realvalue,&nsd);\n" " *(bufpt--) = 0; /* Null terminate */\n" " if( flag_rtz && flag_dp ){ /* Remove trailing zeros and \".\" */\n" " while( bufpt>=buf && *bufpt=='0' ) *(bufpt--) = 0;\n" " if( bufpt>=buf && *bufpt=='.' ) *(bufpt--) = 0;\n" " }\n" " bufpt++; /* point to next free slot */\n" " }else{ /* etEXP or etGENERIC */\n" " flag_dp = (precision>0 || flag_alternateform);\n" " if( prefix ) *(bufpt++) = prefix; /* Sign */\n" " *(bufpt++) = et_getdigit(&realvalue,&nsd); /* First digit */\n" " if( flag_dp ) *(bufpt++) = '.'; /* Decimal point */\n" " while( (precision--)>0 ) *(bufpt++) = et_getdigit(&realvalue,&nsd);\n" " bufpt--; /* point to last digit */\n" " if( flag_rtz && flag_dp ){ /* Remove tail zeros */\n" " while( bufpt>=buf && *bufpt=='0' ) *(bufpt--) = 0;\n" " if( bufpt>=buf && *bufpt=='.' ) *(bufpt--) = 0;\n" " }\n" " bufpt++; /* point to next free slot */\n" " if( exp || flag_exp ){\n" " *(bufpt++) = infop->charset[0];\n" " if( exp<0 ){ *(bufpt++) = '-'; exp = -exp; } /* sign of exp */\n" " else { *(bufpt++) = '+'; }\n" " if( exp>=100 ){\n" " *(bufpt++) = (exp/100)+'0'; /* 100's digit */\n" " exp %= 100;\n" " }\n" " *(bufpt++) = exp/10+'0'; /* 10's digit */\n" " *(bufpt++) = exp%10+'0'; /* 1's digit */\n" " }\n" " }\n" " /* The converted number is in buf[] and zero terminated. Output it.\n" " ** Note that the number is in the usual order, not reversed as with\n" " ** integer conversions. */\n" " length = (long)bufpt-(long)buf;\n" " bufpt = buf;\n" "\n" " /* Special case: Add leading zeros if the flag_zeropad flag is\n" " ** set and we are not left justified */\n" " if( flag_zeropad && !flag_leftjustify && length < width){\n" " int i;\n" " int nPad = width - length;\n" " for(i=width; i>=nPad; i--){\n" " bufpt[i] = bufpt[i-nPad];\n" " }\n" " i = prefix!=0;\n" " while( nPad-- ) bufpt[i++] = '0';\n" " length = width;\n" " }\n" "#endif\n" " break;\n" " case etSIZE:\n" " *(va_arg(ap,int*)) = count;\n" " length = width = 0;\n" " break;\n" " case etPERCENT:\n" " buf[0] = '%';\n" " bufpt = buf;\n" " length = 1;\n" " break;\n" " case etCHARLIT:\n" " case etCHARX:\n" " c = buf[0] = (xtype==etCHARX ? va_arg(ap,int) : *++fmt);\n" " if( precision>=0 ){\n" " for(idx=1; idx=0 && precisionetBUFSIZE ){\n" " bufpt = zExtra = Tcl_Alloc( n );\n" " }else{\n" " bufpt = buf;\n" " }\n" " for(i=j=0; (c=arg[i])!=0; i++){\n" " k = NeedEsc[c&0xff];\n" " if( k==0 ){\n" " bufpt[j++] = c;\n" " }else if( k==1 ){\n" " bufpt[j++] = '\\\\';\n" " bufpt[j++] = ((c>>6) & 3) + '0';\n" " bufpt[j++] = ((c>>3) & 7) + '0';\n" " bufpt[j++] = (c & 7) + '0';\n" " }else{\n" " bufpt[j++] = '\\\\';\n" " bufpt[j++] = k;\n" " }\n" " }\n" " bufpt[j] = 0;\n" " length = j;\n" " if( precision>=0 && precision0 ){\n" " if( flag_center ){\n" " nspace = nspace/2;\n" " width -= nspace;\n" " flag_leftjustify = 1;\n" " }\n" " count += nspace;\n" " while( nspace>=etSPACESIZE ){\n" " (*func)(arg,spaces,etSPACESIZE);\n" " nspace -= etSPACESIZE;\n" " }\n" " if( nspace>0 ) (*func)(arg,spaces,nspace);\n" " }\n" " }\n" " if( length>0 ){\n" " (*func)(arg,bufpt,length);\n" " count += length;\n" " }\n" " if( xtype==etMEMSTRING && zMem ){\n" " Tcl_Free(zMem);\n" " }\n" " if( flag_leftjustify ){\n" " register int nspace;\n" " nspace = width-length;\n" " if( nspace>0 ){\n" " count += nspace;\n" " while( nspace>=etSPACESIZE ){\n" " (*func)(arg,spaces,etSPACESIZE);\n" " nspace -= etSPACESIZE;\n" " }\n" " if( nspace>0 ) (*func)(arg,spaces,nspace);\n" " }\n" " }\n" " if( zExtra ){\n" " Tcl_Free(zExtra);\n" " }\n" " }/* End for loop over the format string */\n" " return errorflag ? -1 : count;\n" "} /* End of function */\n" "\n" "/*\n" "** The following section of code handles the mprintf routine, that\n" "** writes to memory obtained from malloc().\n" "*/\n" "\n" "/* This structure is used to store state information about the\n" "** write to memory that is currently in progress.\n" "*/\n" "struct sgMprintf {\n" " char *zBase; /* A base allocation */\n" " char *zText; /* The string collected so far */\n" " int nChar; /* Length of the string so far */\n" " int nAlloc; /* Amount of space allocated in zText */\n" "};\n" "\n" "/* \n" "** The xprintf callback function. \n" "**\n" "** This routine add nNewChar characters of text in zNewText to\n" "** the sgMprintf structure pointed to by \"arg\".\n" "*/\n" "static void mout(void *arg, char *zNewText, int nNewChar){\n" " struct sgMprintf *pM = (struct sgMprintf*)arg;\n" " if( pM->nChar + nNewChar + 1 > pM->nAlloc ){\n" " pM->nAlloc = pM->nChar + nNewChar*2 + 1;\n" " if( pM->zText==pM->zBase ){\n" " pM->zText = Tcl_Alloc(pM->nAlloc);\n" " if( pM->zText && pM->nChar ) memcpy(pM->zText,pM->zBase,pM->nChar);\n" " }else{\n" " pM->zText = Tcl_Realloc(pM->zText, pM->nAlloc);\n" " }\n" " }\n" " if( pM->zText ){\n" " memcpy(&pM->zText[pM->nChar], zNewText, nNewChar);\n" " pM->nChar += nNewChar;\n" " pM->zText[pM->nChar] = 0;\n" " }\n" "}\n" "\n" "/*\n" "** mprintf() works like printf(), but allocations memory to hold the\n" "** resulting string and returns a pointer to the allocated memory.\n" "*/\n" "char *mprintf(const char *zFormat, ...){\n" " va_list ap;\n" " struct sgMprintf sMprintf;\n" " char *zNew;\n" " char zBuf[200];\n" "\n" " sMprintf.nChar = 0;\n" " sMprintf.nAlloc = sizeof(zBuf);\n" " sMprintf.zText = zBuf;\n" " sMprintf.zBase = zBuf;\n" " va_start(ap,zFormat);\n" " vxprintf(mout,&sMprintf,zFormat,ap);\n" " va_end(ap);\n" " sMprintf.zText[sMprintf.nChar] = 0;\n" " if( sMprintf.zText==sMprintf.zBase ){\n" " zNew = Tcl_Alloc( sMprintf.nChar+1 );\n" " if( zNew ) strcpy(zNew,zBuf);\n" " }else{\n" " zNew = Tcl_Realloc(sMprintf.zText,sMprintf.nChar+1);\n" " }\n" " return zNew;\n" "}\n" "\n" "/* This is the varargs version of mprintf. \n" "*/\n" "char *vmprintf(const char *zFormat, va_list ap){\n" " struct sgMprintf sMprintf;\n" " char zBuf[200];\n" " sMprintf.nChar = 0;\n" " sMprintf.zText = zBuf;\n" " sMprintf.nAlloc = sizeof(zBuf);\n" " sMprintf.zBase = zBuf;\n" " vxprintf(mout,&sMprintf,zFormat,ap);\n" " sMprintf.zText[sMprintf.nChar] = 0;\n" " if( sMprintf.zText==sMprintf.zBase ){\n" " sMprintf.zText = Tcl_Alloc( strlen(zBuf)+1 );\n" " if( sMprintf.zText ) strcpy(sMprintf.zText,zBuf);\n" " }else{\n" " sMprintf.zText = Tcl_Realloc(sMprintf.zText,sMprintf.nChar+1);\n" " }\n" " return sMprintf.zText;\n" "}\n" "\n" "/*\n" "** Add text output to a Tcl_DString.\n" "**\n" "** This routine is called by vxprintf(). It's job is to add\n" "** nNewChar characters of text from zNewText to the Tcl_DString\n" "** that \"arg\" is pointing to.\n" "*/\n" "static void dstringout(void *arg, char *zNewText, int nNewChar){\n" " Tcl_DString *str = (Tcl_DString*)arg;\n" " Tcl_DStringAppend(str,zNewText,nNewChar);\n" "}\n" "\n" "/*\n" "** Append formatted output to a DString.\n" "*/\n" "char *Et_DStringAppendF(Tcl_DString *str, const char *zFormat, ...){\n" " va_list ap;\n" " va_start(ap,zFormat);\n" " vxprintf(dstringout,str,zFormat,ap);\n" " va_end(ap);\n" " return Tcl_DStringValue(str);\n" "}\n" "\n" "/*\n" "** Make this variable true to trace all calls to EvalF\n" "*/\n" "int Et_EvalTrace = 0;\n" "\n" "/*\n" "** Eval the results of a string.\n" "*/\n" "int Et_EvalF(Tcl_Interp *interp, const char *zFormat, ...){\n" " char *zCmd;\n" " va_list ap;\n" " int result;\n" " va_start(ap,zFormat);\n" " zCmd = vmprintf(zFormat,ap);\n" " if( Et_EvalTrace ) printf(\"%s\\n\",zCmd);\n" " result = Tcl_Eval(interp,zCmd);\n" " if( Et_EvalTrace ) printf(\"%d %s\\n\",result,interp->result);\n" " Tcl_Free(zCmd);\n" " return result;\n" "}\n" "int Et_GlobalEvalF(Tcl_Interp *interp, const char *zFormat, ...){\n" " char *zCmd;\n" " va_list ap;\n" " int result;\n" " va_start(ap,zFormat);\n" " zCmd = vmprintf(zFormat,ap);\n" " if( Et_EvalTrace ) printf(\"%s\\n\",zCmd);\n" " result = Tcl_GlobalEval(interp,zCmd);\n" " if( Et_EvalTrace ) printf(\"%d %s\\n\",result,interp->result);\n" " Tcl_Free(zCmd);\n" " return result;\n" "}\n" "\n" "/*\n" "** Set the result of an interpreter using printf-like arguments.\n" "*/\n" "void Et_ResultF(Tcl_Interp *interp, const char *zFormat, ...){\n" " Tcl_DString str;\n" " va_list ap;\n" "\n" " Tcl_DStringInit(&str);\n" " va_start(ap,zFormat);\n" " vxprintf(dstringout,&str,zFormat,ap);\n" " va_end(ap);\n" " Tcl_DStringResult(interp,&str); \n" "}\n" "\n" "#if ET_HAVE_OBJ\n" "/*\n" "** Append text to a string object.\n" "*/\n" "int Et_AppendObjF(Tcl_Obj *pObj, const char *zFormat, ...){\n" " va_list ap;\n" " int rc;\n" "\n" " va_start(ap,zFormat);\n" " rc = vxprintf((void(*)(void*,char*,int))Tcl_AppendToObj, pObj, zFormat, ap);\n" " va_end(ap);\n" " return rc;\n" "}\n" "#endif\n" "\n" "\n" "#if ET_WIN32\n" "/*\n" "** This array translates all characters into themselves. Except\n" "** for the \\ which gets translated into /. And all upper-case\n" "** characters are translated into lower case. This is used for\n" "** hashing and comparing filenames, to work around the Windows\n" "** but of ignoring filename case and using the wrong separator\n" "** character for directories.\n" "**\n" "** The array is initialized by FilenameHashInit().\n" "**\n" "** We also define a macro ET_TRANS() that actually does\n" "** the character translation. ET_TRANS() is a no-op under\n" "** unix.\n" "*/\n" "static char charTrans[256];\n" "#define ET_TRANS(X) (charTrans[0xff&(int)(X)])\n" "#else\n" "#define ET_TRANS(X) (X)\n" "#endif\n" "\n" "/*\n" "** Hash a filename. The value returned is appropriate for\n" "** indexing into the Et_FileHashTable[] array.\n" "*/\n" "static int FilenameHash(char *zName){\n" " int h = 0;\n" " while( *zName ){\n" " h = h ^ (h<<5) ^ ET_TRANS(*(zName++));\n" " }\n" " if( h<0 ) h = -h;\n" " return h % (sizeof(Et_FileHashTable)/sizeof(Et_FileHashTable[0]));\n" "}\n" "\n" "/*\n" "** Compare two filenames. Return 0 if they are the same and\n" "** non-zero if they are different.\n" "*/\n" "static int FilenameCmp(char *z1, char *z2){\n" " int diff;\n" " while( (diff = ET_TRANS(*z1)-ET_TRANS(*z2))==0 && *z1!=0){\n" " z1++;\n" " z2++;\n" " }\n" " return diff;\n" "}\n" "\n" "/*\n" "** Initialize the file hash table\n" "*/\n" "static void FilenameHashInit(void){\n" " int i;\n" "#if ET_WIN32\n" " for(i=0; izName);\n" " p->pNext = Et_FileHashTable[h];\n" " Et_FileHashTable[h] = p;\n" " }\n" "}\n" "\n" "/*\n" "** Locate the text of a built-in file given its name. \n" "** Return 0 if not found. Return this size of the file (not\n" "** counting the null-terminator in *pSize if pSize!=NULL.\n" "**\n" "** If deshroud==1 and the file is shrouded, then descramble\n" "** the text.\n" "*/\n" "static char *FindBuiltinFile(char *zName, int deshroud, int *pSize){\n" " int h;\n" " struct EtFile *p;\n" "\n" " h = FilenameHash(zName);\n" " p = Et_FileHashTable[h];\n" " while( p && FilenameCmp(p->zName,zName)!=0 ){ p = p->pNext; }\n" "#if ET_SHROUD_KEY>0\n" " if( p && p->shrouded && deshroud ){\n" " char *z;\n" " int xor = ET_SHROUD_KEY;\n" " for(z=p->zData; *z; z++){\n" " if( *z>=0x20 ){ *z ^= xor; xor = (xor+1)&0x1f; }\n" " }\n" " p->shrouded = 0;\n" " }\n" "#endif\n" " if( p && pSize ){\n" " *pSize = p->nData;\n" " }\n" " return p ? p->zData : 0;\n" "}\n" "\n" "/*\n" "** Add a new file to the list of built-in files.\n" "**\n" "** This routine makes a copy of zFilename. But it does NOT make\n" "** a copy of zData. It just holds a pointer to zData and uses\n" "** that for all file access. So after calling this routine,\n" "** you should never change zData!\n" "*/\n" "void Et_NewBuiltinFile(\n" " char *zFilename, /* Name of the new file */\n" " char *zData, /* Data for the new file */\n" " int nData /* Number of bytes in the new file */\n" "){\n" " int h;\n" " struct EtFile *p;\n" "\n" " p = (struct EtFile*)Tcl_Alloc( sizeof(struct EtFile) + strlen(zFilename) + 1);\n" " if( p==0 ) return;\n" " p->zName = (char*)&p[1];\n" " strcpy(p->zName, zFilename);\n" " p->zData = zData;\n" " p->nData = nData;\n" " p->shrouded = 0;\n" " h = FilenameHash(zFilename);\n" " p->pNext = Et_FileHashTable[h];\n" " Et_FileHashTable[h] = p;\n" "}\n" "\n" "/*\n" "** A TCL interface to the Et_NewBuiltinFile function. For Tcl8.0\n" "** and later, we make this an Obj command so that it can deal with\n" "** binary data.\n" "*/\n" "#if ET_HAVE_OBJ\n" "static int Et_NewBuiltinFileCmd(ET_OBJARGS){\n" " char *zData, *zNew;\n" " int nData;\n" " if( objc!=3 ){\n" " Tcl_WrongNumArgs(interp, 1, objv, \"filename data\");\n" " return TCL_ERROR;\n" " }\n" " zData = Tcl_GetByteArrayFromObj(objv[2], &nData);\n" " zNew = Tcl_Alloc( nData );\n" " if( zNew ){\n" " memcpy(zNew, zData, nData);\n" " Et_NewBuiltinFile(Tcl_GetByteArrayFromObj(objv[1], 0), zNew, nData);\n" " }\n" " return TCL_OK;\n" "}\n" "#else\n" "static int Et_NewBuiltinFileCmd(ET_TCLARGS){\n" " char *zData;\n" " int nData;\n" " if( argc!=3 ){\n" " Et_ResultF(interp,\"wrong # args: should be \\\"%s FILENAME DATA\\\"\", argv[0]);\n" " return TCL_ERROR;\n" " }\n" " nData = strlen(argv[2]) + 1;\n" " zData = Tcl_Alloc( nData );\n" " if( zData ){\n" " strcpy(zData, argv[2]);\n" " Et_NewBuiltinFile(argv[1], zData, nData);\n" " }\n" " return TCL_OK;\n" "}\n" "#endif\n" "\n" "/*\n" "** The following section implements the InsertProc functionality. The\n" "** new InsertProc feature of Tcl8.0.3 and later allows us to overload\n" "** the usual system call commands for file I/O and replace them with\n" "** commands that operate on the built-in files.\n" "*/\n" "#ifdef ET_HAVE_INSERTPROC\n" "\n" "/* \n" "** Each open channel to a built-in file is an instance of the\n" "** following structure.\n" "*/\n" "typedef struct Et_FileStruct {\n" " char *zData; /* All of the data */\n" " int nData; /* Bytes of data, not counting the null terminator */\n" " int cursor; /* How much of the data has been read so far */\n" "} Et_FileStruct;\n" "\n" "/*\n" "** Close a previously opened built-in file.\n" "*/\n" "static int Et_FileClose(ClientData instanceData, Tcl_Interp *interp){\n" " Et_FileStruct *p = (Et_FileStruct*)instanceData;\n" " Tcl_Free((char*)p);\n" " return 0;\n" "}\n" "\n" "/*\n" "** Read from a built-in file.\n" "*/\n" "static int Et_FileInput(\n" " ClientData instanceData, /* The file structure */\n" " char *buf, /* Write the data read here */\n" " int bufSize, /* Read this much data */\n" " int *pErrorCode /* Write the error code here */\n" "){\n" " Et_FileStruct *p = (Et_FileStruct*)instanceData;\n" " *pErrorCode = 0;\n" " if( p->cursor+bufSize>p->nData ){\n" " bufSize = p->nData - p->cursor;\n" " }\n" " memcpy(buf, &p->zData[p->cursor], bufSize);\n" " p->cursor += bufSize;\n" " return bufSize;\n" "}\n" "\n" "/*\n" "** Writes to a built-in file always return EOF.\n" "*/\n" "static int Et_FileOutput(\n" " ClientData instanceData, /* The file structure */\n" " char *buf, /* Read the data from here */\n" " int toWrite, /* Write this much data */\n" " int *pErrorCode /* Write the error code here */\n" "){\n" " *pErrorCode = 0;\n" " return 0;\n" "}\n" "\n" "/*\n" "** Move the cursor around within the built-in file.\n" "*/\n" "static int Et_FileSeek(\n" " ClientData instanceData, /* The file structure */\n" " long offset, /* Offset to seek to */\n" " int mode, /* One of SEEK_CUR, SEEK_SET or SEEK_END */\n" " int *pErrorCode /* Write the error code here */\n" "){\n" " Et_FileStruct *p = (Et_FileStruct*)instanceData;\n" " switch( mode ){\n" " case SEEK_CUR: offset += p->cursor; break;\n" " case SEEK_END: offset += p->nData; break;\n" " default: break;\n" " }\n" " if( offset<0 ) offset = 0;\n" " if( offset>p->nData ) offset = p->nData;\n" " p->cursor = offset;\n" " return offset;\n" "}\n" "\n" "/*\n" "** The Watch method is a no-op\n" "*/\n" "static void Et_FileWatch(ClientData instanceData, int mask){\n" "}\n" "\n" "/*\n" "** The Handle method always returns an error.\n" "*/\n" "static int Et_FileHandle(ClientData notUsed, int dir, ClientData *handlePtr){\n" " return TCL_ERROR;\n" "}\n" "\n" "/*\n" "** This is the channel type that will access the built-in files.\n" "*/\n" "static Tcl_ChannelType builtinChannelType = {\n" " \"builtin\", /* Type name. */\n" " NULL, /* Always non-blocking.*/\n" " Et_FileClose, /* Close proc. */\n" " Et_FileInput, /* Input proc. */\n" " Et_FileOutput, /* Output proc. */\n" " Et_FileSeek, /* Seek proc. */\n" " NULL, /* Set option proc. */\n" " NULL, /* Get option proc. */\n" " Et_FileWatch, /* Watch for events on console. */\n" " Et_FileHandle, /* Get a handle from the device. */\n" "};\n" "\n" "/*\n" "** This routine attempts to do an open of a built-in file.\n" "*/\n" "static Tcl_Channel Et_FileOpen(\n" " Tcl_Interp *interp, /* The TCL interpreter doing the open */\n" " char *zFilename, /* Name of the file to open */\n" " char *modeString, /* Mode string for the open (ignored) */\n" " int permissions /* Permissions for a newly created file (ignored) */\n" "){\n" " char *zData;\n" " Et_FileStruct *p;\n" " int nData;\n" " char zName[50];\n" " Tcl_Channel chan;\n" "\n" " zData = FindBuiltinFile(zFilename, 1, &nData);\n" " if( zData==0 ) return NULL;\n" " p = (Et_FileStruct*)Tcl_Alloc( sizeof(Et_FileStruct) );\n" " if( p==0 ) return NULL;\n" " p->zData = zData;\n" " p->nData = nData;\n" " p->cursor = 0;\n" " sprintf(zName,\"builtin%08x\",(unsigned int)zData);\n" " chan = Tcl_CreateChannel(&builtinChannelType, zName, \n" " (ClientData)p, TCL_READABLE);\n" " return chan;\n" "}\n" "\n" "/*\n" "** This routine does a stat() system call for a built-in file.\n" "*/\n" "static int Et_FileStat(char *path, struct stat *buf){\n" " char *zData;\n" " int nData;\n" "\n" " zData = FindBuiltinFile(path, 0, &nData);\n" " if( zData==0 ){\n" " return -1;\n" " }\n" " memset(buf, 0, sizeof(*buf));\n" " buf->st_mode = 0400;\n" " buf->st_size = nData;\n" " return 0;\n" "}\n" "\n" "/*\n" "** This routien does an access() system call for a built-in file.\n" "*/\n" "static int Et_FileAccess(char *path, int mode){\n" " char *zData;\n" "\n" " if( mode & 3 ){\n" " return -1;\n" " }\n" " zData = FindBuiltinFile(path, 0, 0);\n" " if( zData==0 ){\n" " return -1;\n" " }\n" " return 0; \n" "}\n" "#endif /* ET_HAVE_INSERTPROC */\n" "\n" "/*\n" "** An overloaded version of \"source\". First check for the file\n" "** is one of the built-ins. If it isn't a built-in, then check the\n" "** disk. But if ET_STANDALONE is set (which corresponds to the\n" "** \"Strict\" option in the user interface) then never check the disk.\n" "** This gives us a quick way to check for the common error of\n" "** sourcing a file that exists on the development by mistake, \n" "** and only discovering the mistake when you move the program\n" "** to your customer's machine.\n" "*/\n" "static int Et_Source(ET_TCLARGS){\n" " char *z;\n" "\n" " if( argc!=2 ){\n" " Et_ResultF(interp,\"wrong # args: should be \\\"%s FILENAME\\\"\", argv[0]);\n" " return TCL_ERROR;\n" " }\n" " z = FindBuiltinFile(argv[1], 1, 0);\n" " if( z ){\n" " int rc;\n" " rc = Tcl_Eval(interp,z);\n" " if (rc == TCL_ERROR) {\n" " char msg[200];\n" " sprintf(msg, \"\\n (file \\\"%.150s\\\" line %d)\", argv[1],\n" " interp->errorLine);\n" " Tcl_AddErrorInfo(interp, msg);\n" " } else {\n" " rc = TCL_OK;\n" " }\n" " return rc;\n" " }\n" "#if ET_STANDALONE\n" " Et_ResultF(interp,\"no such file: \\\"%s\\\"\", argv[1]);\n" " return TCL_ERROR;\n" "#else\n" " return Tcl_EvalFile(interp,argv[1]);\n" "#endif\n" "}\n" "\n" "#ifndef ET_HAVE_INSERTPROC\n" "/*\n" "** An overloaded version of \"file exists\". First check for the file\n" "** in the file table, then go to disk.\n" "**\n" "** We only overload \"file exists\" if we don't have InsertProc() \n" "** procedures. If we do have InsertProc() procedures, they will\n" "** handle this more efficiently.\n" "*/\n" "static int Et_FileExists(ET_TCLARGS){\n" " int i, rc;\n" " Tcl_DString str;\n" " if( argc==3 && strncmp(argv[1],\"exis\",4)==0 ){\n" " if( FindBuiltinFile(argv[2], 0, 0)!=0 ){\n" " interp->result = \"1\";\n" " return TCL_OK;\n" " }\n" " }\n" " Tcl_DStringInit(&str);\n" " Tcl_DStringAppendElement(&str,\"Et_FileCmd\");\n" " for(i=1; i1 ){\n" " zTitle = argv[1];\n" " }\n" " if( argc>2 ){\n" " zMsg = argv[2];\n" " }\n" " MessageBox(0, zMsg, zTitle, MB_ICONSTOP | MB_OK);\n" " return TCL_OK;\n" "}\n" "#endif\n" "\n" "/*\n" "** A default implementation for \"bgerror\"\n" "*/\n" "static char zBgerror[] = \n" " \"proc Et_Bgerror err {\\n\"\n" " \" global errorInfo tk_library\\n\"\n" " \" if {[info exists errorInfo]} {\\n\"\n" " \" set ei $errorInfo\\n\"\n" " \" } else {\\n\"\n" " \" set ei {}\\n\"\n" " \" }\\n\"\n" " \" if {[catch {bgerror $err}]==0} return\\n\"\n" " \" if {[string length $ei]>0} {\\n\"\n" " \" set err $ei\\n\"\n" " \" }\\n\"\n" " \" if {[catch {Et_MessageBox {Error} $err}]} {\\n\"\n" " \" puts stderr $err\\n\"\n" " \" }\\n\"\n" " \" exit\\n\"\n" " \"}\\n\"\n" ";\n" "\n" "/*\n" "** Do the initialization.\n" "**\n" "** This routine is called after the interpreter is created, but\n" "** before Et_PreInit() or Et_AppInit() have been run.\n" "*/\n" "static int Et_DoInit(Tcl_Interp *interp){\n" " int i;\n" " extern int Et_PreInit(Tcl_Interp*);\n" " extern int Et_AppInit(Tcl_Interp*);\n" "\n" " /* Insert our alternative stat(), access() and open() procedures\n" " ** so that any attempt to work with a file will check our built-in\n" " ** scripts first.\n" " */\n" "#ifdef ET_HAVE_INSERTPROC\n" " extern int TclStatInsertProc(int (*)(char*, struct stat *));\n" " extern int TclAccessInsertProc(int (*)(char*, int));\n" " extern int TclOpenFileChannelInsertProc(Tcl_Channel (*)(Tcl_Interp*,char*,\n" " char*,int));\n" " TclStatInsertProc(Et_FileStat);\n" " TclAccessInsertProc(Et_FileAccess);\n" " TclOpenFileChannelInsertProc(Et_FileOpen);\n" "#endif\n" "\n" " /* Initialize the hash-table for built-in scripts\n" " */\n" " FilenameHashInit();\n" "\n" " /* The Et_NewBuiltFile command is inserted for use by FreeWrap\n" " ** and similar tools.\n" " */\n" "#if ET_HAVE_OBJ\n" " Tcl_CreateObjCommand(interp,\"Et_NewBuiltinFile\",Et_NewBuiltinFileCmd,0,0);\n" "#else\n" " Tcl_CreateCommand(interp,\"Et_NewBuiltinFile\",Et_NewBuiltinFileCmd,0,0);\n" "#endif\n" "\n" " /* Overload the \"file\" and \"source\" commands\n" " */\n" "#ifndef ET_HAVE_INSERTPROC\n" " {\n" " static char zRename[] = \"rename file Et_FileCmd\";\n" " Tcl_Eval(interp,zRename);\n" " Tcl_CreateCommand(interp,\"file\",Et_FileExists,0,0);\n" " }\n" "#endif\n" " Tcl_CreateCommand(interp,\"source\",Et_Source,0,0);\n" "\n" " Et_Interp = interp;\n" "#ifdef ET_TCL_LIBRARY\n" " Tcl_SetVar(interp,\"tcl_library\",ET_TCL_LIBRARY,TCL_GLOBAL_ONLY);\n" " Tcl_SetVar(interp,\"tcl_libPath\",ET_TCL_LIBRARY,TCL_GLOBAL_ONLY);\n" " Tcl_SetVar2(interp,\"env\",\"TCL_LIBRARY\",ET_TCL_LIBRARY,TCL_GLOBAL_ONLY);\n" "#endif\n" "#ifdef ET_TK_LIBRARY\n" " Tcl_SetVar(interp,\"tk_library\",ET_TK_LIBRARY,TCL_GLOBAL_ONLY);\n" " Tcl_SetVar2(interp,\"env\",\"TK_LIBRARY\",ET_TK_LIBRARY,TCL_GLOBAL_ONLY);\n" "#endif\n" "#if ET_WIN32\n" " Tcl_CreateCommand(interp,\"Et_MessageBox\",Et_MessageBox, 0, 0);\n" "#endif \n" " Tcl_Eval(interp,zBgerror);\n" "#if ET_HAVE_PREINIT\n" " if( Et_PreInit(interp) == TCL_ERROR ){\n" " goto initerr;\n" " }\n" "#endif\n" " if( Tcl_Init(interp) == TCL_ERROR ){\n" " goto initerr;\n" " }\n" " Et_GlobalEvalF(interp,\"set dir $tcl_library;source $dir/tclIndex;unset dir\");\n" "#if ET_ENABLE_TK\n" " if( Tk_Init(interp) == TCL_ERROR ){\n" " goto initerr;\n" " }\n" " Tcl_StaticPackage(interp,\"Tk\", Tk_Init, 0);\n" " Et_GlobalEvalF(interp,\"set dir $tk_library;source $dir/tclIndex;unset dir\");\n" "#endif\n" " /* Tcl_SetVar(interp, \"tcl_rcFileName\", \"~/.wishrc\", TCL_GLOBAL_ONLY); */\n" " for(i=0; iresult);\n" " return TCL_ERROR;\n" "}\n" "\n" "\n" "#if ET_READ_STDIN==0 || ET_AUTO_FORK!=0\n" "/*\n" "** Initialize everything.\n" "*/\n" "static int Et_Local_Init(int argc, char **argv){\n" " Tcl_Interp *interp;\n" " char *args;\n" " char buf[100];\n" " static char zWaitForever[] = \"while 1 {vwait forever}\";\n" "\n" " Tcl_FindExecutable(argv[0]);\n" " interp = Tcl_CreateInterp();\n" " args = Tcl_Merge(argc-1, argv+1);\n" " Tcl_SetVar(interp, \"argv\", args, TCL_GLOBAL_ONLY);\n" " ckfree(args);\n" " sprintf(buf, \"%d\", argc-1);\n" " Tcl_SetVar(interp, \"argc\", buf, TCL_GLOBAL_ONLY);\n" " Tcl_SetVar(interp, \"argv0\", argv[0], TCL_GLOBAL_ONLY);\n" " Tcl_SetVar(interp, \"tcl_interactive\", \"0\", TCL_GLOBAL_ONLY);\n" " Et_DoInit(interp);\n" " Tcl_Eval(interp,zWaitForever);\n" " /* Tcl_DeleteInterp(interp); */\n" " /* Tcl_Exit(0); */\n" " return 0;\n" "}\n" "#endif\n" "\n" "/*\n" "** This routine is called to do the complete initialization.\n" "*/\n" "int Et_Init(int argc, char **argv){\n" "#ifdef ET_TCL_LIBRARY\n" " putenv(\"TCL_LIBRARY=\" ET_TCL_LIBRARY);\n" "#endif\n" "#ifdef ET_TK_LIBRARY\n" " putenv(\"TK_LIBRARY=\" ET_TK_LIBRARY);\n" "#endif\n" "#if ET_CONSOLE || !ET_READ_STDIN\n" " Et_Local_Init(argc, argv);\n" "#else\n" "# if ET_ENABLE_TK\n" " Tk_Main(argc,argv,Et_DoInit);\n" "# else\n" " Tcl_Main(argc, argv, Et_DoInit);\n" "# endif\n" "#endif\n" " return 0;\n" "}\n" "\n" "#if !ET_HAVE_MAIN\n" "/*\n" "** Main routine for UNIX programs. If the user has supplied\n" "** their own main() routine in a C module, then the ET_HAVE_MAIN\n" "** macro will be set to 1 and this code will be skipped.\n" "*/\n" "int main(int argc, char **argv){\n" "#if ET_AUTO_FORK\n" " int rc = fork();\n" " if( rc<0 ){\n" " perror(\"can't fork\");\n" " exit(1);\n" " }\n" " if( rc>0 ) return 0;\n" " close(0);\n" " open(\"/dev/null\",O_RDONLY);\n" " close(1);\n" " open(\"/dev/null\",O_WRONLY);\n" "#endif\n" " return Et_Init(argc,argv)!=TCL_OK;\n" "}\n" "#endif\n" ; tkHTML-4ee7aaa953d6cb59/tools/nroff_regen000075500000000000000000000007171151224263100175020ustar00nobodynobody#!/bin/sh # Assume call with pwd = 'doc'. # Phase I ... List known manpages ... rm -f ../tools/rules/manpages touch ../tools/rules/manpages for i in `ls *.man` do echo $i '-->' manpages ../tools/expand -rules ../tools/rules/manpage.list $i >> ../tools/rules/manpages done # Phase II .. Generate true output ... for i in `ls *.man` do echo $i '-->' `basename $i .man`.n ../tools/expand -rules ../tools/rules/manpage.nroff $i > `basename $i .man`.n done tkHTML-4ee7aaa953d6cb59/tools/rules000075500000000000000000000000001151224263100163305ustar00nobodynobodytkHTML-4ee7aaa953d6cb59/tools/rules/formatting000064400000000000000000000065061151224263100205130ustar00nobodynobody# -*- tcl -*- # Helper rules for the creation of the memchan website from the .exp files. # General formatting instructions ... proc state {} [list return [file join [pwd] state]] proc use_bg {} { set c [bgcolor] #puts stderr "using $c" if {$c == {}} {return ""} return bgcolor=$c } proc nbsp {} {return " "} proc p {} {return

      } proc ptop {} {return "

      "} proc td {} {return "

      "} proc trtop {} {return "
      "} proc btable {} {return "
      "} proc stable {} {return "
      "} proc tcl_cmd {cmd} {return "\[$cmd]"} proc wget {url} {exec /usr/bin/wget -q -O - $url 2>/dev/null} proc url {tag text url} { set body { switch -exact -- $what { link {return {%text%}} text {return {%text%}} url {return {%url%}} } } proc $tag {{what link}} [string map [list %text% $text %url% $url] $body] } proc img {tag alt img} { proc $tag {} [list return "\"$alt\""] } proc header {title} { proc pagetitle {} [list return $title] return "[sfproject] @ SourceForge : $title" } proc trailer {} { return "
      [table][tr]
      [copyright][me]
      Last update at [clock format [clock seconds]]
      " } proc protect {text} {return [string map [list & "&" < "<" > ">"] $text]} proc get_changelog {} { set cl [exec [file join [here] .. changelog_to_list] [file join [pwd] .. memchan ChangeLog]] proc get_changelog {} [list return $cl] return $cl } proc changelog {} { set cl [get_changelog] set html "
        " foreach chunk $cl { foreach {date person items} $chunk break ; # lassign append html "

      • [protect $date]

        [protect $person] ...


        [p][changelog_items $items][p]\n" } return $html
      } proc changelog_items {items} { set dlopen 0 set onlykey 0 set html "" foreach item $items { set key [set com {}] foreach {key com} $item break if {$key != {}} { if {!$dlopen} { if {$onlykey} { append html [p] set onlykey 0 } append html
      \n } set dlopen 1 append html
      [protect $key]
      if {$com != {}} { append html
      [protect $com]
      \n } } else { if {$com != {}} { if {$dlopen} {append html
      [p]\n} set dlopen 0 append html [protect $com] set onlykey 1 } } } if {$dlopen} {append html \n} return $html } proc news {} { set nfile [file join [state] news] set data [read [set fh [open $nfile r]]][close $fh] return [string trim $data]\n } proc stats {} { set nfile [file join [state] statistics] set data [read [set fh [open $nfile r]]][close $fh] set data [string trim $data] regsub -all {BGCOLOR="[^"]*"} $data "[use_bg]" data regsub -all {bgcolor="[^"]*"} $data "[use_bg]" data return [string trim $data]\n } tkHTML-4ee7aaa953d6cb59/tools/rules/manpage.api000064400000000000000000000026471151224263100205230ustar00nobodynobody# -*- tcl -*- # rules/manpage.api # # (c) 2001 Andreas Kupries # Defines the procedures a manpage rules file has to support for good # manpages. The procedures here return errors. proc __ {command} {return "return -code error \"Unimplemented command $command\""} ################################################################ proc manpage_begin {command section version module shortdesc description} [__ manpage] proc manpage_end {} [__ manpage_end] proc require {pkg {version {}}} [__ require] proc description {} [__ description] proc section {name} [__ section] proc para {} [__ para] proc list_begin {what} [__ list_begin] proc list_end {} [__ list_end] proc lst_item {{text {}}} [__ lst_item] proc call {cmd args} [__ call] proc bullet {} [__ bullet] proc enum {} [__ enum] proc see_also {args} [__ see_also] proc keywords {args} [__ keywords] proc nl {} [__ nl] proc arg {text} [__ arg] proc cmd {text} [__ cmd] proc opt {text} [__ opt] proc emph {text} [__ emph] proc strong {text} [__ strong] ################################################################ rename __ {} tkHTML-4ee7aaa953d6cb59/tools/rules/manpage.api.spec000064400000000000000000000070201151224263100214420ustar00nobodynobodySpecification of the API a manpage/tcl has to conform to so that rule files are able to process it properly. ====================================================================== The available commands are listed in the file 'manpage.api' too. The definitions in that file return errors. They should be loaded before the actual definitions so that usage of an unimplemented command causes a proper error message. ---------------------------------------------------------------------- The main commands are "manpage_begin", "manpage_end" and "description". All three are required. The first two are the first and last commands in a manpage. Neither text nor other commands may precede "manpage_begin" nor follow "manpage_end". The command "description" separates header and body of the manpage and may not be omitted. The only allowed text between "manpage_begin" and "description" is the command "require". Other commands or normal text are not permitted. "require" is used to list the packages the described command(s) depend(s) on for its operation. This list can be empty. After "description" text all other commands are allowed. The text can be separated into highlevel blocks using named "section"s. Each block can be further divided into paragraphs via "para". The commands "see_also" and "keywords" define whole sections named "SEE ALSO" and "KEYWORDS". They can occur everywhere in the manpage but making them the last section is the usual thing to do. They can be omitted. There are four commands available to mark words, "arg", "cmd", "emph" and "strong". The first two are used to mark words as command arguments and as command names. The other two are visual markup to emphasize words. Another set of four commands is available to construct (nested) lists. These are "list_begin", "list_end", "lst_item" and "call". The first two of these begin and end a list respectively. The argument to the first command is either 'bullet' or 'enum' denoting the type of the list (unordered vs. ordered). The third command starts list items. Each item has some text directly associated with the bullet but the major bulk of the item is the text following the item until the next list command. The last list command, "call" is special. It is used to describe the syntax of a command and its arguments. It should not only cause the appropriate markup of a list item at its place but also add the syntax to the table of contents (synopsis) if supported by the output format in question. nroff and HTML for example do. A logical format like TMML doesn't. I currently use the ?...? notation in my example to mark optional arguments. This should better be done through a command. This command is "opt". _Not_ "optarg" as it may span several arguments. ====================================================================== [list_begin "bullet"] -- Starts a bulleted (unordered) list. [bullet] -- Starts a new item in a bulleted list. [list_begin "enum"] -- Starts a numbered list. [enum] -- Starts a new item in a numbered (ordered) list. Successive list items are numbered [1], [2], ... etc. [list_begin "definitions"] -- Starts a definition list. [lst_item _text_] -- Starts a new entry in a definition list. _text_ is the list item header. [list_begin commands] -- Starts a command list, for describing the syntax of a command and its arguments. [call _cmd_ ? _arg_ _arg_ ... ? ] -- Starts an entry in a command list. In addition, adds the command syntax summary "_cmd_ _args_..." to the SYNOPSIS section. tkHTML-4ee7aaa953d6cb59/tools/rules/manpage.html000064400000000000000000000107651151224263100207160ustar00nobodynobody# -*- tcl -*- # rules/manpage-html # # (c) 2001 Andreas Kupries # # [expand] definitions to convert a tcl based manpage definition into # a manpage based upon HTML markup. Additional definition files allow # the conversion into nroff and XML. # # This conversion is for standalone manpages ... # ################################################################ proc here {} [list return [file dirname [info script]]] source [file join [here] manpage.api] ; # api, defines all required commands with errors. source [file join [here] formatting] ; # HTML basic formatting proc bgcolor {} {return ""} proc border {} {return 0} # Called before the first pass proc init_hook {} {setpasses 2} # Called before the first output. proc begin_hook {} { # Reset the syn flag global state set state(syn) 0 set state(req) 0 return } # Called after the last output. proc end_hook {} {} ################################################################ ## Backend for *roff markup proc manpage_begin {command section version module shortdesc description} { set hdr "" append hdr "$command - $shortdesc " append hdr "[ht_comment {}]\n" append hdr "[ht_comment {Copyright (c) 2000 Andreas Kupries}]\n" append hdr "[ht_comment {All right reserved}]\n" append hdr "[ht_comment {}]\n" append hdr "[ht_comment "CVS: \$Id\$ $command.$section"]\n" append hdr "[ht_comment {}]\n" append hdr "

      [string trimleft $command :]($section) $version $module \"$shortdesc\"

      \n" append hdr "[section NAME]\n" append hdr "[para] $command - $description" return $hdr } proc manpage_end {} {return } proc section {name} {return "

      $name

      "} proc para {} {return

      } global state array set state {req 0 syn 0 call {}} proc require {pkg {version {}}} { global state set state(req) 1 set result "[x_synopsis]package require $pkg" if {$version != {}} { append result " $version" } append result "
      " return $result } proc call {cmd args} { global state if {[exppass] == 1} { append state(call) "[trtop][td]$cmd [join $args " "]

      \n proc bgcolor {} {return ""} } append result [section DESCRIPTION] return $result } proc x_synopsis {} { global state if {!$state(syn)} { set state(syn) 1 return [section SYNOPSIS]\n } else { return "" } } ################################################################ global list_state array set list_state {level -1} proc list_begin {what} { global list_state switch -exact -- $what { enum {set result
        } bullet {set result
          } definitions {set result
          } default {return -code error "Unknown list type $what"} } incr list_state(level) set list_state(l,$list_state(level)) $what return $result } proc list_end {} { global list_state set what $list_state(l,$list_state(level)) catch {unset list_state(l,$list_state(level))} incr list_state(level) -1 switch -exact -- $what { enum {set result
      } bullet {set result } definitions {set result } } return $result } proc lst_item {text} {return
      $text
      } proc bullet {} {return
    • } proc enum {} {return
    • } ################################################################ proc see_also {args} {return "[section {SEE ALSO}]\n[join $args ", "]"} proc keywords {args} {return "[section KEYWORDS]\n[join $args ", "]"} proc nl {} {return
      } proc arg {text} {return $text} proc cmd {text} {return $text} proc emph {text} {return $text} proc strong {text} {return $text} proc opt {text} {return ?$text?} ################################################################ # HTML specific commands proc ht_comment {text} {return ""} ################################################################ proc setx {v string} { upvar $v _ set _ $string return } proc appendx {v string} { upvar $v _ append _ $string return } ################################################################ tkHTML-4ee7aaa953d6cb59/tools/rules/manpage.html.site000064400000000000000000000111741151224263100216540ustar00nobodynobody# -*- tcl -*- # rules/manpage-html # # (c) 2001 Andreas Kupries # # [expand] definitions to convert a tcl based manpage definition into # a manpage based upon HTML markup. Additional definition files allow # the conversion into nroff and XML. # # This conversion is for standalone manpages ... # ################################################################ proc here {} [list return [file dirname [info script]]] source [file join [here] manpage.api] ; # api, defines all required commands with errors. source [file join [here] memchan] ; # site pages policy and memchan configuration proc state {} [list return [file join [file dirname [state]] .. htdocs state]] # Called before the first pass proc init_hook {} {setpasses 2} # Called before the first output. proc begin_hook {} { # Reset the syn flag global state set state(syn) 0 set state(req) 0 return } # Called after the last output. proc end_hook {} {} ################################################################ ## Backend for *roff markup proc manpage_begin {command section version module shortdesc description} { set hdr "" append hdr "[ht_comment {}]\n" append hdr "[ht_comment {Copyright (c) 2000 Andreas Kupries}]\n" append hdr "[ht_comment {All right reserved}]\n" append hdr "[ht_comment {}]\n" append hdr "[ht_comment "CVS: \$Id\$ $command.$section"]\n" append hdr "[ht_comment {}]\n" append hdr [page_begin mem/mp/$command][nav_link [mem/sf/txt]]
      [site_xref]
      [mp_xref] append hdr [page_content] append hdr "

      $module $version -- [string trimleft $command :]($section)

      \n" append hdr "[section NAME]\n" append hdr "[para] $command - $description" return $hdr } proc manpage_end {} {return [page_end]} proc section {name} {return "

      $name

      "} proc para {} {return

      } global state array set state {req 0 syn 0 call {}} proc require {pkg {version {}}} { global state set state(req) 1 set result "[x_synopsis]package require $pkg" if {$version != {}} { append result " $version" } append result "
      \n" return $result } proc call {cmd args} { global state if {[exppass] == 1} { set oldcolor [bgcolor] proc bgcolor {} {return lightyellow} append state(call) "[trtop][td]$cmd [join $args " "]

    • \n } append result [section DESCRIPTION] return $result } proc x_synopsis {} { global state if {!$state(syn)} { global oldcolor set state(syn) 1 return [section SYNOPSIS]\n } else { return "" } } ################################################################ global list_state array set list_state {level -1} proc list_begin {what} { global list_state switch -exact -- $what { enum {set result
        } bullet {set result
          } definitions {set result
          } default {return -code error "Unknown list type $what"} } incr list_state(level) set list_state(l,$list_state(level)) $what return $result } proc list_end {} { global list_state set what $list_state(l,$list_state(level)) catch {unset list_state(l,$list_state(level))} incr list_state(level) -1 switch -exact -- $what { enum {set result
      } bullet {set result } definitions {set result } } return $result } proc lst_item {text} {return
      $text
      } proc bullet {} {return
    • } proc enum {} {return
    • } ################################################################ proc see_also {args} {return "[section {SEE ALSO}]\n[join $args ", "]"} proc keywords {args} {return "[section KEYWORDS]\n[join $args ", "]"} proc nl {} {return
      } proc arg {text} {return $text} proc cmd {text} {return $text} proc emph {text} {return $text} proc strong {text} {return $text} proc opt {text} {return ?$text?} ################################################################ # HTML specific commands proc ht_comment {text} {return ""} ################################################################ proc setx {v string} { upvar $v _ set _ $string return } proc appendx {v string} { upvar $v _ append _ $string return } ################################################################ tkHTML-4ee7aaa953d6cb59/tools/rules/manpage.list000064400000000000000000000025641151224263100207230ustar00nobodynobody# -*- tcl -*- # rules/manpage.api # # (c) 2001 Andreas Kupries # Defines the procedures a manpage rules file has to support for good # manpages. The procedures here return errors. ################################################################ proc manpage_begin {command section version module shortdesc description} { puts [list manpage mem/mp/$command $command mp.$command.html] setoutput nul return } ################################################################ proc manpage_end {} {} proc require {pkg {version {}}} {} proc description {} {} proc section {name} {} proc para {} {} proc call {cmd args} {} proc list_begin {what} {} proc list_end {} {} proc lst_item {text} {} proc see_also {args} {} proc keywords {args} {} proc nl {} {} proc bullet {} {} proc enum {} {} proc arg {text} {} proc cmd {text} {} proc emph {text} {} proc strong {text} {} proc setx {v string} {} proc appendx {v string} {} proc opt {text} {} ################################################################ tkHTML-4ee7aaa953d6cb59/tools/rules/manpage.nroff000064400000000000000000000124641151224263100210620ustar00nobodynobody# -*- tcl -*- # rules/manpage-nroff # # (c) 2001 Andreas Kupries # # [expand] definitions to convert a tcl based manpage definition into # a manpage based upon *roff markup. Additional definition files allow # the conversion into HTML and XML. # ################################################################ proc here {} [list return [file dirname [info script]]] source [file join [here] manpage.api] ; # api, defines all required commands with errors. # Called before the first pass proc init_hook {} {setpasses 2} # Called before the first output. proc begin_hook {} { # Reset the syn flag global state set state(syn) 0 return } # Called after the last output. proc end_hook {} {} ################################################################ ## Backend for *roff markup proc manpage_begin {command section version module shortdesc description} { cpush mp set hdr "" append hdr "[nr_comment {}]\n" append hdr "[nr_comment {Copyright (c) 2000 Andreas Kupries}]\n" append hdr "[nr_comment {All right reserved}]\n" append hdr "[nr_comment {}]\n" append hdr "[nr_comment "CVS: \$Id\$ $command.$section"]\n" append hdr "[nr_comment {}]\n" append hdr ".so man.macros\n" append hdr ".TH \"[string trimleft $command :]\" $section $version $module \"$shortdesc\"\n" append hdr ".BS\n" append hdr "[nr_comment {Note: do not modify the .SH NAME line immediately below!}]\n" append hdr ".SH NAME\n" append hdr "$command \\- $description" return $hdr } proc manpage_end {} { # Strip empty lines out of the generated nroff source. They mess # up the nroff formatting. regsub -all "\[\t \]*\n(\[\t \]*\n)*\[\t \]*" [cpop mp] "\n" data return $data } proc section {name} {return ".SH \"$name\""} proc para {} {nr_p} global state array set state {syn 0 call {}} proc require {pkg {version {}}} { if {$version != {}} { return "[x_synopsis]package require [nr_bld]$pkg $version[nr_rst]\n[nl]" } else { return "[x_synopsis]package require [nr_bld]$pkg[nr_rst]\n[nl]" } } proc call {cmd args} { global state if {[exppass] == 1} { append state(call) "$cmd [join $args " "][nr_rst]\n[nl]\n" } return "[lst_item "$cmd [join $args " "][nr_rst]"]" } proc description {} { global state if {$state(call) == {}} { return .BE\n[section DESCRIPTION] } else { return [x_synopsis]$state(call).BE\n[section DESCRIPTION] } } proc x_synopsis {} { global state if {!$state(syn)} { set state(syn) 1 return [section SYNOPSIS]\n } else { return "" } } ################################################################ global list_state array set list_state {level -1} proc list_begin {what} { global list_state switch -exact -- $what { enum - bullet - definitions {} default {return -code error "Unknown list type $what"} } incr list_state(level) set list_state(l,$list_state(level)) $what set list_state(l,$list_state(level),id) 0 if {$list_state(level) > 0} { return [nr_in] } else { return {} } } proc list_end {} { global list_state catch {unset list_state(l,$list_state(level))} catch {unset list_state(l,$list_state(level),id)} incr list_state(level) -1 if {$list_state(level) >= 0} { return [nr_out] } else { return {} } } proc bullet {} { global list_state switch -exact -- $list_state(l,$list_state(level)) { bullet {return ".TP\n*"} default {return -code error "Illegal use of bullet in non-bullet list"} } } proc enum {} { global list_state switch -exact -- $list_state(l,$list_state(level)) { enum {return ".IP \[[incr list_state(l,$list_state(level),id)]\]\n"} default {return -code error "Illegal use of bullet in non-bullet list"} } } proc lst_item {text} { global list_state switch -exact -- $list_state(l,$list_state(level)) { definitions {return ".TP\n$text"} default {return -code error "Illegal use of bullet in non-bullet list"} } } ################################################################ proc see_also {args} {return "[section {SEE ALSO}]\n[join $args ", "]"} proc keywords {args} {return "[section KEYWORDS]\n[join $args ", "]"} proc nl {} {nr_vspace} proc arg {text} {return [nr_ul]$text[nr_rst]} proc cmd {text} {return [nr_bld]$text[nr_rst]} proc emph {text} {return [nr_ul]$text[nr_rst]} proc strong {text} {return [nr_bld]$text[nr_rst]} proc opt {text} {return ?$text?} ################################################################ # nroff specific commands proc nr_bld {} {return \\fB} proc nr_ul {} {return \\fI} proc nr_rst {} {return \\fR} proc nr_p {} {return .PP} proc nr_comment {text} {return "'\\\" $text"} proc nr_enum {num} {return ".IP \[$num\]"} proc nr_vspace {} {return .sp} proc nr_blt {text} {return ".TP\n$text"} proc nr_bltn {n text} {return ".TP $n\n$text"} proc nr_in {} {return .RS} proc nr_out {} {return .RE} ################################################################ proc setx {v string} { upvar $v _ set _ $string return } proc appendx {v string} { upvar $v _ append _ $string return } ################################################################ tkHTML-4ee7aaa953d6cb59/tools/rules/manpage.tmml000064400000000000000000000104431151224263100207140ustar00nobodynobody# -*- tcl -*- # # $Id: manpage.tmml,v 1.1 2002/12/17 18:31:05 drh Exp $ # # [expand] definitions to convert a tcl based manpage definition # into TMML. # # Copyright (C) 2001 Joe English . # Freely redistributable. # # See also # # BUGS: # + XML markup characters in [expand] macro arguments # are not properly escaped. (Plain text outside of # [...] is handled correctly however.) # # + Text must be preceded by [para] or one of the # list item macros, or else the output will be invalid. # ###################################################################### proc here {} [list return [file dirname [info script]]] source [file join [here] manpage.api] source [file join [here] xmlrules.tcl] ###################################################################### # Utilities. # proc NOP {args} { } ;# do nothing proc NYI {{message {}}} { return -code error [append $message " Not Yet Implemented"] } set this [file tail [info script]] proc provenance {} { return "Generated from [expand::expfile] by EXPAND with $::this" } ###################################################################### # Expand hooks. # proc init_hook {} { setpasses 2 } proc raw_text_hook {text} { xmlEscape $text } proc begin_hook {} { setPassProcs [expand::exppass] } ###################################################################### # Conversion specification. # # Two-pass processing. The first pass collects text for the # SYNOPSIS, SEE ALSO, and KEYWORDS sections, and the second pass # produces output. # holdBuffers synopsis see_also keywords proc nl {} { emptyElement br } proc arg {text} { wrap $text m } proc cmd {text} { wrap $text cmd } proc emph {text} { wrap $text emph } proc strong {text} { wrap $text emph } proc opt {text} { wrap $text o } pass 1 manpage_begin {args} NOP pass 2 manpage_begin {command section version module shortdesc description} { sequence \ [xmlComment [provenance]] \ [start manpage \ id [file root [file tail [expand::expfile]]] \ cat cmd \ title $command \ version $version \ package $module] \ [start namesection] \ [wrap $command name] \ [wrap $description desc] \ [end namesection] \ ; } pass 1 description {} NOP pass 2 description {} { sequence \ [xmlContext manpage] \ [wrapLines? [held synopsis] syntax synopsis] \ [start section] \ [wrap "DESCRIPTION" title] \ ; } pass 1 section {name} NOP pass 2 section {name} { sequence \ [xmlContext manpage] \ [start section] \ [wrap [string toupper $name] title] \ ; } pass 1 para {} NOP pass 2 para {} { sequence [xmlContext section] [start p] } array set listTypes { bullet ul enum ol definitions dl } pass 1 list_begin {what} NOP pass 1 list_end {} NOP pass 2 list_begin {what} { sequence \ [xmlContext {section dd li}] \ [start $::listTypes($what)] \ ; } pass 2 list_end {} { sequence \ [xmlContext {ul ol dl}] \ [end] \ ; } pass 1 bullet {} NOP pass 1 enum {} NOP pass 2 bullet {} { sequence [xmlContext {ul ol}] [start li] } pass 2 enum {} { sequence [xmlContext {ul ol}] [start li] } pass 1 lst_item {text} NOP pass 2 lst_item {text} { sequence \ [xmlContext dl] \ [start dle] \ [wrap $text dt] \ [start dd] \ ; } pass 1 call {cmd args} { hold synopsis [formatCall $cmd $args] } pass 2 call {cmd args} { sequence \ [xmlContext dl] \ [start dle] \ [wrap [formatCall $cmd $args] dt] \ [start dd] \ ; } proc formatCall {cmd arglist} { return "$cmd [join $arglist { }]" ;# OR: wrap "..." command } pass 1 require {pkg {version {}}} { hold synopsis [formatRequire $pkg $version] } pass 2 require {pkg {version {}}} NOP proc formatRequire {pkg version} { return "package require [wrap $pkg package] [wrap? $version l]" } pass 1 see_also {args} { holdWrapped see_also $args ref } pass 1 keywords {args} { holdWrapped keywords $args keyword } pass 2 see_also {args} NOP pass 2 keywords {args} NOP # holdWrapped -- # Common factor of [see_also] and [keywords]. # proc holdWrapped {buffer arglist gi} { foreach arg $arglist { hold $buffer [wrap $arg $gi] } return } pass 1 manpage_end {} NOP pass 2 manpage_end {} { sequence \ [xmlContext manpage] \ [wrapLines? [held see_also] seealso] \ [wrapLines? [held keywords] keywords] \ [end manpage] \ ; } #*EOF* tkHTML-4ee7aaa953d6cb59/tools/rules/memchan000064400000000000000000000040721151224263100177450ustar00nobodynobody# -*- tcl -*- # configures the site policy with some variant information, like colors. # Rules for the creation of the memchan website from the .exp files. proc here {} [list return [file dirname [info script]]] source [file join [here] site] ; # load policy, defines template interface too. source [file join [here] references] ; # load references used by the site. source [file join [here] manpages] ; # load list of known manpages. proc sfproject {} {return Memchan} proc sfgroup {} {return 34191} proc bgcolor {} {return lightsteelblue} proc hlcolor {} {return lightyellow} proc author {} {return "\"Andreas Kupries,,,\""} proc border {} {return border=0} # Declare the pages of this site upfront ... sitepage mem/home "Homepage" index.html sitepage mem/releases "Releases" [releases/url] sitepage mem/images "Logos" images.html sitepage mem/anim "Animations" animations.html sitepage mem/doc "Documentation" documentation.html sitepage mem/clog "ChangeLog" changelog.html sitepage mem/copyright "© Disclaimer" disclaimer.html sitepage mem/event/gen "Event generation" mem_event.html # memchan specific commands proc mem/latest-release {} { set nfile [file join [state] latest.release] foreach {version date} [split [read [set fh [open $nfile r]]][close $fh] \n] break ; # lassign set releasepage [wget [releases/url]] regexp {release_id=([0-9]+)} $releasepage -> release_id return "[link "version $version" [releases/url]&release_id=$release_id] as of $date" } url mc/doc/nroff/gz "Archive" doc/memchan.nroff.tar.gz url mc/doc/nroff/bz "Archive" doc/memchan.nroff.tar.bz2 url mc/doc/nroff/zip "Archive" doc/memchan.nroff.tar.zip url mc/doc/html/gz "Archive" doc/memchan.html.tar.gz url mc/doc/html/bz "Archive" doc/memchan.html.tar.bz2 url mc/doc/html/zip "Archive" doc/memchan.html.tar.zip url mc/doc/tmml/gz "Archive" doc/memchan.tmml.tar.gz url mc/doc/tmml/bz "Archive" doc/memchan.tmml.tar.bz2 url mc/doc/tmml/zip "Archive" doc/memchan.tmml.tar.zip tkHTML-4ee7aaa953d6cb59/tools/rules/references000064400000000000000000000050611151224263100204550ustar00nobodynobody# -*- tcl -*- # Helper rules for the creation of the memchan website from the .exp files. proc releases/url {} {return http://sourceforge.net/project/showfiles.php?group_id=[sfgroup]} img sf/logo "SourceForge Logo" http://sourceforge.net/sflogo.php?group_id=34191 img tcl/logo "Tcl Logo" http://tcl.sourceforge.net/images/logo125.gif img mem/logo/520 "Memchan Logo" art/logo520.jpg img mem/logo/100 "Memchan Logo" art/logo100.gif img mem/logo/64 "Memchan Logo" art/logo64.gif img mem/logo/100a "Animated Memchan Logo" art/logo100a.gif img mem/logo/64a "Animated Memchan Logo" art/logo64a.gif url sf/img [sf/logo] http://sourceforge.net url tcl/sf/img [tcl/logo] http://sourceforge.net/projects/tcl url tcl/sf/txt Tcl http://sourceforge.net/projects/tcl url tcl/sf/txt/home "Tcl Homepage" http://sourceforge.net/projects/tcl url trf/txt Trf http://www.purl.org/net/akupries/soft/trf url trf/txt/home "Trf Homepage" http://www.purl.org/net/akupries/soft/trf url mem/sf/txt "Memchan SF Project" http://sourceforge.net/projects/memchan url mem/txt Memchan http://www.purl.org/net/akupries/soft/memchan url mem/txt/old "Old Memchan page" http://www.purl.org/net/akupries/soft/memchan url mem/txt/old/2 "old Memchan homepage" http://www.purl.org/net/akupries/soft/memchan url copyright "©" disclaimer.html if {0} { url mem/images "Logos" images.html url mem/home "Homepage" index.html url mem/anim "Animations" animations.html url mem/releases "Releases" [releases/url] url mem/doc "Documentation" documentation.html url mem/clog "ChangeLog" changelog.html } url tcl/foundry "Tcl Foundry" http://sourceforge.net/foundry/tcl-foundry/ url me "Andreas Kupries" http://www.purl.org/net/akupries/ ## Future ## Try to make this automatic ... url andreas_kupries/home "Andreas Kupries" http://www.purl.org/net/akupries/ url stevel/home "Steve Landers" http://www.digital-smarties.com/ url jo "John Ousterhout" http://www.scriptics.com/people/john.ousterhout url jcw "Jean-Claude Wippler" http://www.equi4.com/jcw/ url tclwiki "Tcl'ers Wiki" http://www.purl.org/tcl/wiki/ url lvirden "Larry W. Virden" http://www.purl.org/net/lvirden/ url jan "Jan Nijtmans" http://www.purl.org/net/nijtmans/ url tcl/io/fevent "Interaction of I/O system and notifier in the Tcl core" \ http://sourceforge.net/docman/display_doc.php?docid=6710&group_id=10894tkHTML-4ee7aaa953d6cb59/tools/rules/site000064400000000000000000000055531151224263100173060ustar00nobodynobody# -*- tcl -*- # site wide definitions _____________________________ # the general layout of the website. Change this to # adjust the layout. also imposes the interfaces between # site policy and templates source [file join [here] formatting] ; # Make general formatting available. # Rules for the creation of the website from the .exp files. # # General layout __________________________ # Header | [page_begin tag] # - Navigation - | # Interlude | [page_content] # - Content - | # Footer | [page_end] proc sitepage {tag text url} { global pages if {[info exists pages(t,$tag)]} { error "Page $tag already defined" } set pages(t,$tag) . lappend pages(tags) $tag url $tag $text $url return } proc manpage {tag text url} { global pages if {[info exists pages(t,$tag)]} { error "Page $tag already defined" } set pages(t,$tag) . lappend pages(mp) $tag url $tag $text $url return } proc page_begin {tag} { global pages if {![info exists pages(t,$tag)]} { error "Unknown page $tag" } set title [$tag text] set pages(_) $tag set data [header $title] append data "[table][trtop]" append data "[td]

      [sfproject]



    • Last updated @ $last_update
      " append data "[table][trtop][td][news]
      " append data "" append data "[trailer]" return $data } proc page_navigation_begin {} { set data "[trtop][td][table][trtop][table][trtop]" append data "[td]

      [sf/img]

      [mem/logo/100]

      [tcl/sf/img]" append data "[td][nbsp][td][sect Crossreferences]" return $data } proc page_navigation_end {} { return "[td][nbsp][td]" } proc nav_link {link} { return $link
      } proc site_xref {} { global pages set data "" foreach tag $pages(tags) { if {0 == [string compare $tag $pages(_)]} { append data [nav_link "[$tag text]"] } else { append data [nav_link [$tag]] } } return $data } proc mp_xref {} { global pages set data "


      [sect Manpages]" foreach tag $pages(mp) { if {0 == [string compare $tag $pages(_)]} { append data [nav_link "[$tag text]"] } else { append data [nav_link [$tag]] } } return $data } tkHTML-4ee7aaa953d6cb59/tools/rules/xmlrules.tcl000064400000000000000000000113131151224263100207650ustar00nobodynobody# -*- tcl -*- # # $Id: xmlrules.tcl,v 1.1 2002/12/17 18:31:05 drh Exp $ # # [expand] utilities for generating XML. # # Copyright (C) 2001 Joe English . # Freely redistributable. # ###################################################################### # xmlEscape text -- # Replaces XML markup characters in $text with the # appropriate entity references. # variable textMap { & & < < > > } variable attvalMap { & & < < > > {"} " } ; # " proc xmlEscape {text} { variable textMap string map $textMap $text } # startTag gi ?attname attval ... ? -- # Return start-tag for element $gi with specified attributes. # proc startTag {gi args} { variable attvalMap if {[llength $args] == 1} { set args [lindex $args 0] } set tag "<$gi" foreach {name value} $args { append tag " $name='[string map $attvalMap $value]'" } return [append tag ">"] } # endTag gi -- # Return end-tag for element $gi. # proc endTag {gi} { return "" } # emptyElement gi ?attribute value ... ? # Return empty-element tag. # proc emptyElement {gi args} { variable attvalMap if {[llength $args] == 1} { set args [lindex $args 0] } set tag "<$gi" foreach {name value} $args { append tag " $name='[string map $attvalMap $value]'" } return [append tag "/>"] } # xmlComment text -- # Return XML comment declaration containing $text. # NB: if $text includes the sequence "--", it will be mangled. # proc xmlComment {text} { return "" } # wrap content gi -- # Returns $content wrapped inside <$gi> ... tags. # proc wrap {content gi} { return "<$gi>$content" } # wrap? content gi -- # Same as [wrap], but returns an empty string if $content is empty. # proc wrap? {content gi} { if {![string length [string trim $content]]} { return "" } return "<$gi>$content" } # wrapLines? content gi ? gi... ? # Same as [wrap?], but separates entries with newlines # and supports multiple nesting levels. # proc wrapLines? {content args} { if {![string length $content]} { return "" } foreach gi $args { set content [join [list <$gi> $content ] "\n"] } return $content } # sequence args -- # Handy combinator. # proc sequence {args} { join $args "\n" } ###################################################################### # XML context management. # variable elementStack [list] # start gi ?attribute value ... ? -- # Return start-tag for element $gi # As a side-effect, pushes $gi onto the element stack. # proc start {gi args} { variable elementStack lappend elementStack $gi return [startTag $gi $args] } # xmlContext {gi1 ... giN} -- # Pops elements off the element stack until one of # the specified element types is found. # # Returns: sequence of end-tags for each element popped. # proc xmlContext {gis} { variable elementStack set endTags [list] while { [llength $elementStack] && [lsearch $gis [set current [lindex $elementStack end]]] < 0 } { lappend endTags "" set elementStack [lreplace $elementStack end end] } return [join $endTags \n] } # end ? gi ? -- # Generate markup to close element $gi, including end-tags # for any elements above it on the element stack. # # If element name is omitted, closes the current element. # proc end {{gi {}}} { variable elementStack if {![string length $gi]} { set gi [lindex $elementStack end] } set prefix [xmlContext $gi] set elementStack [lreplace $elementStack end end] return [join [list $prefix ] "\n"] } ###################################################################### # Utilities for multi-pass processing. # # Not really XML-related, but I find them handy. # variable PassProcs variable Buffers # pass $passNo procName procArgs { body } -- # Specifies procedure definition for pass $n. # proc pass {pass proc args body} { variable PassProcs lappend PassProcs($pass) $proc $args $body } proc setPassProcs {pass} { variable PassProcs foreach {proc args body} $PassProcs($pass) { proc $proc $args $body } } # holdBuffers buffer ? buffer ...? -- # Declare a list of hold buffers, # to collect data in one pass and output it later. # proc holdBuffers {args} { variable Buffers foreach arg $args { set Buffers($arg) [list] } } # hold buffer text -- # Append text to named buffer # proc hold {buffer entry} { variable Buffers lappend Buffers($buffer) $entry return } # held buffer -- # Returns current contents of named buffer and empty the buffer. # proc held {buffer} { variable Buffers set content [join $Buffers($buffer) "\n"] set Buffers($buffer) [list] return $content } #*EOF* tkHTML-4ee7aaa953d6cb59/tools/setversion000075500000000000000000000046211151224263100174070ustar00nobodynobody#!/bin/sh # -*- tcl -*- \ exec tclsh "$0" ${1+"$@"} # Insert version and other information into a number of files. global trouble set trouble 0 # ============================================================ # Generate the substitution map. proc mapdef {k v} { global map set map(@${k}@) $v return } proc map {} { global map set res [list] foreach k [lsort [array names map]] { lappend res $k $map($k) } return $res } # ============================================================ proc svfile {fname patternlist} { global trouble subst out if {![file exists $fname]} { puts stderr "File $fname: Does not exist" set trouble 1 return } puts "Updating file $fname ..." set fh [open $fname r] set contents [read $fh] close $fh puts $out "svfile [list $fname] \{" foreach {pattern current} $patternlist { set newvalue [string map $subst $pattern] puts $out " [list $pattern]" puts $out " [list $newvalue]" set contents [string map [list $current $newvalue] $contents] } puts $out "\}" if {[catch { set fh [open ${fname}.new w] puts -nonewline $fh $contents close $fh }]} { file delete -force ${fname}.new puts stderr "Unable to write new contents of $fname" set trouble 1 return } file rename -force ${fname}.new $fname return } proc extension {name data} { global pname set pname $name } # ============================================================ set v [lindex $argv 0] if {$v == {}} { puts stderr "Usage: $argv0 major.minor(\[abp.\]patchlevel)?" exit -1 } regexp {([0-9]+)\.([0-9+])(([abp.])([0-9]+))?} $v \ -> major minor __ detail patchlevel source DESCRIPTION mapdef mDate [string toupper \ [clock format \ [clock seconds] -format "%b-%d-%Y"]] mapdef mFullVersion $v mapdef mMajor $major mapdef mMinor $minor mapdef mShortDosVersion $major$minor mapdef mVersion ${major}.$minor mapdef mName $pname # ============================================================ set flistfile [file join [file dirname [info script]] svfiles] set newflist ${flistfile}.new set out [open ${flistfile}.new w] set subst [map] source $flistfile close $out ## set trouble 1 ; # enforce that new file does not overwrite old if {!$trouble} { file rename -force ${flistfile}.new ${flistfile} } tkHTML-4ee7aaa953d6cb59/tools/sgmlparse.c000064400000000000000000000127051151224263100174230ustar00nobodynobody/* ** This file contains code used to tokenize SGML. */ #include #include #include #include #include #include "sgmlparse.h" #define stricmp strcasecmp /* These three pointers define certain special handlers. All whitespace ** is sent to xSpaceHandler. Non-whitespace is given to xWordHandler. ** Any markup that isn't specifically directed elsewhere is given ** to xDefaultMarkupHandlers. */ static void (*xSpaceHandler)(const char*,void*); static void (*xWordHandler)(const char*,void*); static void (*xCommentHandler)(const char*,void*); static void (*xDefaultMarkupHandler)(int, const char**, void*); /* Each handler is stored in a hash table as an instance of the ** following structure. */ typedef struct sgHandler Handler; struct sgHandler { char *zName; /* Name of markup to handle */ void (*xHandler)(int, const char**, void*); /* Routine to do the work */ Handler *pCollide; /* Next handler with same hash */ }; /* The size of the handler hash table. ** For best results, this should be a prime number which is larger than ** the number of markups in the hash table. */ #define SGML_HASH_SIZE 203 /* The handler hash table */ static Handler *apHandler[SGML_HASH_SIZE]; /* Hash a handler name */ static int SgmlHash(const char *zName){ int h = 0; char c; while( (c=*zName)!=0 ){ if( isupper(c) ) c = tolower(c); h = h<<5 ^ h ^ c; zName++; } if( h<0 ) h = -h; return h % SGML_HASH_SIZE; } /* Given a pointer to an input file, read and parse that file ** as if it were SGML. ** ** This is not a true SGML parser because it handles some unusual ** cases differently, and ignores the & operator completely. */ void SgmlParse(FILE *in, void *pArg){ int c; int i, j; int argc; Handler *pHandler; char *argv[100]; char zBuf[10000]; c = getc(in); while( c!=EOF ){ if( isspace(c) ){ /* Case 1: spaces */ zBuf[0] = c; i = 1; while( i' ) c = getc(in); zBuf[i] = 0; if( strncmp(zBuf,"

      Site Contents

      • Home Front page of this site
      • Standards Summary of support for CSS and HTML standards
      • Man page Unix style manual page for the widget.
      • Hv3 Page for the demo/test application hv3. Screenshots and starpacks for windows and linux are available here.
      • Cvstrac Cvstrac is used for project change-log, wiki and bug tracking.
      } proc getTabs {idx} { set ret "
      " append ret {
      } append ret set ii 0 foreach {label href caption} [list \ Home index.html "Front page of this site" \ Standards support.html "Summary of support for CSS and HTML standards" \ "Tkhtml3" tkhtml.html "Unix style manual page for the Tkhtml3 widget." \ "Hv3" hv3.html { Page for the web browser application hv3. Screenshots and starpacks for windows and linux are available here. } \ "Hv3 Widget" hv3_widget.html { Page for the Hv3 mega-widget, a Snit based pure Tcl widget that adds some commonly requested functionality to Tkhtml3. } \ FFAQ ffaq.html "tkhtml.tcl.tk FFAQ" \ Cvstrac http://tkhtml.tcl.tk/cvstrac/timeline { Cvstrac is used for project change-log, wiki and bug tracking. } ] { if {$ii==$idx} { append ret [subst { } incr ii } append ret
      $label}] } else { append ret "$label" } append ret "$caption" append ret {
      append ret
      return $ret } set ::PageSectionList [list] proc addPageSection {title name} { lappend ::PageSectionList [list $title $name] } proc getToc {} { append ret {

      Page Contents

        } foreach entry $::PageSectionList { foreach {caption href} $entry {} append ret "
      • $caption
      • \n" } append ret "
      \n
      " return $ret } tkHTML-4ee7aaa953d6cb59/webpage/mkffaqpage.tcl000064400000000000000000000062541151224263100203440ustar00nobodynobody source [file join [file dirname [info script]] common.tcl] addPageSection "Download" download addPageSection "Source Code/Hacking" source addPageSection "More Information" info proc VERSION {} { if {[info exists ::env(VERSION)]} {return $::env(VERSION)} return "alpha-15" } set idx 1 proc Q {id Question Answer} { global idx append ::BODY "

      ${idx}. $Question

      " append ::BODY $Answer append ::TOC "
    • ${idx}. $Question" incr idx } Q statefile {How can I save my options/cookies/history-list etc.?} {

      By default, Hv3 saves absolutely no data to the file system. After the Hv3 window has been closed, it is not possible for anyone else using the same computer to discover which websites you have visited or logged in to.

      However, although this preserves your privacy, sometimes it is not conveniant. If a "state file" is enabled, Hv3 stores the following data to a file on disk:

      • HTTP cookies.
      • The list of visited URIs (used for auto-completion in the location bar and for coloring visited hyperlinks).
      • The values of the settings configured in the "Options" pull-down menu, except for the "Hide GUI" option.
      • User bookmarks.

      To use a state file, specify the "-statefile" option as part of the command line used to start Hv3. The -statefile option is used to specify a file on disk used to persistently store various elements of the browser application state. Windows users may need to create a "batch file" to achieve this. For example, assuming that the Hv3 binary is named "hv3-linux-nightly-07_0723" and you wish to use the file "/home/dan/hv3_state.db" as the statefile, the full command line would be:

          hv3-linux-nightly-07_0723 -statefile /home/dan/hv3_state.db
      

      Because the state file is actually an SQLite database, there is no problem with two or more Hv3 processes using the same state file simultaneously. Bookmarked and configuration settings are propagated between instances automatically.

      } Q hv3_polipo {What is this hv3_polipo?} {

      hv3_polipo is a very slightly modified version of the standard polipo program by Juliusz Chroboczek, available at http://www.pps.jussieu.fr/~jch/software/polipo/. The modifications are designed to make sure that no hv3_polipo processes are left running if hv3 crashes or is terminated by the operating system. The patch used to create the custom version is available here.

      If building Hv3 from source code, you probably want to obtain hv3_polipo as well. The starkit and other pre-built packages available here already include pre-compiled versions.

      } puts [subst { tkhtml.tcl.tk FFAQ [getTabs 5]

      tkhtml.tcl.tk FFAQ

        $::TOC
      $::BODY }] tkHTML-4ee7aaa953d6cb59/webpage/mkhv3page.tcl000064400000000000000000000131541151224263100201240ustar00nobodynobodysource [file join [file dirname [info script]] common.tcl] addPageSection "Download" download addPageSection "Source Code/Hacking" source addPageSection "More Information" info proc VERSION {} { if {[info exists ::env(VERSION)]} {return $::env(VERSION)} return "alpha-16" } if {[string first alpha [VERSION]] == 0} { set files_comment "" } else { set files_comment [subst -novariables {

      The files offered for download above are not built from any specific released version of Tkhtml. Instead, they are updated whenever the source code is considered stable enough (some projects call these "nightly" builds). In practice this means once every couple of days. The binaries currently offered were last updated at [clock format [clock seconds]]. }] } puts [subst -novariables { Html Viewer 3 - Tkhtml3 Web Browser [getTabs 3]

      Hv3 - Tcl/Tk Web Browser

      [getToc]

      Html Viewer 3 (hv3) is a powerful yet minimalist web browser that uses Tkhtml3 as a rendering engine and SEE (Simple ECMAScript Engine) to interpret scripts. The application itself is written in Tcl. Currently it is at alpha stage. Please try it out, then report bugs or make suggestions.

      Instructions for obtaining source code, reporting bugs, requesting enhancements, joining the mailing list and contacting the authors may be found on the front page of this site.

      Download

      Windows

      hv3-win32-[VERSION].exe - Executable for win32 platforms.

      hv3-win32-[VERSION].kit - Starkit package. To use this you also require a tclkit runtime from Equi4 software (http://www.equi4.com). If you're not sure what this means, grab the executable file above instead.

      Generic Linux

      hv3-linux-[VERSION].gz - Gzip'd executable for linux x86 platforms. Everything is staticly linked in, so there are no dependencies. To use this, download the file, gunzip it, set the permissions to executable and run it. i.e. execute the following commands from a terminal window:

        wget http://tkhtml.tcl.tk/hv3-linux-[VERSION].gz
        gunzip hv3-linux-[VERSION].gz
        chmod 755 hv3-linux-[VERSION]
        ./hv3-linux-[VERSION]
      

      hv3-linux-[VERSION].kit - Starkit package. To use this you also require a tclkit runtime from Equi4 software (http://www.equi4.com). If you're not sure what this means, grab the gzip'd executable file above instead.

      Puppy Linux

      hv3-[VERSION].pet - Pupget package for Puppy linux (http://www.puppyos.com). This won't work with other linux distributions. For anything other than puppy or puppy derivitives, use the generic linux package above.

      [set ::files_comment]

      Detailed version information for any hv3 build may be found by visiting the internal URI "home://about/" (i.e. type "home://about/" into the location entry field at the top of the window).

      Source Code and Hacking

      A goal of Hv3 development is that the source code should be accessible; it should be easy to hack on. For those wishing to experiment with modifying Hv3 source code, there are two options:

      1. By downloading one of the starkits available above and editing the Tcl code.
      2. By building the whole system from scratch.

      The Windows and "Generic Linux" *.kit files available for download above are constructed using starkit technology. This means you can "unwrap" them, modify the source code therein, and run the modified version. The "Getting started with Starkits and Tclkit" page over at equi4.com provides a step by step example of doing this.

      To build the system from scratch, first obtain the latest sources for Tkhtml3 and Hv3. Detailed instructions for building the required components (Tkhtml3, hv3_polipo and Tclsee) and running the Hv3 script are found in the COMPILE.txt file of the source code distribution.

      More Information

      There is more information related to Hv3 to be found in the tkhtml.tcl.tk FFAQ.

      }] tkHTML-4ee7aaa953d6cb59/webpage/mksupportpage.tcl000064400000000000000000000322431151224263100211400ustar00nobodynobody source [file join [file dirname [info script]] common.tcl] set ::html {} set ::html_head {} proc P {args} { foreach a $args { append ::html "$a " } append ::html "\n" } proc SUPPORTTABLE {title args} { P
      $title foreach {a b} $args { P
      $a $b } P
      } proc CSSREF {section property {class {support}}} { # set cssdoc file:///home/dan/work/tkhtml/docs/css_1.0/css1_spec.html set cssdoc http://www.w3.org/TR/CSS21/ set ref ${cssdoc}${section}.html#propdef-${property} return "$property" } set ::section_counter 1 proc SECTION {title} { set name "part$::section_counter" P

      $title

      addPageSection $title $name incr ::section_counter } set ::title "" proc START {title} { set ::html_head [subst { $title }] set ::title $title } proc FINISH {} { puts $::html_head puts [getTabs 1] puts [subst {

      $::title

      [getToc] }] puts {
      } puts $::html puts {
      } } ########################################################################### START "DOM, CSS and HTML Support" P {

      Ultimately, Tkhtml3 aims to support those aspects of HTML 4.01 and CSS 2.1 that apply to the parsing and visual rendering of documents. But, as you may have surmised, that is a work in progress. This document describes the current situation in terms of the CSS properties, CSS selectors, HTML attributes and HTML tags supported.

      This document currently tracks the CVS version against the CSS 2.1, HTML 4.01 (todo) and DOM (todo) specifications.

      } SECTION "CSS Property Support" P {

      The tables in this section compare CSS property support in Tkhtml3 with the CSS level 2.1 specification. Of course, there may be bugs in the support of any or all of the properties listed as supported below. If you find a bug, please report it!

      } SUPPORTTABLE {Font Properties} \ [CSSREF fonts font-family] { Standard families "cursive" and "fantasy" are only available if the underlying font system used by Tk supports them. } \ [CSSREF fonts font-style] { Values 'italic' and 'oblique' map to "-slant italic" and 'normal' maps to "-slant roman". } \ [CSSREF fonts font-variant nosupport] {No support.} \ [CSSREF fonts font-weight] { Values 'bold', 'bolder' and numbers greater than 550 map to "-weight bold", everything else maps to "-weight normal". } \ [CSSREF fonts font-size] {} \ [CSSREF fonts font] { Supported except for font-variant values ('small-caps'). } SUPPORTTABLE {Color and Background Properties} \ [CSSREF colors color] {} \ [CSSREF colors background-color] {} \ [CSSREF colors background-image] {} \ [CSSREF colors background-repeat] {} \ [CSSREF colors background-attachment] {} \ [CSSREF colors background-position] {} \ [CSSREF colors background] {} SUPPORTTABLE {Text Properties} \ [CSSREF text word-spacing nosupport] {No support.} \ [CSSREF text letter-spacing nosupport] {No support.} \ [CSSREF text text-decoration] { Value 'blink' is not supported. Also, multiple decorations (e.g. an underline and an overline) are not supported. } \ [CSSREF text vertical-align] {} \ [CSSREF text text-transform nosupport] {No support.} \ [CSSREF text text-align] {} \ [CSSREF text text-indent] {} \ [CSSREF text white-space] {} SUPPORTTABLE {Box Properties} \ [CSSREF box margin] { Properties 'margin-top', 'margin-right', 'margin-bottom' and 'margin-left' are also supported. } \ [CSSREF box padding] { Properties 'padding-top', 'padding-right', 'padding-bottom' and 'padding-left' are also supported. } \ [CSSREF box border-width] {} \ [CSSREF box border-style] { All border styles apart from 'none' (i.e. 'dashed', 'groove' etc.) are currently rendered as solid lines. This is legal according to the spec, but it's sub-optimal. } \ [CSSREF box border-color] {} \ [CSSREF box border] { Properties 'border-top', 'border-right', 'border-bottom' and 'border-left' are also supported. Also 'border-top-color', 'border-left-width' and other such variants. } SUPPORTTABLE {Visual Rendering Properties} \ [CSSREF visuren display] { Not all values are supported. Currently supported values are 'inline', 'block', 'list-item', 'table', 'table-row', 'table-cell', 'none' and 'inherit'. The following are handled as 'block': 'run-in', 'inline-block', 'table-caption'. } \ [CSSREF visudet width] {} \ [CSSREF visudet height] {} \ [CSSREF visuren float] {} \ [CSSREF visuren clear] {} \ [CSSREF visudet line-height] {} \ [CSSREF visudet min-width] {Support is a bit patchy. Most cases work.} \ [CSSREF visudet max-width] {Support is a bit patchy. Most cases work.} \ [CSSREF visudet min-height] {Support is a bit patchy. Most cases work.}\ [CSSREF visudet max-height] {Support is a bit patchy. Most cases work.}\ [CSSREF visuren position] { Positioning modes 'static', 'relative', 'fixed' and 'absolute' are all supported. } \ [CSSREF visuren left] {} \ [CSSREF visuren right] {} \ [CSSREF visuren top] {} \ [CSSREF visuren bottom] {} \ [CSSREF visuren z-index] {} \ [CSSREF visuren unicode-bidi nosupport] { Tkhtml3 does not yet support bi-directional text. So the properties "unicode-bidi" and "direction" are both ignored. } \ [CSSREF visuren direction nosupport] {No support.} SUPPORTTABLE {Visual Effects Properties} \ [CSSREF visufx overflow] {} \ [CSSREF visufx clip nosupport] {No support.} \ [CSSREF visufx visibility] {} SUPPORTTABLE {Table Properties} \ [CSSREF tables border-collapse nosupport] {No support.} \ [CSSREF tables border-spacing] {} \ [CSSREF tables caption-side nosupport] {No support.} \ [CSSREF tables empty-cells nosupport] {No support.} \ [CSSREF tables table-layout nosupport] {No support.} SUPPORTTABLE {User Interface Properties} \ [CSSREF ui cursor] { Only enumerated values are supported. Tkhtml3 doesn't actually do anything with this property, but it is available for the applications use. } \ [CSSREF ui outline] {} \ [CSSREF ui outline-width ] {} \ [CSSREF ui outline-color ] {} \ [CSSREF ui outline-style ] {} SUPPORTTABLE {Generated Content Properties} \ [CSSREF generate list-style-type] {} \ [CSSREF generate list-style-image] {} \ [CSSREF generate list-style-position] {} \ [CSSREF generate list-style] {} \ [CSSREF generate content] {String, attr(), counter() and counters() values work. There is no support for url(), or the keywords for automatic quotes generation. } \ [CSSREF generate counter-increment] {} \ [CSSREF generate counter-reset] {} \ [CSSREF generate quotes nosupport] {No support.} # List of CSS 2.1 properties considered out of scope for Tkhtml. set outofscopes { azimuth cue-after cue-before cue elevation pause-after pause-before pause pitch-range pitch play-during richness speak-header speak-numeral speak-punctuation speak speech-rate stress voice-family volume orphans page-break-after page-break-before page-break-inside widows } P {

      The following CSS 2.1 properties are currently considered to be outside of Tkhtml3's scope, as they only apply to aural or paged document rendering:

      } P
        set ii 1 foreach property $outofscopes { P
      • $property incr ii if {$ii % 10 == 0} {P
        } } P
      SECTION {CSS Selector Support} P {

      Essentially, all CSS 2.1 selectors are supported except for the following pseudo-elements:

      • :first-letter
      • :first-line
      • :lang
      } if 0 { SECTION {HTML Parsing Support} P {

      This section describes the some of the special processing that Tkhtml does to support HTML.

      Implicit Elements

      In any Html document, the <html>, <head> and <body> elements are always present, even if not explicity opened or closed in the html text.

      Implicit Closing Tags

      This sub-section describes the cases where the Html parser infers the presence of implicit closing tags and inserts them before generating the document tree. Tkhtml can detect implicit closing tags in five cases:

      Empty elements:
      The <br>, <area>, <link>, <img>, <param>, <hr>, <base>, <meta> and <input> elements are always empty, they cannot contain any other elements.
      Inline content only elements:
      The <p> and <dt> elements may only contain inline content. They are implicitly closed by any element that does not generate inline content (according to html).
      Flow content only elements:
      The <th>, <td>, <p> and <dt> elements may only contain flow content. They are implicitly closed by any element that does not generate flow content (according to html).
      Table-cell content only elements:
      The <tr> element may only contain <th> or <td> elements.
      Text content only elements:
      The <option> element may only contain text, not markup tags.

      Table Support

      Table support is a curious mix of support for CSS and Html at the moment. The CSS display types 'table', 'table-row' and 'table-cell' are recognized for laying out document sub-trees as tables. The default stylesheet assigns these values to the display properties of Html <table>, <tr>, <td> and <th> elements.

      Tkhtml checks for and respects the "rowspan" and "cellspan" attributes on any element with the display property set to 'table-cell'. There is no way to asign a row or column span via CSS (at least not with Tkhtml).

      There is no support for the <caption>, <thead>, <tfoot>, <tbody>, <colgroup> and <col> tags, these are ignored by the parser.

      The Tkhtml layout engine simply ignores any children of an element with display property 'table' that do not have their display property set to 'table-row'. Children of 'table-row' elements that are not of type 'table-cell' are similarly ignored. This is incorrect, the CSS2 specification requires anonymous boxes to be inserted where such elements are missing. The Tkhtml html parser compensates for this by transforming each sub-tree rooted at a <table> element according to the following rules:

      1. Children of <table> elements other than <tr>, <td> and <th> are moved in the tree to become left-hand siblings of the <table> element.
      2. Should there exist one or more <td> or <th> children of the <table> element, then one or more <tr> elements is inserted into the tree. Each new <tr> element is a child of the <table> element.
      3. Children of <tr> elements that are themselves children of <table> elements other than <td> and <th> are also moved in the tree to become left-hand siblings of the <table> element.

      Logically, steps are performed in the order above. For example, parsing the following Html fragment:

      <table>
        <div>Text A</div>
        <tr> <div>Text B</div>
          <td> Text C
        </tr>
        <td> Text D
        <td> Text E
      </table>
        

      Produces the tree that one would expect from:

      <div>Text A</div>
      <div>Text B</div>
      <table>
        <tr> 
          <td> Text C
        </tr>
        <tr> 
          <td> Text D
          <td> Text E
        </tr>
      </table>
        
      } SECTION {HTML Element Support} # List of HTML attributes: abbr accept-charset accept accesskey action align alt archive axis background bgcolor border cellpadding char charoff charset checked cite class classid clear code codebase codetype color cols colspan compact content coords data datetime declare defer dir disabled enctype face for frame frameborder headers height href hreflang hspace http-equiv id ismap label lang language link longdesc longdesc marginheight marginwidth maxlength media method multiple name nohref noresize noshade nowrap object profile prompt readonly rel rev rows rowspan rules scheme scope scrolling selected shape size span src standby start style summary tabindex target text title type usemap valign value valuetype version vlink vspace width } FINISH tkHTML-4ee7aaa953d6cb59/webpage/mkwebpage.tcl000064400000000000000000000147111151224263100202010ustar00nobodynobody#!/usr/bin/tclsh # # Construct the web page for tkhtml # # @(#) $Id: mkwebpage.tcl,v 1.38 2007/10/03 10:06:39 danielk1977 Exp $ # source [file join [file dirname [info script]] common.tcl] proc header {} { puts { tkhtml.tcl.tk } } proc footer {} { puts { } } set ::TITLE {} ;# The title set ::BODY {} ;# Body of html document is built up in this variable proc p {text} { append ::BODY

      append ::BODY $text append ::BODY

      } set ::H 0 proc h {level text} { set var ::BODY if {$level==1} { set var ::TITLE } append $var if {$level==2} { set name "part[incr ::H]" append ::BODY "" addPageSection $text $name } append $var $text append $var } proc output_page {} { header puts [getTabs 0] puts {
      } puts $::TITLE puts [getToc] puts {
      } puts $::BODY puts {
      } puts {
      } footer } ########################################################################### # Document content is below this line. h 1 {tkhtml.tcl.tk} p {

      This website hosts the tkhtml.tcl.tk project, an experiment in creating modern web browser components based on the Tcl/Tk platform. Currently this consists of two pieces of software and their accompanying documentation:

      Hv3 Hv3 is a cross-platform web browser with support for modern web standards like HTML, CSS, HTTP and ECMAScript (a.k.a. javascript).
      Tkhtml3 Tkhtml3 is a Tk widget that displays content formatted according to the HTML and CSS standards. Tkhtml3 is not an end-user application, it is for Tcl programmers who wish to embed a standards-compliant HTML/CSS implementation in their applications.

      There is a mailing list for Hv3 and Tkhtml3 hosted by Google Groups. You can join the mailing list, view the archive and post new messages by clicking here:

      The Tkhtml3/Hv3 mailing list

      Bug reports, enhancement requests and the project changelog are managed by a CVStrac installation. There is also a wiki where users can contribute content. Access CVStrac here:

      CVSTrac - Bug reports, Enhancement requests, Changelog and Wiki
      } h 2 {Documents} p {
      • A paper describing Tkhtml3 (www.tcl.tk) was presented at the 2006 Tcl conference. Even though it is a little out of date, this is the best general introduction to Tkhtml3 programming available. Prospective users should read this paper for a general overview, then proceed to the tkhtml(n) man page to absorp the details.
      • An early requirements specification from way back in 2005. This is no longer really relevant, but it's amusing in it's own way.
      } h 2 {Source Code} p {

      The source code for Tkhtml3 and Hv3 is bundled together as a single project for source code management purposes. It can be obtained either by downloading a release tarball, or via anonymous CVS.

      Download the source code for the latest release (alpha 16).

      Or to obtain the lastest source-code from cvs, use the following procedure (from an x-term or command prompt):

      1. Log in with the following command:
        cvs -d :pserver:anonymous@tkhtml.tcl.tk:/tkhtml login
      2. You will be prompted for a password. Use "anonymous".
      3. Obtain the lastest version 3 source code:
        cvs -d :pserver:anonymous@tkhtml.tcl.tk:/tkhtml checkout htmlwidget
      } h 2 {Participation} p { tkhtml.tcl.tk is an open-source project, and so requires community participation to succeed. All are welcome! Here are some of the ways you can participate:
      Using Hv3 Download Hv3 and browse the web with it for a while. Report any bugs, problems or incompatibilities that you encounter. Make some suggestions for improvements.
      Using Tkhtml3 Write a program that uses Tkhtml3, or embed it into an existing program. Comment on your experience doing so and report any bugs.
      Join The Mailing List Join the Tkhtml3/Hv3 mailing list hosted at Google Groups to discuss Tkhtml3 or Hv3.
      Help Out With The Website As you can see, the website isn't up to much at the moment (ironic eh?). If you would like to help change that, or if you can help by building a mac osx build, please get in touch.
      Join The Development Team If you can program in C, Tcl or javascript, then you are welcome to join the development team. Pick an aspect of Tkhtml3 or Hv3 you want to improve, post a message to the mailing list, and go from there.
      } h 2 {Contacts} p { It is best to join the mailing list and post messages there. That way there is an archive of the message. Alternatively, you can send mail to one of the following contacts:
      danielk1977@gmail.com (Dan - current maintainer)
      drh@hwaci.com (Richard)
      } output_page tkHTML-4ee7aaa953d6cb59/webpage/tkhtml_tcl_tk.css000064400000000000000000000033271151224263100211110ustar00nobodynobody #toc { float: right; margin: 1em 1em 1em 1em; padding: 1em; border: 1px solid black; } #toc ul, #toc li { display: block; margin: 0; padding: 0; } #toc li { margin-left: 3ex; display: list-item; list-style-type: decimal; } #toc h3 { margin-top: 0; } body { background-color: #d9d9d9; } h1 { text-align: center; margin: 1em; } table { margin: 1em auto; } #sitemap { max-width:720px; margin:auto; position: relative; } #sitemap h3 { display: none; } #sitemap table { overflow: auto; margin:auto; line-height: 1.5em; padding: 0px; border-spacing: 0px; } #sitemap tr { border-spacing: 0px; } #sitemap td { border: black 1px solid; border-bottom: none; } #sitemap td.spacer { border: none; } #sitemap a[href] { display: block; padding: 0.5em 1em 0px 1em; text-decoration: none; color: black } #sitemap .caption { display: none; } #sitemap td:hover .caption { display: block; position: absolute; top: 110%; left: 25%; right: 25%; display: block; border: 1px solid black; background-color: #ececec; padding: 0px 0.5em; } #sitemap #active .caption { display: none; position: static; } a[href]:hover { background-color: #ececec; color: black; border-bottom: solid black 1px; text-decoration: none; } #sitemap a[href] { border-bottom: none; background-color: transparent; } #sitemap td:hover { background-color: #ececec; } #sitemap #active { background-color: white; } #body { text-align: left; border: black 1px solid; padding: 0px 0.5em; max-width: 720px; margin: auto; background-color: white; } .bigred { font-size: 1.6em; /* color:red; text-decoration:none; */ } .screenshot { border: solid 1px black; margin: 1em; }