pax_global_header00006660000000000000000000000064135471557420014527gustar00rootroot0000000000000052 comment=b9cd4b01995218e2470e41411a949e417512ebe6 htmldoc-1.9.7/000077500000000000000000000000001354715574200131775ustar00rootroot00000000000000htmldoc-1.9.7/CHANGES.md000066400000000000000000000222511354715574200145730ustar00rootroot00000000000000# Changes in HTMLDOC v1.9.7 - Refactored the PRE rendering code to work around compiler optimization bugs (Issue #349) - Added support for links with targets (Issue #351) - Fixed a table rowspan + valign bug (Issue #360) # Changes in HTMLDOC v1.9.6 - Added support for data URIs (Issue #340) - HTMLDOC no longer includes a PDF table of contents when converting a single web page (Issue #344) - Updated the markdown support with external links, additional inline markup, and hard line breaks. - Links in markdown text no longer render with a leading space as part of the link (Issue #346) - Fixed a buffer underflow bug discovered by AddressSanitizer. - Fixed a bug in UTF-8 support (Issue #348) - PDF output now includes the base language of the input document(s) (Issue #350) - Optimized the loading of font widths (Issue #354) - Optimized PDF page resources (Issue #356) - Optimized the base memory used for font widths (Issue #357) - Added proper `­` support (Issue #361) - Title files can now be markdown. # Changes in HTMLDOC v1.9.5 - The GUI did not support EPUB output. - Empty markdown table cells were not rendered in PDF or PostScript output. - The automatically-generated title page now supports both "docnumber" and "version" metadata. - Added support for dc:subject and dc:language metadata in EPUB output from the HTML keywords and lang values. - Added support for the subject and language metadata in markdown input. - Fixed a buffer underflow bug (Issue #338) - `htmldoc --help` now reports whether HTTPS URLs are supported (Issue #339) - Fixed an issue with HTML title pages and EPUB output. # Changes in HTMLDOC v1.9.4 - Inline fixed-width text is no longer reduced in size automatically (Issue #309) - Optimized initialization of font width data (Issue #334) # Changes in HTMLDOC v1.9.3 - Fixed formatting bugs with aligned images (Issue #322, Issue #324) - Fixed support for three digit "#RGB" color values (Issue #323) - Fixed character set support for markdown metadata. - Updated libpng to v1.6.34 (Issue #326) - The makefiles did not use the CPPFLAGS value (Issue #328) # Changes in HTMLDOC v1.9.2 - Added Markdown table support. - Fixed parsing of TBODY, TFOOT, and THEAD elements in HTML files. # Changes in HTMLDOC v1.9.1 - Fixed monospace font size issue (Issue #309) - Added support for reproducible builds (Issue #310) - Added limited support for the HTML 4.0 SPAN element (Issue #311) - Added (extremely limited) UTF-8 support for input files (Issue #314) - Fixed buffer underflow for (invalid) short HTML comments (Issue #316) - Now indent PRE text, by popular request. - EPUB output now makes sure that `` is written as ``. - Now support both NAME and ID for table-of-contents targets. # Changes in HTMLDOC v1.9 - Added support for repeating a single header row for tables that span multiple pages (Issue #16) - Added support for embedding the current filename/URL in the header or footer (Issue #50) - Added EPUB support (Issue #301) - Added Markdown support (Issue #302) - Fixed a regression in header/footer image scaling (Issue #303) - Documentation updates (Issue #305) - Compiler fixes (Issue #304, Issue #306) - Fixed a bug when running HTMLDOC as a macOS application. - Updated the bundled libpng to v1.6.29. # Changes in HTMLDOC v1.8.30 - Updated documentation to reflect new project page on Github. - Dropped old CDE and IRIX desktop integration files. - Cleaned up the GUI and adopted new default text editors for Linux and macOS. - PAGE BREAK comments at the end of a file in web page mode would lose the first page (Issue #251) - Fixed the scaling of header/footer images to limit them to the height of the header or footer (Issue #273) - Fixed an issue with the top-level makefile not exiting with an error as needed (Issue #282) - Fixed a URL referencing bug when the same hostname but a different port was used (Issue #290) - Fixed build issue on macOS (Issue #291) - Fixed handling of indexed+alpha PNG images (Issue #295) # Changes in HTMLDOC v1.8.29 - Updated local PNG library to version 1.6.20. - Updated local JPEG library to version 9b. - Dropped support for OpenSSL. - Added configure script support for libjpeg-turbo. - Updated HTTP code to latest CUPS/ippsample sources. - Duplex PDF output incorrectly forced an even number of pages - The table of contents showed the wrong page numbers after headings containing the "_HD_OMIT_TOC" attribute. - Fixed reported build issues - The configure script's --enable-local* options did not work. # Changes in HTMLDOC v1.8.28 - Updated local zlib to version 1.2.8. - Updated local PNG library to version 1.6.8. - Updated local JPEG library to version 9. - Updated default PDF version to 1.4. - SECURITY: Fixed three buffer overflow issues when reading AFM files and parsing page sizes. - Fixed incompatibility with Fortify's version of strcpy, which does not work properly with variable-length arrays - Fixed compilation against PNG library 1.5 or later - Fixed documentation errors - Marked Zapf-Dingbats as a standard font - Fixed GPL license text in GUI - Fixed a table formatting problem when a column has multiple colspan values - Fixed parsing of HTML comments - Fixed potential out-of-bounds read in table-of-contents rendering code - Fixed handling of image URLs with ampersands in them - Fixed top/bottom margins for logo and header/footer images - Fixed image alignment bug - Fixed X11 build problem # Changes in HTMLDOC v1.8.27 - Fixed a crash bug that appeared when more than 10 blank pages were present in a document - Color changes were not reflected in PRE text - Remote URLs did not always work on older operating systems - Image filenames using % escapes were not decoded properly. - Rows using BGCOLOR that spanned across multiple pages did not render properly - Rows no longer start on a new page due to a cell with both HEIGHT and ROWSPAN specified - CMYK JPEG images caused HTMLDOC to crash - Table cell width calculations didn't always account for the proper minimum width - Images were not copied when generating indexed HTML output to a directory - Changing the bottom margin resulted in text that was formatted below the bottom margin. - The Monospace-Oblique font was not embedded properly in PDF files. # Changes in HTMLDOC v1.8.26 - Outline and keyword strings in PDF files are now stored as Unicode - The Flate compression code could get in an infinite loop if it ran out of memory - Book files saved from the GUI did not handle filenames with spaces - Fixed and re-enabled the ASCII85Device filter support in PostScript Level 2/3 output - Character entities in the first word of a file were not rendered properly - Fixed-size table columns were incorrectly resized when a table width was also specified and there was extra space to distribute - Text could "walk" up or down when in-line images were used - Row backgrounds incorrectly replaced cell backgrounds when the first cell in a row used ROWSPAN - HTMLDOC did not correctly parse FONT FACE attributes - Images in Level 2/3 PostScript output did not work on some printers - The GUI did not use the first page header # Changes in HTMLDOC v1.8.25 - Added "--overflow" and "--no-overflow" command-line options to show or hide the content-too-large errors; the default is "--no-overflow". - Added "--header1" command-line option and "HEADER1" page comments to set the page header for the first page of each chapter. - Added "timing" and "remotebytes" debug data generation. - Added DejaVu font collection to better support Cyrillic and Greek text; the new fonts are available under the generic names "monospace", "sans", and "serif". - Added "--referer" command-line option and corresponding CGI-mode support to pass Referer: information in HTTP requests - On Windows, HTMLDOC now logs CGI mode errors to a file called "htmldoc.log" in the Windows temporary directory. - HTMLDOC no longer uses Base-85 encoding for image data when producing Level 2 and 3 PostScript output. It appears that many printers and PostScript interpreters cannot properly decode this data when the original image data is not a multiple of 8 bits. - HTMLDOC now renders STRONG elements in boldface instead of bold-italic to match the W3C recommendations. - HTMLDOC now automatically inserts a TR element before a TD or TH element as needed to improve web site compatibility; this also triggers a HTML error in --strict mode. - "$HFIMAGEn" didn't work in a header/footer string. - HTMLDOC could crash when rendering a table. - Book files were not used in CGI mode - Cookies were not sent in HTTP requests - Table cells were not aligned properly when the ROWSPAN attribute was set to 1 - HTMLDOC crashed when rendering unresolved hyperlinks in aligned images - Documented the HTMLDOC_NOCGI environment variable - HTMLDOC sometimes crashed when rendering tables with background colors - HTMLDOC would crash when writing encrypted strings longer than 1024 bytes - HTMLDOC didn't set the data directory when running in CGI mode on Windows. - HTMLDOC could crash when loading the Symbol.afm file - HTMLDOC did not always honor HEIGHT attributes in table rows. - Tables with a mix of colspan and rowspan sometimes caused cells to be moved vertically outside the cell. htmldoc-1.9.7/COPYING000066400000000000000000000431231354715574200142350ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 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. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. 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 Program or any portion of it, thus forming a work based on the Program, 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) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, 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 Program, 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 Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) 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; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, 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 executable. However, as a special exception, the source code 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. If distribution of executable or 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 counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program 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. 5. 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 Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program 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 to this License. 7. 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 Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program 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 Program. 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. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program 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. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies 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 Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, 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 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. 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 PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License. htmldoc-1.9.7/INSTALL.md000066400000000000000000000044211354715574200146300ustar00rootroot00000000000000How to Install HTMLDOC from Source ================================== To compile HTMLDOC you'll need C and C++ compilers (gcc is fine, most vendor compilers work, too). The JPEG, PNG, and ZLIB libraries are provided with HTMLDOC. For the GUI support you'll need FLTK 1.1.x or 1.3.x. FLTK is a LGPL'd cross- platform GUI toolkit and can be downloaded from: http://www.fltk.org/ For HTTPS support you'll need GNU TLS on Linux and UNIX. Windows ------- A Visual Studio solution is included in the "vcnet" directory. You must add the FLTK include and library directories separately for the solution to build. We highly recommend building and installing the HTMLDOC MSI target, as it takes care of registering the installation location with Windows. If you want to install the software by hand, create a directory for the software and copy the HTMLDOC executable, the "fonts" directory, the "data" directory, and the "doc" directory to it so that it looks like this: C:\Install\Dir\ htmldoc.exe data\ ... data files ... doc\ ... doc files ... fonts\ ... fonts files ... Then create the following registry entries with REGEDIT: HKEY_LOCAL_MACHINE\Software\HTMLDOC\doc = C:\install\dir\doc HKEY_LOCAL_MACHINE\Software\HTMLDOC\data = C:\install\dir Linux, macOS, and Other UNIX Platforms -------------------------------------- To compile the software under UNIX you first need to run the "configure" script in the source directory. Usually this is just: ./configure Then run "make" to build the software and generate the documentation: make Finally, run "make install" (typically as root) to install the software: sudo make install Ubuntu Notes ------------ You should install the following packages: sudo apt-get install build-essential autoconf libfltk1.3-dev \ libgnutls28-dev libjpeg-dev libpng-dev zlib1g-dev CentOS, Fedora, and RHEL Notes ------------------------------ The version of GCC bundled with older releases of these operating systems cannot handle the version of libpng that is bundled with HTMLDOC. Install the following packages to avoid this and get full functionality: sudo yum install autoconf fltk-devel gnutls-devel libjpeg-devel \ libpng-devel zlib-devel htmldoc-1.9.7/Makedefs.in000066400000000000000000000034151354715574200152510ustar00rootroot00000000000000# # Makefile definitions for HTMLDOC, an HTML document processing program. # # Copyright © 2011-2019 by Michael R Sweet. # Copyright © 1997-2010 by Easy Software Products. # # This program is free software. Distribution and use rights are outlined in # the file "COPYING". # # # Programs... # AR = @AR@ AWK = @AWK@ CC = @CC@ CXX = @CXX@ CHMOD = @CHMOD@ CP = @CP@ INSTALL = @INSTALL@ LN = /bin/ln -sf MKDIR = @MKDIR@ -p MV = @MV@ POST = @POST@ RANLIB = @RANLIB@ RM = @RM@ -f SHELL = /bin/sh # The extension to use for executables... EXEEXT = @EXEEXT@ # # Installation programs... # INSTALL_BIN = $(INSTALL) -c -m 555 @INSTALL_STRIP@ INSTALL_DATA = $(INSTALL) -c -m 444 INSTALL_DIR = $(INSTALL) -d INSTALL_MAN = $(INSTALL) -c -m 444 # # Directories... # BUILDROOT = $(DSTROOT)$(RPM_BUILD_ROOT)$(DESTDIR) bindir = @bindir@ datadir = @datadir@ datarootdir = @datarootdir@ exec_prefix = @exec_prefix@ includedir = @includedir@ infodir = @infodir@ libdir = @libdir@ libexecdir = @libexecdir@ localstatedir = @localstatedir@ mandir = @mandir@ oldincludedir = @oldincludedir@ prefix = @prefix@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ top_srcdir = @top_srcdir@ # # Program options... # # OPTIM defines the common compiler optimization/debugging options. # ARFLAGS = @ARFLAGS@ CFLAGS = -I.. @CFLAGS@ @LARGEFILE@ $(OPTIM) @JPEGINC@ @PNGINC@ @ZLIBINC@ CPPFLAGS = @CPPFLAGS@ CXXFLAGS = -I.. @CXXFLAGS@ @LARGEFILE@ $(OPTIM) @JPEGINC@ @PNGINC@ @ZLIBINC@ LDFLAGS = @LDFLAGS@ $(OPTIM) LIBS = @SSLLIBS@ @LIBS@ OPTIM = @OPTIM@ @SSLFLAGS@ # # Rules... # .SILENT: .SUFFIXES: .a .c .cxx .h .o .c.o: echo Compiling $<... $(CC) $(CPPFLAGS) $(CFLAGS) -c $< .cxx.o: echo Compiling $<... $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $< htmldoc-1.9.7/Makefile.in000066400000000000000000000036571354715574200152570ustar00rootroot00000000000000# # Makefile for HTMLDOC, an HTML document processing program. # # Copyright 2011-2019 by Michael R Sweet. # Copyright 1997-2010 by Easy Software Products. # # This program is free software. Distribution and use rights are outlined in # the file "COPYING". # # # Include common definitions... # include Makedefs # # Subdirectories... # DIRS = @JPEG@ @ZLIB@ @PNG@ htmldoc doc INSTALLDIRS = fonts data desktop doc htmldoc # # Make all targets... # all: for dir in $(DIRS); do\ echo Making all in $$dir...;\ (cd $$dir; $(MAKE) -$(MAKEFLAGS)) || exit 1;\ done # # Remove object and target files... # clean: for dir in $(DIRS); do\ echo Cleaning in $$dir...;\ (cd $$dir; $(MAKE) -$(MAKEFLAGS) clean) || exit 1;\ done # # Clean everything # distclean: clean $(RM) -r autom4te*.cache $(RM) config.h $(RM) config.log $(RM) config.status $(RM) desktop/htmldoc.dt $(RM) desktop/htmldoc.plist $(RM) Makedefs $(RM) Makefile # # Install object and target files... # install: $(MAKE) all for dir in $(INSTALLDIRS); do\ echo Installing in $$dir...;\ (cd $$dir; $(MAKE) -$(MAKEFLAGS) install) || exit 1;\ done # # Sign the HTMLDOC application bundle and make a disk image... Set the # APPLEID and TEAMID environment variables from the Apple developer pages. # IDENTITY = "Developer ID Application" VERSION = @SVERSION@ dmg: echo Signing HTMLDOC application bundle codesign -s $(IDENTITY) --timestamp htmldoc/htmldoc.app echo Creating archive for notarization rm -f htmldoc/htmldoc.zip ditto -c -k --keepParent htmldoc/htmldoc.app htmldoc/htmldoc.zip echo Notarizing application xcrun altool --notarize-app -f htmldoc/htmldoc.zip \ --primary-bundle-id org.msweet.htmldoc \ --username "$(APPLEID)" \ --password "@keychain:AC_PASSWORD" \ --asc-provider "$(TEAMID)" echo Making disk image rm -f ~/Desktop/htmldoc-$(VERSION)-macos.dmg dmgbuild -s dmgbuild.py "HTMLDOC $(VERSION)" ~/Desktop/htmldoc-$(VERSION)-macos.dmg htmldoc-1.9.7/README.md000066400000000000000000000115351354715574200144630ustar00rootroot00000000000000Introduction ------------ HTMLDOC is a program that reads HTML and Markdown source files or web pages and generates corresponding EPUB, HTML, PostScript, or PDF files with an optional table of contents. HTMLDOC was developed in the 1990's as a documentation generator for my previous company, and has since seen a lot of usage as a report generator embedded in web servers. However, it does not support many things in "the modern web", such as: - Cascading Style Sheets (CSS): While I have experimented with adding CSS support to HTMLDOC, proper CSS support is non-trivial especially for paged output (which is not well supported by CSS) - Encryption: HTMLDOC currently supports the older (and very insecure) PDF 1.4 (128-bit RC4) encryption. I have looked at supporting AES (256-bit) encryption, however it is not widely supported and there are incompatible changes in PDF 2.0, so it is unlikely to be added to HTMLDOC. - Forms: HTML forms and PDF forms are very different things. While I have had many requests to add support for PDF forms over the years, I have not found a satisfactory way to do so. - Tables: HTMLDOC supports HTML 3.2 tables with basic support for TBODY and THEAD. - Unicode: While HTMLDOC does support UTF-8 for "Western" languages, there is absolutely no support for languages that require dynamic rewriting or right-to-left text formatting. Basically this means you can't use HTMLDOC to format Arabic, Chinese, Hebrew, Japanese, or other languages that are not based on latin-based alphabets that read left-to-right. - Emoji: The fonts bundled with HTMLDOC do not include Unicode Emoji characters. Resources --------- The following HTMLDOC resources are available online: - Official web site and online documentation: https://www.msweet.org/htmldoc - Issue tracker and questions: https://github.com/michaelrsweet/htmldoc/issues Using HTMLDOC ------------- Note: Complete documentation for HTMLDOC is available in the "doc" subdirectory. The following provides basic information on using HTMLDOC at the command-line and does not discuss the GUI or web server functionality. HTMLDOC accepts a list of HTML and/or Markdown "source" files and will generate EPUB, HTML, PostScript, or PDF output via command-line options. A summary of command-line options can be shown with the "--help" option: htmldoc --help HTMLDOC normally expects "structured" documents, with chapters, etc. Chapters begin with a H1 markup and continue to the end of the listed HTML files or the next H1 markup, whichever comes first. To convert unstructured documents such as web pages, use the "--webpage" option to HTMLDOC: htmldoc --webpage ... To generate a Level 2 PostScript file you might use: htmldoc -f outfile.ps chapter1.html ... chapterN.html Similarly you can generate an EPUB or PDF file of the same source files using: htmldoc -f outfile.epub chapter1.html ... chapterN.html htmldoc -f outfile.pdf chapter1.html ... chapterN.html Finally, to generate HTML files for viewing (with a linked table-of-contents) do the following: htmldoc -t html -d outdir chapter1.html ... chapterN.html or: htmldoc -t html -f outfile.html chapter1.html ... chapterN.html A complete description of all command-line options and HTML guidelines can be found in the software users manual in the "doc" directory. Credits ------- Many thanks to Leonard Rosenthol for providing the original changes to support a macOS (9) version of HTMLDOC. The original table VALIGN and "HALF PAGE" code was contributed by D. Richard Hipp. The original multiple header/footer image code was contributed by Lynn Pye. The RC4 encryption code is from librc4 1.1 by the folks at Carnegie Mellon University. The MD5 hash code is from L. Peter Deutsch at Aladdin Enterprises (creators of Ghostscript, among other things). Legal Stuff ----------- HTMLDOC is copyright © 1997-2019 by Michael R Sweet. This program is free software. Distribution and use rights are outlined in the file "COPYING". HTMLDOC includes code to encrypt PDF document files using the RC4 algorithm with up to a 128-bit key. While this software and code may be freely used and exported under current US laws, other countries may restrict your use and possession of this code and software. The Adobe Portable Document Format is Copyright 1985-2005 by Adobe Systems Incorporated. Adobe, FrameMaker, and PostScript are registered trademarks of Adobe Systems, Incorporated. The Graphics Interchange Format is the copyright and GIF is the service mark property of CompuServe Incorporated. Linux is a registered trademark of Linus Torvalds. macOS is a registered trademark of Apple Inc. Microsoft and Windows are registered trademarks of Microsoft Corporation. UNIX is a registered trademark of the X/Open Company, Ltd. This software is based in part on the work of the Independent JPEG Group and FLTK project. htmldoc-1.9.7/SNAPCRAFT.md000066400000000000000000000004771354715574200150520ustar00rootroot00000000000000# Building HTMLDOC Snaps Support for building HTMLDOC as a "snap" package can be found in the "snap" directory. In fact, every push to the Github repository triggers builds through the Snapcraft buildbot, and the resulting snaps can be installed using the "--edge" option, e.g.: sudo snap install --edge htmldoc htmldoc-1.9.7/cgi-bin/000077500000000000000000000000001354715574200145075ustar00rootroot00000000000000htmldoc-1.9.7/cgi-bin/htmldoc.java000066400000000000000000000055231354715574200170110ustar00rootroot00000000000000// // "$Id$" // // Java interface to HTMLDOC. // // Copyright 2011 by Michael R Sweet // Copyright 2001 by Easy Software Products. // // This program is free software. Distribution and use rights are outlined in // the file "COPYING.txt". // class htmldoc { // Convert named file to PDF on stdout... public static int topdf(String filename)// I - Name of file to convert { String command; // Command string Process process; // Process for HTMLDOC Runtime runtime; // Local runtime object java.io.InputStream input; // Output from HTMLDOC byte buffer []; // Buffer for output data int bytes; // Number of bytes // First tell the client that we will be sending PDF... System.out.print("Content-type: application/pdf\n\n"); // Construct the command string command = "htmldoc --quiet --jpeg --webpage -t pdf --left 36 " + "--header .t. --footer .1. " + filename; // Run the process and wait for it to complete... runtime = Runtime.getRuntime(); try { // Create a new HTMLDOC process... process = runtime.exec(command); // Get stdout from the process and a buffer for the data... input = process.getInputStream(); buffer = new byte[8192]; // Read output from HTMLDOC until we have it all... while ((bytes = input.read(buffer)) > 0) System.out.write(buffer, 0, bytes); // Return the exit status from HTMLDOC... return (process.waitFor()); } catch (Exception e) { // An error occurred - send it to stderr for the web server... System.err.print(e.toString() + " caught while running:\n\n"); System.err.print(" " + command + "\n"); return (1); } } // Main entry for htmldoc class public static void main(String[] args)// I - Command-line args { String server_name, // SERVER_NAME env var server_port, // SERVER_PORT env var path_info, // PATH_INFO env var query_string, // QUERY_STRING env var filename; // File to convert if ((server_name = System.getProperty("SERVER_NAME")) != null && (server_port = System.getProperty("SERVER_PORT")) != null && (path_info = System.getProperty("PATH_INFO")) != null) { // Construct a URL for the resource specified... filename = "http://" + server_name + ":" + server_port + path_info; if ((query_string = System.getProperty("QUERY_STRING")) != null) { filename = filename + "?" + query_string; } } else if (args.length == 1) { // Pull the filename from the command-line... filename = args[0]; } else { // Error - no args or env variables! System.err.print("Usage: htmldoc.class filename\n"); return; } // Convert the file to PDF and send to the web client... topdf(filename); } } // // End of "$Id$". // htmldoc-1.9.7/cgi-bin/topdf000066400000000000000000000010131354715574200155410ustar00rootroot00000000000000#!/bin/sh # # Sample "portal" script to convert the named HTML file to PDF on-the-fly. # # Usage: http://www.domain.com/path/topdf/path/filename.html # # # The "options" variable contains any options you want to pass to HTMLDOC. # options="-t pdf --quiet --jpeg --webpage --header .t. --footer .1." # # Tell the browser to expect a PDF file... # echo "Content-Type: application/pdf" echo "" # # Run HTMLDOC to generate the PDF file... # htmldoc $options http://${SERVER_NAME}:${SERVER_PORT}${PATH_INFO}?$QUERY_STRING htmldoc-1.9.7/cgi-bin/topdf.c000066400000000000000000000010161354715574200157650ustar00rootroot00000000000000#include #include /* topdf() - convert a HTML file to PDF */ FILE *topdf(const char *filename) /* HTML file to convert */ { char command[1024]; /* Command to execute */ puts("Content-Type: application/pdf\n"); sprintf(command, "htmldoc -t pdf --webpage %s", filename); return (popen(command, "w")); } /* topdf2() - pipe HTML output to HTMLDOC for conversion to PDF */ FILE *topdf2(void) { puts("Content-Type: application/pdf\n"); return (popen("htmldoc -t pdf --webpage -", "w")); } htmldoc-1.9.7/cgi-bin/topdf.php000066400000000000000000000030101354715574200163260ustar00rootroot00000000000000Bad URL\n" ."

Bad URL

\n", ."

The URL $url is bad.

\n" ."\n"); } else { topdf($url); } ?> htmldoc-1.9.7/cgi-bin/topdf.pl000066400000000000000000000005571354715574200161670ustar00rootroot00000000000000sub topdf(filename); sub topdf { # Get the filename argument... my $filename = shift; # Make stdout unbuffered... select(STDOUT); $| = 1; # Write the content type to the client... print "Content-Type: application/pdf\n\n"; # Run HTMLDOC to provide the PDF file to the user... system "htmldoc -t pdf --quiet --webpage $filename"; } htmldoc-1.9.7/config.h.in000066400000000000000000000076551354715574200152370ustar00rootroot00000000000000/* * Configuration file for HTMLDOC. * * Copyright 2011-2017 by Michael R Sweet. * Copyright 1997-2010 by Easy Software Products. All rights reserved. * * This program is free software. Distribution and use rights are outlined in * the file "COPYING". */ /* * What is the version number for this software? */ #define SVERSION "1.8.30" /* * Limits for the output "engines"... */ #define MAX_CHAPTERS 1000 /* Maximum number of chapters or files */ #define MAX_COLUMNS 200 /* Maximum number of columns in a table */ #define MAX_HF_IMAGES 10 /* Maximum number of header/footer images */ /* * Memory allocation units for other stuff... */ #define ALLOC_FILES 10 /* Temporary/image files */ #define ALLOC_HEADINGS 50 /* Headings */ #define ALLOC_LINKS 100 /* Web links */ #define ALLOC_OBJECTS 100 /* PDF objects */ #define ALLOC_PAGES 10 /* PS/PDF pages */ #define ALLOC_ROWS 20 /* Table rows */ /* * Locations of files... */ #define DOCUMENTATION "/usr/share/doc/htmldoc" #define HTML_DATA "/usr/share/htmldoc" /* * Do we have the FLTK library? */ #undef HAVE_LIBFLTK /* * Do we have the Xpm library? */ #undef HAVE_LIBXPM /* * Which encryption libraries do we have? */ #undef HAVE_CDSASSL #undef HAVE_GNUTLS #undef HAVE_SSPISSL #undef HAVE_SSL /* * Do we have the gnutls_transport_set_pull_timeout_function function? */ #undef HAVE_GNUTLS_TRANSPORT_SET_PULL_TIMEOUT_FUNCTION /* * Do we have the gnutls_priority_set_direct function? */ #undef HAVE_GNUTLS_PRIORITY_SET_DIRECT /* * What Security framework headers do we have? */ #undef HAVE_AUTHORIZATION_H #undef HAVE_SECBASEPRIV_H #undef HAVE_SECCERTIFICATE_H #undef HAVE_SECIDENTITYSEARCHPRIV_H #undef HAVE_SECITEM_H #undef HAVE_SECITEMPRIV_H #undef HAVE_SECPOLICY_H #undef HAVE_SECPOLICYPRIV_H #undef HAVE_SECURETRANSPORTPRIV_H /* * Do we have the cssmErrorString function? */ #undef HAVE_CSSMERRORSTRING /* * Do we have the SecGenerateSelfSignedCertificate function? */ #undef HAVE_SECGENERATESELFSIGNEDCERTIFICATE /* * Do we have the SecKeychainOpen function? */ #undef HAVE_SECKEYCHAINOPEN /* * Do we have (a working) SSLSetEnabledCiphers function? */ #undef HAVE_SSLSETENABLEDCIPHERS /* * Do we need to use ? */ #undef HAVE_STRINGS_H /* * Do we have the header file? */ #undef HAVE_LOCALE_H /* * Do we have some of the "standard" string functions? */ #undef HAVE_STRDUP #undef HAVE_STRCASECMP #undef HAVE_STRNCASECMP #undef HAVE_STRLCAT #undef HAVE_STRLCPY /* * How about snprintf() and vsnprintf()? */ #undef HAVE_SNPRINTF #undef HAVE_VSNPRINTF /* * Does the "tm" structure contain the "tm_gmtoff" member? */ #undef HAVE_TM_GMTOFF /* * Which random number generator function to use... */ #undef HAVE_ARC4RANDOM #undef HAVE_RANDOM #undef HAVE_LRAND48 #ifdef HAVE_ARC4RANDOM # define HTMLDOC_RAND() arc4random() # define HTMLDOC_SRAND(v) #elif defined(HAVE_RANDOM) # define HTMLDOC_RAND() random() # define HTMLDOC_SRAND(v) srandom(v) #elif defined(HAVE_LRAND48) # define HTMLDOC_RAND() lrand48() # define HTMLDOC_SRAND(v) srand48(v) #else # define HTMLDOC_RAND() rand() # define HTMLDOC_SRAND(v) srand(v) #endif /* HAVE_ARC4RANDOM */ /* * Do we have hstrerror()? */ #undef HAVE_HSTRERROR /* * Do we have getaddrinfo()? */ #undef HAVE_GETADDRINFO /* * Do we have getnameinfo()? */ #undef HAVE_GETNAMEINFO /* * Do we have the header file and/or res_init()? */ #undef HAVE_RESOLV_H #undef HAVE_RES_INIT /* * Do we have poll()? */ #undef HAVE_POLL /* * Do we have the long long type? */ #undef HAVE_LONG_LONG #ifdef HAVE_LONG_LONG # define HTMLDOC_LLFMT "%lld" # define HTMLDOC_LLCAST (long long) #else # define HTMLDOC_LLFMT "%ld" # define HTMLDOC_LLCAST (long) #endif /* HAVE_LONG_LONG */ /* * Do we have the strtoll() function? */ #undef HAVE_STRTOLL #ifndef HAVE_STRTOLL # define strtoll(nptr,endptr,base) strtol((nptr), (endptr), (base)) #endif /* !HAVE_STRTOLL */ htmldoc-1.9.7/configure000077500000000000000000006037311354715574200151200ustar00rootroot00000000000000#! /bin/sh # Guess values for system-dependent variables and create Makefiles. # Generated by GNU Autoconf 2.69 for HTMLDOC 1.9.7. # # Report bugs to . # # # Copyright (C) 1992-1996, 1998-2012 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 more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi as_nl=' ' export as_nl # Printing a long string crashes Solaris 7 /usr/bin/printf. as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo # Prefer a ksh shell builtin over an external printf program on Solaris, # but without wasting forks for bash or zsh. if test -z "$BASH_VERSION$ZSH_VERSION" \ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='print -r --' as_echo_n='print -rn --' elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='printf %s\n' as_echo_n='printf %s' else if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' as_echo_n='/usr/ucb/echo -n' else as_echo_body='eval expr "X$1" : "X\\(.*\\)"' as_echo_n_body='eval arg=$1; case $arg in #( *"$as_nl"*) expr "X$arg" : "X\\(.*\\)$as_nl"; arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; esac; expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" ' export as_echo_n_body as_echo_n='sh -c $as_echo_n_body as_echo' fi export as_echo_body as_echo='sh -c $as_echo_body as_echo' fi # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || PATH_SEPARATOR=';' } fi # IFS # We need space, tab and new line, in precisely that order. Quoting is # there to prevent editors from complaining about space-tab. # (If _AS_PATH_WALK were called with IFS unset, it would disable word # splitting by setting IFS to empty value.) IFS=" "" $as_nl" # Find who we are. Look in the path if we contain no directory separator. as_myself= 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 IFS=$as_save_IFS ;; 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 $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi # Unset variables that we do not need and which cause bugs (e.g. in # pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" # suppresses any "Segmentation fault" message there. '((' could # trigger a bug in pdksh 5.2.14. for as_var in BASH_ENV ENV MAIL MAILPATH do eval test x\${$as_var+set} = xset \ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done PS1='$ ' PS2='> ' PS4='+ ' # NLS nuisances. LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE # CDPATH. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH # Use a proper internal environment variable to ensure we don't fall # into an infinite loop, continuously re-executing ourselves. if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then _as_can_reexec=no; export _as_can_reexec; # We cannot yet assume a decent shell, so we have to provide a # neutralization value for shells without unset; and this also # works around shells that cannot unset nonexistent variables. # Preserve -v and -x to the replacement shell. BASH_ENV=/dev/null ENV=/dev/null (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV case $- in # (((( *v*x* | *x*v* ) as_opts=-vx ;; *v* ) as_opts=-v ;; *x* ) as_opts=-x ;; * ) as_opts= ;; esac exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} # Admittedly, this is quite paranoid, since all the known shells bail # out after a failed `exec'. $as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 as_fn_exit 255 fi # We don't want this to propagate to other subprocesses. { _as_can_reexec=; unset _as_can_reexec;} if test "x$CONFIG_SHELL" = x; then as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which # is contrary to our usage. Disable this feature. alias -g '\${1+\"\$@\"}'='\"\$@\"' setopt NO_GLOB_SUBST else case \`(set -o) 2>/dev/null\` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi " as_required="as_fn_return () { (exit \$1); } as_fn_success () { as_fn_return 0; } as_fn_failure () { as_fn_return 1; } as_fn_ret_success () { return 0; } as_fn_ret_failure () { return 1; } exitcode=0 as_fn_success || { exitcode=1; echo as_fn_success failed.; } as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; } as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; } as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; } if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then : else exitcode=1; echo positional parameters were not saved. fi test x\$exitcode = x0 || exit 1 test -x / || exit 1" as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1 test \$(( 1 + 1 )) = 2 || exit 1" if (eval "$as_required") 2>/dev/null; then : as_have_required=yes else as_have_required=no fi if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then : else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR as_found=false for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. as_found=: case $as_dir in #( /*) for as_base in sh bash ksh sh5; do # Try only shells that exist, to save several forks. as_shell=$as_dir/$as_base if { test -f "$as_shell" || test -f "$as_shell.exe"; } && { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then : CONFIG_SHELL=$as_shell as_have_required=yes if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then : break 2 fi fi done;; esac as_found=false done $as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } && { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then : CONFIG_SHELL=$SHELL as_have_required=yes fi; } IFS=$as_save_IFS if test "x$CONFIG_SHELL" != x; then : export CONFIG_SHELL # We cannot yet assume a decent shell, so we have to provide a # neutralization value for shells without unset; and this also # works around shells that cannot unset nonexistent variables. # Preserve -v and -x to the replacement shell. BASH_ENV=/dev/null ENV=/dev/null (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV case $- in # (((( *v*x* | *x*v* ) as_opts=-vx ;; *v* ) as_opts=-v ;; *x* ) as_opts=-x ;; * ) as_opts= ;; esac exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} # Admittedly, this is quite paranoid, since all the known shells bail # out after a failed `exec'. $as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 exit 255 fi if test x$as_have_required = xno; then : $as_echo "$0: This script requires a shell more modern than all" $as_echo "$0: the shells that I found on your system." if test x${ZSH_VERSION+set} = xset ; then $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should" $as_echo "$0: be upgraded to zsh 4.3.4 or later." else $as_echo "$0: Please tell bug-autoconf@gnu.org and $0: https://github.com/michaelrsweet/htmldoc/issues about $0: your system, including any error possibly output before $0: this message. Then install a modern shell, or manually $0: run the script under such a shell if you do have one." fi exit 1 fi fi fi SHELL=${CONFIG_SHELL-/bin/sh} export SHELL # Unset more variables known to interfere with behavior of common tools. CLICOLOR_FORCE= GREP_OPTIONS= unset CLICOLOR_FORCE GREP_OPTIONS ## --------------------- ## ## M4sh Shell Functions. ## ## --------------------- ## # as_fn_unset VAR # --------------- # Portably unset VAR. as_fn_unset () { { eval $1=; unset $1;} } as_unset=as_fn_unset # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. as_fn_set_status () { return $1 } # as_fn_set_status # as_fn_exit STATUS # ----------------- # Exit the shell with STATUS, even in a "trap 0" or "set -e" context. as_fn_exit () { set +e as_fn_set_status $1 exit $1 } # as_fn_exit # as_fn_mkdir_p # ------------- # Create "$as_dir" as a directory, including parents if necessary. as_fn_mkdir_p () { case $as_dir in #( -*) as_dir=./$as_dir;; esac test -d "$as_dir" || eval $as_mkdir_p || { as_dirs= while :; do case $as_dir in #( *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" as_dir=`$as_dirname -- "$as_dir" || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` test -d "$as_dir" && break done test -z "$as_dirs" || eval "mkdir $as_dirs" } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" } # as_fn_mkdir_p # as_fn_executable_p FILE # ----------------------- # Test if FILE is an executable regular file. as_fn_executable_p () { test -f "$1" && test -x "$1" } # as_fn_executable_p # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : eval 'as_fn_append () { eval $1+=\$2 }' else as_fn_append () { eval $1=\$$1\$2 } fi # as_fn_append # as_fn_arith ARG... # ------------------ # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : eval 'as_fn_arith () { as_val=$(( $* )) }' else as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` } fi # as_fn_arith # as_fn_error STATUS ERROR [LINENO LOG_FD] # ---------------------------------------- # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are # provided, also output the error to LOG_FD, referencing LINENO. Then exit the # script with STATUS, using 1 if that was 0. as_fn_error () { as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi $as_echo "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; 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 if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then as_dirname=dirname else as_dirname=false fi as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || $as_echo X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` # 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 as_lineno_1=$LINENO as_lineno_1a=$LINENO as_lineno_2=$LINENO as_lineno_2a=$LINENO eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" && test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || { # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-) sed -n ' p /[$]LINENO/= ' <$as_myself | sed ' s/[$]LINENO.*/&-/ t lineno b :lineno N :loop s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ t loop s/-\n.*// ' >$as_me.lineno && chmod +x "$as_me.lineno" || { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } # If we had to re-execute with $CONFIG_SHELL, we're ensured to have # already done that, so ensure we don't try to do so again and fall # in an infinite loop. This has already happened in practice. _as_can_reexec=no; export _as_can_reexec # 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 sensitive to this). . "./$as_me.lineno" # Exit status is that of the last command. exit } ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) case `echo 'xy\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. xy) ECHO_C='\c';; *) echo `echo ksh88 bug on AIX 6.1` > /dev/null ECHO_T=' ';; esac;; *) ECHO_N='-n';; esac rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file else rm -f conf$$.dir mkdir conf$$.dir 2>/dev/null fi if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. # In both cases, we have to default to `cp -pR'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -pR' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -pR' fi else as_ln_s='cp -pR' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null if mkdir -p . 2>/dev/null; then as_mkdir_p='mkdir -p "$as_dir"' else test -d ./-p && rmdir ./-p as_mkdir_p=false fi as_test_x='test -x' as_executable_p=as_fn_executable_p # 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'" test -n "$DJDIR" || exec 7<&0 &1 # Name of the host. # hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status, # so uname gets run too. ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` # # Initializations. # ac_default_prefix=/usr/local ac_clean_files= ac_config_libobj_dir=. LIBOBJS= cross_compiling=no subdirs= MFLAGS= MAKEFLAGS= # Identity of this package. PACKAGE_NAME='HTMLDOC' PACKAGE_TARNAME='htmldoc' PACKAGE_VERSION='1.9.7' PACKAGE_STRING='HTMLDOC 1.9.7' PACKAGE_BUGREPORT='https://github.com/michaelrsweet/htmldoc/issues' PACKAGE_URL='https://michaelrsweet.github.io/htmldoc' # Factoring default headers for most tests. ac_includes_default="\ #include #ifdef HAVE_SYS_TYPES_H # include #endif #ifdef HAVE_SYS_STAT_H # include #endif #ifdef STDC_HEADERS # include # include #else # ifdef HAVE_STDLIB_H # include # endif #endif #ifdef HAVE_STRING_H # if !defined STDC_HEADERS && defined HAVE_MEMORY_H # include # endif # include #endif #ifdef HAVE_STRINGS_H # include #endif #ifdef HAVE_INTTYPES_H # include #endif #ifdef HAVE_STDINT_H # include #endif #ifdef HAVE_UNISTD_H # include #endif" ac_subst_vars='LTLIBOBJS LIBOBJS ZLIBINC ZLIB PNGINC PNG JPEGINC JPEG POST SSLLIBS SSLFLAGS LIBGCRYPTCONFIG LIBGNUTLSCONFIG LARGEFILE EGREP GREP ARFLAGS PKGCONFIG RM MKDIR MV INSTALL FLTKCONFIG CP CHMOD AR RANLIB CPP ac_ct_CXX CXXFLAGS CXX OBJEXT EXEEXT ac_ct_CC CPPFLAGS LDFLAGS CFLAGS CC AWK OPTIM INSTALL_STRIP SVERSION target_alias host_alias build_alias LIBS ECHO_T ECHO_N ECHO_C DEFS mandir localedir libdir psdir pdfdir dvidir htmldir infodir docdir oldincludedir includedir localstatedir sharedstatedir sysconfdir datadir datarootdir libexecdir sbindir bindir program_transform_name prefix exec_prefix PACKAGE_URL PACKAGE_BUGREPORT PACKAGE_STRING PACKAGE_VERSION PACKAGE_TARNAME PACKAGE_NAME PATH_SEPARATOR SHELL' ac_subst_files='' ac_user_opts=' enable_option_checking enable_debug with_gui enable_largefile enable_ssl enable_gnutls enable_cdsassl enable_localjpeg enable_localzlib enable_localpng enable_sanitizer ' ac_precious_vars='build_alias host_alias target_alias CC CFLAGS LDFLAGS LIBS CPPFLAGS CXX CXXFLAGS CCC CPP' # Initialize some variables set by options. ac_init_help= ac_init_version=false ac_unrecognized_opts= ac_unrecognized_sep= # 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. # (The list follows the same order as the GNU Coding Standards.) bindir='${exec_prefix}/bin' sbindir='${exec_prefix}/sbin' libexecdir='${exec_prefix}/libexec' datarootdir='${prefix}/share' datadir='${datarootdir}' sysconfdir='${prefix}/etc' sharedstatedir='${prefix}/com' localstatedir='${prefix}/var' includedir='${prefix}/include' oldincludedir='/usr/include' docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' infodir='${datarootdir}/info' htmldir='${docdir}' dvidir='${docdir}' pdfdir='${docdir}' psdir='${docdir}' libdir='${exec_prefix}/lib' localedir='${datarootdir}/locale' mandir='${datarootdir}/man' ac_prev= ac_dashdash= 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 case $ac_option in *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; *=) ac_optarg= ;; *) ac_optarg=yes ;; esac # Accept the important Cygnus configure options, so we can diagnose typos. case $ac_dashdash$ac_option in --) ac_dashdash=yes ;; -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) ac_prev=datadir ;; -datadir=* | --datadir=* | --datadi=* | --datad=*) datadir=$ac_optarg ;; -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \ | --dataroo | --dataro | --datar) ac_prev=datarootdir ;; -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \ | --dataroot=* | --dataroo=* | --dataro=* | --datar=*) datarootdir=$ac_optarg ;; -disable-* | --disable-*) ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid feature name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval enable_$ac_useropt=no ;; -docdir | --docdir | --docdi | --doc | --do) ac_prev=docdir ;; -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*) docdir=$ac_optarg ;; -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv) ac_prev=dvidir ;; -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*) dvidir=$ac_optarg ;; -enable-* | --enable-*) ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid feature name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval enable_$ac_useropt=\$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 ;; -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht) ac_prev=htmldir ;; -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \ | --ht=*) htmldir=$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 ;; -localedir | --localedir | --localedi | --localed | --locale) ac_prev=localedir ;; -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*) localedir=$ac_optarg ;; -localstatedir | --localstatedir | --localstatedi | --localstated \ | --localstate | --localstat | --localsta | --localst | --locals) ac_prev=localstatedir ;; -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*) 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 ;; -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd) ac_prev=pdfdir ;; -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*) pdfdir=$ac_optarg ;; -psdir | --psdir | --psdi | --psd | --ps) ac_prev=psdir ;; -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) psdir=$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_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid package name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval with_$ac_useropt=\$ac_optarg ;; -without-* | --without-*) ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid package name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval with_$ac_useropt=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 ;; -*) as_fn_error $? "unrecognized option: \`$ac_option' Try \`$0 --help' for more information" ;; *=*) ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` # Reject names that are not valid shell variable names. case $ac_envvar in #( '' | [0-9]* | *[!_$as_cr_alnum]* ) as_fn_error $? "invalid variable name: \`$ac_envvar'" ;; esac eval $ac_envvar=\$ac_optarg export $ac_envvar ;; *) # FIXME: should be removed in autoconf 3.0. $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2 expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && $as_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'` as_fn_error $? "missing argument to $ac_option" fi if test -n "$ac_unrecognized_opts"; then case $enable_option_checking in no) ;; fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;; *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; esac fi # Check all directory arguments for consistency. for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ datadir sysconfdir sharedstatedir localstatedir includedir \ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ libdir localedir mandir do eval ac_val=\$$ac_var # Remove trailing slashes. case $ac_val in */ ) ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'` eval $ac_var=\$ac_val;; esac # Be sure to have absolute directory names. case $ac_val in [\\/$]* | ?:[\\/]* ) continue;; NONE | '' ) case $ac_var in *prefix ) continue;; esac;; esac as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val" 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 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 ac_pwd=`pwd` && test -n "$ac_pwd" && ac_ls_di=`ls -di .` && ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || as_fn_error $? "working directory cannot be determined" test "X$ac_ls_di" = "X$ac_pwd_ls_di" || as_fn_error $? "pwd does not report name of working directory" # 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 the parent directory. ac_confdir=`$as_dirname -- "$as_myself" || $as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_myself" : 'X\(//\)[^/]' \| \ X"$as_myself" : 'X\(//\)$' \| \ X"$as_myself" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_myself" | 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 test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir" fi ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" ac_abs_confdir=`( cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg" pwd)` # When building in place, set srcdir=. if test "$ac_abs_confdir" = "$ac_pwd"; then srcdir=. fi # Remove unnecessary trailing slashes from srcdir. # Double slashes in file names in object file debugging info # mess up M-x gdb in Emacs. case $srcdir in */) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;; esac for ac_var in $ac_precious_vars; do eval ac_env_${ac_var}_set=\${${ac_var}+set} eval ac_env_${ac_var}_value=\$${ac_var} eval ac_cv_env_${ac_var}_set=\${${ac_var}+set} eval ac_cv_env_${ac_var}_value=\$${ac_var} done # # 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 HTMLDOC 1.9.7 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 \`..'] 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] --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] --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] --datadir=DIR read-only architecture-independent data [DATAROOTDIR] --infodir=DIR info documentation [DATAROOTDIR/info] --localedir=DIR locale-dependent data [DATAROOTDIR/locale] --mandir=DIR man documentation [DATAROOTDIR/man] --docdir=DIR documentation root [DATAROOTDIR/doc/htmldoc] --htmldir=DIR html documentation [DOCDIR] --dvidir=DIR dvi documentation [DOCDIR] --pdfdir=DIR pdf documentation [DOCDIR] --psdir=DIR ps documentation [DOCDIR] _ACEOF cat <<\_ACEOF _ACEOF fi if test -n "$ac_init_help"; then case $ac_init_help in short | recursive ) echo "Configuration of HTMLDOC 1.9.7:";; esac cat <<\_ACEOF Optional Features: --disable-option-checking ignore unrecognized --enable/--with options --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) --enable-FEATURE[=ARG] include FEATURE [ARG=yes] --enable-debug turn on debugging, default=no --disable-largefile omit support for large files --enable-ssl turn on SSL/TLS support, default=yes --enable-gnutls use GNU TLS for SSL/TLS support, default=yes --enable-cdsassl use CDSA for SSL/TLS support, default=yes --enable-localjpeg use local JPEG library, default=auto --enable-localzlib use local ZLIB library, default=auto --enable-localpng use local PNG library, default=auto --enable-sanitizer build with AddressSanitizer Optional Packages: --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) --without-gui do not compile the GUI version of HTMLDOC, default=yes 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 LIBS libraries to pass to the linker, e.g. -l CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I if you have headers in a nonstandard directory CXX C++ compiler command CXXFLAGS C++ compiler flags 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. Report bugs to . HTMLDOC home page: . _ACEOF ac_status=$? fi if test "$ac_init_help" = "recursive"; then # If there are subdirs, report their specific --help. for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue test -d "$ac_dir" || { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } || continue ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix cd "$ac_dir" || { ac_status=$?; continue; } # Check for guested 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 else $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 fi || ac_status=$? cd "$ac_pwd" || { ac_status=$?; break; } done fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF HTMLDOC configure 1.9.7 generated by GNU Autoconf 2.69 Copyright (C) 2012 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 fi ## ------------------------ ## ## Autoconf initialization. ## ## ------------------------ ## # ac_fn_c_try_compile LINENO # -------------------------- # Try to compile conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_compile # ac_fn_cxx_try_compile LINENO # ---------------------------- # Try to compile conftest.$ac_ext, and return whether this succeeded. ac_fn_cxx_try_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_cxx_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_cxx_try_compile # ac_fn_c_try_cpp LINENO # ---------------------- # Try to preprocess conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_cpp () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if { { ac_try="$ac_cpp conftest.$ac_ext" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } > conftest.i && { test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || test ! -s conftest.err }; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_cpp # ac_fn_c_try_run LINENO # ---------------------- # Try to link conftest.$ac_ext, and return whether this succeeded. Assumes # that executables *can* be run. ac_fn_c_try_run () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { ac_try='./conftest$ac_exeext' { { case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; }; then : ac_retval=0 else $as_echo "$as_me: program exited with status $ac_status" >&5 $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=$ac_status fi rm -rf conftest.dSYM conftest_ipa8_conftest.oo eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_run # ac_fn_c_check_header_mongrel LINENO HEADER VAR INCLUDES # ------------------------------------------------------- # Tests whether HEADER exists, giving a warning if it cannot be compiled using # the include files in INCLUDES and setting the cache variable VAR # accordingly. ac_fn_c_check_header_mongrel () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if eval \${$3+:} false; then : { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } else # Is the header compilable? { $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 usability" >&5 $as_echo_n "checking $2 usability... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 #include <$2> _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_header_compiler=yes else ac_header_compiler=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_compiler" >&5 $as_echo "$ac_header_compiler" >&6; } # Is the header present? { $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 presence" >&5 $as_echo_n "checking $2 presence... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include <$2> _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : ac_header_preproc=yes else ac_header_preproc=no fi rm -f conftest.err conftest.i conftest.$ac_ext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5 $as_echo "$ac_header_preproc" >&6; } # So? What about this header? case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in #(( yes:no: ) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&5 $as_echo "$as_me: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 $as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} ;; no:yes:* ) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: present but cannot be compiled" >&5 $as_echo "$as_me: WARNING: $2: present but cannot be compiled" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: check for missing prerequisite headers?" >&5 $as_echo "$as_me: WARNING: $2: check for missing prerequisite headers?" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: see the Autoconf documentation" >&5 $as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&5 $as_echo "$as_me: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 $as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} ( $as_echo "## -------------------------------------------------------------- ## ## Report this to https://github.com/michaelrsweet/htmldoc/issues ## ## -------------------------------------------------------------- ##" ) | sed "s/^/$as_me: WARNING: /" >&2 ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else eval "$3=\$ac_header_compiler" fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_header_mongrel # ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES # ------------------------------------------------------- # Tests whether HEADER exists and can be compiled using the include files in # INCLUDES, setting the cache variable VAR accordingly. ac_fn_c_check_header_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 #include <$2> _ACEOF if ac_fn_c_try_compile "$LINENO"; then : eval "$3=yes" else eval "$3=no" fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_header_compile # ac_fn_c_try_link LINENO # ----------------------- # Try to link conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_link () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext conftest$ac_exeext if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest$ac_exeext && { test "$cross_compiling" = yes || test -x conftest$ac_exeext }; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would # interfere with the next link command; also delete a directory that is # left behind by Apple's compiler. We do this before executing the actions. rm -rf conftest.dSYM conftest_ipa8_conftest.oo eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_link # ac_fn_c_check_func LINENO FUNC VAR # ---------------------------------- # Tests whether FUNC exists, setting the cache variable VAR accordingly ac_fn_c_check_func () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Define $2 to an innocuous variant, in case declares $2. For example, HP-UX 11i declares gettimeofday. */ #define $2 innocuous_$2 /* System header to define __stub macros and hopefully few prototypes, which can conflict with char $2 (); below. Prefer to if __STDC__ is defined, since exists even on freestanding compilers. */ #ifdef __STDC__ # include #else # include #endif #undef $2 /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char $2 (); /* 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_$2 || defined __stub___$2 choke me #endif int main () { return $2 (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : eval "$3=yes" else eval "$3=no" fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_func cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. It was created by HTMLDOC $as_me 1.9.7, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ _ACEOF exec 5>>config.log { 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` /usr/bin/hostinfo = `(/usr/bin/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=. $as_echo "PATH: $as_dir" done IFS=$as_save_IFS } >&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_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=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; esac case $ac_pass in 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;; 2) as_fn_append 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 as_fn_append ac_configure_args " '$ac_arg'" ;; esac done done { ac_configure_args0=; unset ac_configure_args0;} { ac_configure_args1=; unset 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: Use '\'' to represent an apostrophe within the trap. # WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. trap 'exit_status=$? # Save into config.log some information that might help in debugging. { echo $as_echo "## ---------------- ## ## Cache variables. ## ## ---------------- ##" echo # The following way of writing the cache mishandles newlines in values, ( for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #( *${as_nl}ac_space=\ *) sed -n \ "s/'\''/'\''\\\\'\'''\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p" ;; #( *) sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) echo $as_echo "## ----------------- ## ## Output variables. ## ## ----------------- ##" echo for ac_var in $ac_subst_vars do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac $as_echo "$ac_var='\''$ac_val'\''" done | sort echo if test -n "$ac_subst_files"; then $as_echo "## ------------------- ## ## File substitutions. ## ## ------------------- ##" echo for ac_var in $ac_subst_files do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac $as_echo "$ac_var='\''$ac_val'\''" done | sort echo fi if test -s confdefs.h; then $as_echo "## ----------- ## ## confdefs.h. ## ## ----------- ##" echo cat confdefs.h echo fi test "$ac_signal" != 0 && $as_echo "$as_me: caught signal $ac_signal" $as_echo "$as_me: exit $exit_status" } >&5 rm -f core *.core core.conftest.* && rm -f -r conftest* confdefs* conf$$* $ac_clean_files && exit $exit_status ' 0 for ac_signal in 1 2 13 15; do trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal done ac_signal=0 # confdefs.h avoids OS command line length limits that DEFS can exceed. rm -f -r conftest* confdefs.h $as_echo "/* confdefs.h */" > 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 cat >>confdefs.h <<_ACEOF #define PACKAGE_URL "$PACKAGE_URL" _ACEOF # Let the site file select an alternate cache file if it wants to. # Prefer an explicitly selected file to automatically selected ones. ac_site_file1=NONE ac_site_file2=NONE if test -n "$CONFIG_SITE"; then # We do not want a PATH search for config.site. case $CONFIG_SITE in #(( -*) ac_site_file1=./$CONFIG_SITE;; */*) ac_site_file1=$CONFIG_SITE;; *) ac_site_file1=./$CONFIG_SITE;; esac elif test "x$prefix" != xNONE; then ac_site_file1=$prefix/share/config.site ac_site_file2=$prefix/etc/config.site else ac_site_file1=$ac_default_prefix/share/config.site ac_site_file2=$ac_default_prefix/etc/config.site fi for ac_site_file in "$ac_site_file1" "$ac_site_file2" do test "x$ac_site_file" = xNONE && continue if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 $as_echo "$as_me: loading site script $ac_site_file" >&6;} sed 's/^/| /' "$ac_site_file" >&5 . "$ac_site_file" \ || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "failed to load site script $ac_site_file See \`config.log' for more details" "$LINENO" 5; } 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. DJGPP emulates it as a regular file. if test /dev/null != "$cache_file" && test -f "$cache_file"; then { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 $as_echo "$as_me: loading cache $cache_file" >&6;} case $cache_file in [\\/]* | ?:[\\/]* ) . "$cache_file";; *) . "./$cache_file";; esac fi else { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5 $as_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 $ac_precious_vars; 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,) { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 $as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} ac_cache_corrupted=: ;; ,set) { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5 $as_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 # differences in whitespace do not lead to failure. ac_old_val_w=`echo x $ac_old_val` ac_new_val_w=`echo x $ac_new_val` if test "$ac_old_val_w" != "$ac_new_val_w"; then { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5 $as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} ac_cache_corrupted=: else { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 $as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} eval $ac_var=\$ac_old_val fi { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5 $as_echo "$as_me: former value: \`$ac_old_val'" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5 $as_echo "$as_me: current value: \`$ac_new_val'" >&2;} fi;; esac # Pass precious variables to config.status. if test "$ac_new_set" = set; then case $ac_new_val in *\'*) ac_arg=$ac_var=`$as_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. *) as_fn_append ac_configure_args " '$ac_arg'" ;; esac fi done if $ac_cache_corrupted; then { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 $as_echo "$as_me: error: changes in the environment can compromise the build" >&2;} as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5 fi ## -------------------- ## ## Main body of script. ## ## -------------------- ## 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_config_headers="$ac_config_headers config.h" SVERSION="1.9.7" cat >>confdefs.h <<_ACEOF #define SVERSION "$SVERSION" _ACEOF uname=`uname` uversion=`uname -r | sed -e '1,$s/[^0-9]//g'` if test "$uname" = "IRIX64"; then uname="IRIX" fi INSTALL_STRIP="-s" OPTIM="${OPTIM:=}" CFLAGS="${CFLAGS:=}" CXXFLAGS="${CXXFLAGS:=}" LDFLAGS="${LDFLAGS:=}" # Check whether --enable-debug was given. if test "${enable_debug+set}" = set; then : enableval=$enable_debug; if eval "test x$enable_debug = xyes"; then INSTALL_STRIP="" OPTIM="-g " fi fi # Check whether --with-gui was given. if test "${with_gui+set}" = set; then : withval=$with_gui; fi for ac_prog in gawk mawk nawk awk do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_AWK+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$AWK"; then ac_cv_prog_AWK="$AWK" # 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_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_AWK="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi AWK=$ac_cv_prog_AWK if test -n "$AWK"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AWK" >&5 $as_echo "$AWK" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$AWK" && break done 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 for ac_prog in clang cc gcc 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 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&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_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="$ac_tool_prefix$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$CC" && break done fi if test -z "$CC"; then ac_ct_CC=$CC for ac_prog in clang cc gcc do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_CC+:} false; then : $as_echo_n "(cached) " >&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_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 $as_echo "$ac_ct_CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$ac_ct_CC" && break done if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi fi test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "no acceptable C compiler found in \$PATH See \`config.log' for more details" "$LINENO" 5; } # Provide some information about the compiler. $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 set X $ac_compile ac_compiler=$2 for ac_option in --version -v -V -qversion; do { { ac_try="$ac_compiler $ac_option >&5" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compiler $ac_option >&5") 2>conftest.err ac_status=$? if test -s conftest.err; then sed '10a\ ... rest of stderr output deleted ... 10q' conftest.err >conftest.er1 cat conftest.er1 >&5 fi rm -f conftest.er1 conftest.err $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } done cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files a.out a.out.dSYM 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. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5 $as_echo_n "checking whether the C compiler works... " >&6; } ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` # The possible output files: ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*" ac_rmfiles= for ac_file in $ac_files do case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; * ) ac_rmfiles="$ac_rmfiles $ac_file";; esac done rm -f $ac_rmfiles if { { ac_try="$ac_link_default" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link_default") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : # Autoconf-2.13 could set the ac_cv_exeext variable to `no'. # So ignore a value of `no', otherwise this would lead to `EXEEXT = no' # in a Makefile. We should not override ac_cv_exeext if it was cached, # so that the user can short-circuit this test for compilers unknown to # Autoconf. for ac_file in $ac_files '' do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; [ab].out ) # We found the default executable, but exeext='' is most # certainly right. break;; *.* ) if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no; then :; else ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` fi # We set ac_cv_exeext here because the later test for it is not # safe: cross compilers may not add the suffix if given an `-o' # argument, so we may need to know it at that point already. # Even if this section looks crufty: it has the advantage of # actually working. break;; * ) break;; esac done test "$ac_cv_exeext" = no && ac_cv_exeext= else ac_file='' fi if test -z "$ac_file"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "C compiler cannot create executables See \`config.log' for more details" "$LINENO" 5; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5 $as_echo_n "checking for C compiler default output file name... " >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 $as_echo "$ac_file" >&6; } ac_exeext=$ac_cv_exeext rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out ac_clean_files=$ac_clean_files_save { $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5 $as_echo_n "checking for suffix of executables... " >&6; } if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; 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 | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` break;; * ) break;; esac done else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of executables: cannot compile and link See \`config.log' for more details" "$LINENO" 5; } fi rm -f conftest conftest$ac_cv_exeext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 $as_echo "$ac_cv_exeext" >&6; } rm -f conftest.$ac_ext EXEEXT=$ac_cv_exeext ac_exeext=$EXEEXT cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { FILE *f = fopen ("conftest.out", "w"); return ferror (f) || fclose (f) != 0; ; return 0; } _ACEOF ac_clean_files="$ac_clean_files conftest.out" # Check that the compiler produces executables we can run. If not, either # the compiler is broken, or we cross compile. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 $as_echo_n "checking whether we are cross compiling... " >&6; } if test "$cross_compiling" != yes; then { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } if { ac_try='./conftest$ac_cv_exeext' { { case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; }; then cross_compiling=no else if test "$cross_compiling" = maybe; then cross_compiling=yes else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot run C compiled programs. If you meant to cross compile, use \`--host'. See \`config.log' for more details" "$LINENO" 5; } fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 $as_echo "$cross_compiling" >&6; } rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out ac_clean_files=$ac_clean_files_save { $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 $as_echo_n "checking for suffix of object files... " >&6; } if ${ac_cv_objext+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF rm -f conftest.o conftest.obj if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : for ac_file in conftest.o conftest.obj conftest.*; do test -f "$ac_file" || continue; case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;; *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` break;; esac done else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of object files: cannot compile See \`config.log' for more details" "$LINENO" 5; } fi rm -f conftest.$ac_cv_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 $as_echo "$ac_cv_objext" >&6; } OBJEXT=$ac_cv_objext ac_objext=$OBJEXT { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5 $as_echo_n "checking whether we are using the GNU C compiler... " >&6; } if ${ac_cv_c_compiler_gnu+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { #ifndef __GNUC__ choke me #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_compiler_gnu=yes else ac_compiler_gnu=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_cv_c_compiler_gnu=$ac_compiler_gnu fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 $as_echo "$ac_cv_c_compiler_gnu" >&6; } if test $ac_compiler_gnu = yes; then GCC=yes else GCC= fi ac_test_CFLAGS=${CFLAGS+set} ac_save_CFLAGS=$CFLAGS { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 $as_echo_n "checking whether $CC accepts -g... " >&6; } if ${ac_cv_prog_cc_g+:} false; then : $as_echo_n "(cached) " >&6 else ac_save_c_werror_flag=$ac_c_werror_flag ac_c_werror_flag=yes ac_cv_prog_cc_g=no CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_g=yes else CFLAGS="" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : else ac_c_werror_flag=$ac_save_c_werror_flag CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_g=yes fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_c_werror_flag=$ac_save_c_werror_flag fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 $as_echo "$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 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5 $as_echo_n "checking for $CC option to accept ISO C89... " >&6; } if ${ac_cv_prog_cc_c89+:} false; then : $as_echo_n "(cached) " >&6 else ac_cv_prog_cc_c89=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include struct stat; /* 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 -std 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 -std. */ int osf4_cc_array ['\x00' == 0 ? 1 : -1]; /* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters inside strings and character constants. */ #define FOO(x) 'x' int xlc6_cc_array[FOO(a) == 'x' ? 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 for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \ -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" do CC="$ac_save_CC $ac_arg" if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_c89=$ac_arg fi rm -f core conftest.err conftest.$ac_objext test "x$ac_cv_prog_cc_c89" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC fi # AC_CACHE_VAL case "x$ac_cv_prog_cc_c89" in x) { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 $as_echo "none needed" >&6; } ;; xno) { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 $as_echo "unsupported" >&6; } ;; *) CC="$CC $ac_cv_prog_cc_c89" { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 $as_echo "$ac_cv_prog_cc_c89" >&6; } ;; esac if test "x$ac_cv_prog_cc_c89" != xno; then : 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 ac_ext=cpp ac_cpp='$CXXCPP $CPPFLAGS' ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_cxx_compiler_gnu if test -z "$CXX"; then if test -n "$CCC"; then CXX=$CCC else if test -n "$ac_tool_prefix"; then for ac_prog in clang++ c++ g++ 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 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CXX+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CXX"; then ac_cv_prog_CXX="$CXX" # 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_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CXX="$ac_tool_prefix$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CXX=$ac_cv_prog_CXX if test -n "$CXX"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CXX" >&5 $as_echo "$CXX" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$CXX" && break done fi if test -z "$CXX"; then ac_ct_CXX=$CXX for ac_prog in clang++ c++ g++ do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_CXX+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CXX"; then ac_cv_prog_ac_ct_CXX="$ac_ct_CXX" # 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_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CXX="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CXX=$ac_cv_prog_ac_ct_CXX if test -n "$ac_ct_CXX"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CXX" >&5 $as_echo "$ac_ct_CXX" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$ac_ct_CXX" && break done if test "x$ac_ct_CXX" = x; then CXX="g++" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CXX=$ac_ct_CXX fi fi fi fi # Provide some information about the compiler. $as_echo "$as_me:${as_lineno-$LINENO}: checking for C++ compiler version" >&5 set X $ac_compile ac_compiler=$2 for ac_option in --version -v -V -qversion; do { { ac_try="$ac_compiler $ac_option >&5" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compiler $ac_option >&5") 2>conftest.err ac_status=$? if test -s conftest.err; then sed '10a\ ... rest of stderr output deleted ... 10q' conftest.err >conftest.er1 cat conftest.er1 >&5 fi rm -f conftest.er1 conftest.err $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } done { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C++ compiler" >&5 $as_echo_n "checking whether we are using the GNU C++ compiler... " >&6; } if ${ac_cv_cxx_compiler_gnu+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { #ifndef __GNUC__ choke me #endif ; return 0; } _ACEOF if ac_fn_cxx_try_compile "$LINENO"; then : ac_compiler_gnu=yes else ac_compiler_gnu=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_cv_cxx_compiler_gnu=$ac_compiler_gnu fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cxx_compiler_gnu" >&5 $as_echo "$ac_cv_cxx_compiler_gnu" >&6; } if test $ac_compiler_gnu = yes; then GXX=yes else GXX= fi ac_test_CXXFLAGS=${CXXFLAGS+set} ac_save_CXXFLAGS=$CXXFLAGS { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CXX accepts -g" >&5 $as_echo_n "checking whether $CXX accepts -g... " >&6; } if ${ac_cv_prog_cxx_g+:} false; then : $as_echo_n "(cached) " >&6 else ac_save_cxx_werror_flag=$ac_cxx_werror_flag ac_cxx_werror_flag=yes ac_cv_prog_cxx_g=no CXXFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_cxx_try_compile "$LINENO"; then : ac_cv_prog_cxx_g=yes else CXXFLAGS="" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_cxx_try_compile "$LINENO"; then : else ac_cxx_werror_flag=$ac_save_cxx_werror_flag CXXFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_cxx_try_compile "$LINENO"; then : ac_cv_prog_cxx_g=yes fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_cxx_werror_flag=$ac_save_cxx_werror_flag fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cxx_g" >&5 $as_echo "$ac_cv_prog_cxx_g" >&6; } if test "$ac_test_CXXFLAGS" = set; then CXXFLAGS=$ac_save_CXXFLAGS elif test $ac_cv_prog_cxx_g = yes; then if test "$GXX" = yes; then CXXFLAGS="-g -O2" else CXXFLAGS="-g" fi else if test "$GXX" = yes; then CXXFLAGS="-O2" else CXXFLAGS= fi 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 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 { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5 $as_echo_n "checking how to run the C preprocessor... " >&6; } # On Suns, sometimes $CPP names a directory. if test -n "$CPP" && test -d "$CPP"; then CPP= fi if test -z "$CPP"; then if ${ac_cv_prog_CPP+:} false; then : $as_echo_n "(cached) " >&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 confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef __STDC__ # include #else # include #endif Syntax error _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : else # Broken: fails on valid input. continue fi rm -f conftest.err conftest.i conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : # Broken: success on invalid input. continue else # Passes both tests. ac_preproc_ok=: break fi rm -f conftest.err conftest.i conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.i 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 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5 $as_echo "$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 confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef __STDC__ # include #else # include #endif Syntax error _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : else # Broken: fails on valid input. continue fi rm -f conftest.err conftest.i conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : # Broken: success on invalid input. continue else # Passes both tests. ac_preproc_ok=: break fi rm -f conftest.err conftest.i conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.i conftest.err conftest.$ac_ext if $ac_preproc_ok; then : else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "C preprocessor \"$CPP\" fails sanity check See \`config.log' for more details" "$LINENO" 5; } 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}ranlib", so it can be a program name with args. set dummy ${ac_tool_prefix}ranlib; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_RANLIB+:} false; then : $as_echo_n "(cached) " >&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_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi RANLIB=$ac_cv_prog_RANLIB if test -n "$RANLIB"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RANLIB" >&5 $as_echo "$RANLIB" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "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 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_RANLIB+:} false; then : $as_echo_n "(cached) " >&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_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_RANLIB="ranlib" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB if test -n "$ac_ct_RANLIB"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_RANLIB" >&5 $as_echo "$ac_ct_RANLIB" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_RANLIB" = x; then RANLIB=":" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac RANLIB=$ac_ct_RANLIB fi else RANLIB="$ac_cv_prog_RANLIB" fi # Extract the first word of "ar", so it can be a program name with args. set dummy ar; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_path_AR+:} false; then : $as_echo_n "(cached) " >&6 else case $AR in [\\/]* | ?:[\\/]*) ac_cv_path_AR="$AR" # Let the user override the test with a path. ;; *) 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_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_path_AR="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac fi AR=$ac_cv_path_AR if test -n "$AR"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AR" >&5 $as_echo "$AR" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi # Extract the first word of "chmod", so it can be a program name with args. set dummy chmod; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_path_CHMOD+:} false; then : $as_echo_n "(cached) " >&6 else case $CHMOD in [\\/]* | ?:[\\/]*) ac_cv_path_CHMOD="$CHMOD" # Let the user override the test with a path. ;; *) 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_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_path_CHMOD="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac fi CHMOD=$ac_cv_path_CHMOD if test -n "$CHMOD"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CHMOD" >&5 $as_echo "$CHMOD" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi # Extract the first word of "cp", so it can be a program name with args. set dummy cp; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_path_CP+:} false; then : $as_echo_n "(cached) " >&6 else case $CP in [\\/]* | ?:[\\/]*) ac_cv_path_CP="$CP" # Let the user override the test with a path. ;; *) 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_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_path_CP="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac fi CP=$ac_cv_path_CP if test -n "$CP"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CP" >&5 $as_echo "$CP" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi # Extract the first word of "fltk-config", so it can be a program name with args. set dummy fltk-config; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_path_FLTKCONFIG+:} false; then : $as_echo_n "(cached) " >&6 else case $FLTKCONFIG in [\\/]* | ?:[\\/]*) ac_cv_path_FLTKCONFIG="$FLTKCONFIG" # Let the user override the test with a path. ;; *) 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_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_path_FLTKCONFIG="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac fi FLTKCONFIG=$ac_cv_path_FLTKCONFIG if test -n "$FLTKCONFIG"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $FLTKCONFIG" >&5 $as_echo "$FLTKCONFIG" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for install-sh script" >&5 $as_echo_n "checking for install-sh script... " >&6; } INSTALL="`pwd`/install-sh" { $as_echo "$as_me:${as_lineno-$LINENO}: result: using $INSTALL" >&5 $as_echo "using $INSTALL" >&6; } # Extract the first word of "mv", so it can be a program name with args. set dummy mv; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_path_MV+:} false; then : $as_echo_n "(cached) " >&6 else case $MV in [\\/]* | ?:[\\/]*) ac_cv_path_MV="$MV" # Let the user override the test with a path. ;; *) 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_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_path_MV="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac fi MV=$ac_cv_path_MV if test -n "$MV"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MV" >&5 $as_echo "$MV" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi # Extract the first word of "mkdir", so it can be a program name with args. set dummy mkdir; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_path_MKDIR+:} false; then : $as_echo_n "(cached) " >&6 else case $MKDIR in [\\/]* | ?:[\\/]*) ac_cv_path_MKDIR="$MKDIR" # Let the user override the test with a path. ;; *) 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_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_path_MKDIR="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac fi MKDIR=$ac_cv_path_MKDIR if test -n "$MKDIR"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MKDIR" >&5 $as_echo "$MKDIR" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi # Extract the first word of "rm", so it can be a program name with args. set dummy rm; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_path_RM+:} false; then : $as_echo_n "(cached) " >&6 else case $RM in [\\/]* | ?:[\\/]*) ac_cv_path_RM="$RM" # Let the user override the test with a path. ;; *) 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_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_path_RM="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac fi RM=$ac_cv_path_RM if test -n "$RM"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RM" >&5 $as_echo "$RM" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}pkg-config", so it can be a program name with args. set dummy ${ac_tool_prefix}pkg-config; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_path_PKGCONFIG+:} false; then : $as_echo_n "(cached) " >&6 else case $PKGCONFIG in [\\/]* | ?:[\\/]*) ac_cv_path_PKGCONFIG="$PKGCONFIG" # Let the user override the test with a path. ;; *) 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_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_path_PKGCONFIG="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac fi PKGCONFIG=$ac_cv_path_PKGCONFIG if test -n "$PKGCONFIG"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PKGCONFIG" >&5 $as_echo "$PKGCONFIG" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_path_PKGCONFIG"; then ac_pt_PKGCONFIG=$PKGCONFIG # Extract the first word of "pkg-config", so it can be a program name with args. set dummy pkg-config; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_path_ac_pt_PKGCONFIG+:} false; then : $as_echo_n "(cached) " >&6 else case $ac_pt_PKGCONFIG in [\\/]* | ?:[\\/]*) ac_cv_path_ac_pt_PKGCONFIG="$ac_pt_PKGCONFIG" # Let the user override the test with a path. ;; *) 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_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_path_ac_pt_PKGCONFIG="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac fi ac_pt_PKGCONFIG=$ac_cv_path_ac_pt_PKGCONFIG if test -n "$ac_pt_PKGCONFIG"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_pt_PKGCONFIG" >&5 $as_echo "$ac_pt_PKGCONFIG" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_pt_PKGCONFIG" = x; then PKGCONFIG="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac PKGCONFIG=$ac_pt_PKGCONFIG fi else PKGCONFIG="$ac_cv_path_PKGCONFIG" fi if test "$ac_cv_prog_ranlib" = ":"; then ARFLAGS="crs" else ARFLAGS="cr" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5 $as_echo_n "checking for grep that handles long lines and -e... " >&6; } if ${ac_cv_path_GREP+:} false; then : $as_echo_n "(cached) " >&6 else if test -z "$GREP"; then ac_path_GREP_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in grep ggrep; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext" as_fn_executable_p "$ac_path_GREP" || continue # Check for GNU ac_path_GREP and select it if it is found. # Check for GNU $ac_path_GREP case `"$ac_path_GREP" --version 2>&1` in *GNU*) ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;; *) ac_count=0 $as_echo_n 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" $as_echo 'GREP' >> "conftest.nl" "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_GREP_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_GREP_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_GREP"; then as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 fi else ac_cv_path_GREP=$GREP fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5 $as_echo "$ac_cv_path_GREP" >&6; } GREP="$ac_cv_path_GREP" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5 $as_echo_n "checking for egrep... " >&6; } if ${ac_cv_path_EGREP+:} false; then : $as_echo_n "(cached) " >&6 else if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 then ac_cv_path_EGREP="$GREP -E" else if test -z "$EGREP"; then ac_path_EGREP_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in egrep; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext" as_fn_executable_p "$ac_path_EGREP" || continue # Check for GNU ac_path_EGREP and select it if it is found. # Check for GNU $ac_path_EGREP case `"$ac_path_EGREP" --version 2>&1` in *GNU*) ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;; *) ac_count=0 $as_echo_n 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" $as_echo 'EGREP' >> "conftest.nl" "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_EGREP_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_EGREP_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_EGREP"; then as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 fi else ac_cv_path_EGREP=$EGREP fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5 $as_echo "$ac_cv_path_EGREP" >&6; } EGREP="$ac_cv_path_EGREP" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5 $as_echo_n "checking for ANSI C header files... " >&6; } if ${ac_cv_header_stdc+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #include #include int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_header_stdc=yes else ac_cv_header_stdc=no fi rm -f core 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 confdefs.h - <<_ACEOF >conftest.$ac_ext /* 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 confdefs.h - <<_ACEOF >conftest.$ac_ext /* 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 confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #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)) return 2; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : else ac_cv_header_stdc=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5 $as_echo "$ac_cv_header_stdc" >&6; } if test $ac_cv_header_stdc = yes; then $as_echo "#define STDC_HEADERS 1" >>confdefs.h 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=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default " if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF fi done ac_fn_c_check_header_mongrel "$LINENO" "strings.h" "ac_cv_header_strings_h" "$ac_includes_default" if test "x$ac_cv_header_strings_h" = xyes; then : $as_echo "#define HAVE_STRINGS_H 1" >>confdefs.h fi ac_fn_c_check_header_mongrel "$LINENO" "locale.h" "ac_cv_header_locale_h" "$ac_includes_default" if test "x$ac_cv_header_locale_h" = xyes; then : $as_echo "#define HAVE_LOCALE_H 1" >>confdefs.h fi for ac_func in strdup strcasecmp strncasecmp strlcat strlcpy do : as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" if eval test \"x\$"$as_ac_var"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 _ACEOF fi done if test "$uname" = "HP-UX" -a "$uversion" = "1020"; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Forcing snprintf emulation for HP-UX..." >&5 $as_echo "$as_me: WARNING: Forcing snprintf emulation for HP-UX..." >&2;} else for ac_func in snprintf vsnprintf do : as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" if eval test \"x\$"$as_ac_var"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 _ACEOF fi done fi for ac_func in random lrand48 arc4random do : as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" if eval test \"x\$"$as_ac_var"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 _ACEOF fi done { $as_echo "$as_me:${as_lineno-$LINENO}: checking for tm_gmtoff member in tm structure" >&5 $as_echo_n "checking for tm_gmtoff member in tm structure... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { struct tm t; int o = t.tm_gmtoff; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } $as_echo "#define HAVE_TM_GMTOFF 1" >>confdefs.h else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext LDFLAGS="${LDFLAGS:=}" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pow in -lm" >&5 $as_echo_n "checking for pow in -lm... " >&6; } if ${ac_cv_lib_m_pow+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lm $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char pow (); int main () { return pow (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_m_pow=yes else ac_cv_lib_m_pow=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_m_pow" >&5 $as_echo "$ac_cv_lib_m_pow" >&6; } if test "x$ac_cv_lib_m_pow" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBM 1 _ACEOF LIBS="-lm $LIBS" fi ac_fn_c_check_func "$LINENO" "poll" "ac_cv_func_poll" if test "x$ac_cv_func_poll" = xyes; then : $as_echo "#define HAVE_POLL 1" >>confdefs.h fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing socket" >&5 $as_echo_n "checking for library containing socket... " >&6; } if ${ac_cv_search_socket+:} false; then : $as_echo_n "(cached) " >&6 else ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char socket (); int main () { return socket (); ; return 0; } _ACEOF for ac_lib in '' socket; do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi if ac_fn_c_try_link "$LINENO"; then : ac_cv_search_socket=$ac_res fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext if ${ac_cv_search_socket+:} false; then : break fi done if ${ac_cv_search_socket+:} false; then : else ac_cv_search_socket=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_socket" >&5 $as_echo "$ac_cv_search_socket" >&6; } ac_res=$ac_cv_search_socket if test "$ac_res" != no; then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing gethostbyaddr" >&5 $as_echo_n "checking for library containing gethostbyaddr... " >&6; } if ${ac_cv_search_gethostbyaddr+:} false; then : $as_echo_n "(cached) " >&6 else ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char gethostbyaddr (); int main () { return gethostbyaddr (); ; return 0; } _ACEOF for ac_lib in '' nsl; do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi if ac_fn_c_try_link "$LINENO"; then : ac_cv_search_gethostbyaddr=$ac_res fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext if ${ac_cv_search_gethostbyaddr+:} false; then : break fi done if ${ac_cv_search_gethostbyaddr+:} false; then : else ac_cv_search_gethostbyaddr=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_gethostbyaddr" >&5 $as_echo "$ac_cv_search_gethostbyaddr" >&6; } ac_res=$ac_cv_search_gethostbyaddr if test "$ac_res" != no; then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing getaddrinfo" >&5 $as_echo_n "checking for library containing getaddrinfo... " >&6; } if ${ac_cv_search_getaddrinfo+:} false; then : $as_echo_n "(cached) " >&6 else ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char getaddrinfo (); int main () { return getaddrinfo (); ; return 0; } _ACEOF for ac_lib in '' nsl; do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi if ac_fn_c_try_link "$LINENO"; then : ac_cv_search_getaddrinfo=$ac_res fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext if ${ac_cv_search_getaddrinfo+:} false; then : break fi done if ${ac_cv_search_getaddrinfo+:} false; then : else ac_cv_search_getaddrinfo=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_getaddrinfo" >&5 $as_echo "$ac_cv_search_getaddrinfo" >&6; } ac_res=$ac_cv_search_getaddrinfo if test "$ac_res" != no; then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" $as_echo "#define HAVE_GETADDRINFO 1" >>confdefs.h fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing getnameinfo" >&5 $as_echo_n "checking for library containing getnameinfo... " >&6; } if ${ac_cv_search_getnameinfo+:} false; then : $as_echo_n "(cached) " >&6 else ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char getnameinfo (); int main () { return getnameinfo (); ; return 0; } _ACEOF for ac_lib in '' nsl; do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi if ac_fn_c_try_link "$LINENO"; then : ac_cv_search_getnameinfo=$ac_res fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext if ${ac_cv_search_getnameinfo+:} false; then : break fi done if ${ac_cv_search_getnameinfo+:} false; then : else ac_cv_search_getnameinfo=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_getnameinfo" >&5 $as_echo "$ac_cv_search_getnameinfo" >&6; } ac_res=$ac_cv_search_getnameinfo if test "$ac_res" != no; then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" $as_echo "#define HAVE_GETNAMEINFO 1" >>confdefs.h fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing hstrerror" >&5 $as_echo_n "checking for library containing hstrerror... " >&6; } if ${ac_cv_search_hstrerror+:} false; then : $as_echo_n "(cached) " >&6 else ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char hstrerror (); int main () { return hstrerror (); ; return 0; } _ACEOF for ac_lib in '' nsl socket resolv; do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi if ac_fn_c_try_link "$LINENO"; then : ac_cv_search_hstrerror=$ac_res fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext if ${ac_cv_search_hstrerror+:} false; then : break fi done if ${ac_cv_search_hstrerror+:} false; then : else ac_cv_search_hstrerror=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_hstrerror" >&5 $as_echo "$ac_cv_search_hstrerror" >&6; } ac_res=$ac_cv_search_hstrerror if test "$ac_res" != no; then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" $as_echo "#define HAVE_HSTRERROR 1" >>confdefs.h fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing __res_init" >&5 $as_echo_n "checking for library containing __res_init... " >&6; } if ${ac_cv_search___res_init+:} false; then : $as_echo_n "(cached) " >&6 else ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char __res_init (); int main () { return __res_init (); ; return 0; } _ACEOF for ac_lib in '' resolv bind; do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi if ac_fn_c_try_link "$LINENO"; then : ac_cv_search___res_init=$ac_res fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext if ${ac_cv_search___res_init+:} false; then : break fi done if ${ac_cv_search___res_init+:} false; then : else ac_cv_search___res_init=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search___res_init" >&5 $as_echo "$ac_cv_search___res_init" >&6; } ac_res=$ac_cv_search___res_init if test "$ac_res" != no; then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" $as_echo "#define HAVE_RES_INIT 1" >>confdefs.h else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing res_9_init" >&5 $as_echo_n "checking for library containing res_9_init... " >&6; } if ${ac_cv_search_res_9_init+:} false; then : $as_echo_n "(cached) " >&6 else ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char res_9_init (); int main () { return res_9_init (); ; return 0; } _ACEOF for ac_lib in '' resolv bind; do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi if ac_fn_c_try_link "$LINENO"; then : ac_cv_search_res_9_init=$ac_res fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext if ${ac_cv_search_res_9_init+:} false; then : break fi done if ${ac_cv_search_res_9_init+:} false; then : else ac_cv_search_res_9_init=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_res_9_init" >&5 $as_echo "$ac_cv_search_res_9_init" >&6; } ac_res=$ac_cv_search_res_9_init if test "$ac_res" != no; then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" $as_echo "#define HAVE_RES_INIT 1" >>confdefs.h else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing res_init" >&5 $as_echo_n "checking for library containing res_init... " >&6; } if ${ac_cv_search_res_init+:} false; then : $as_echo_n "(cached) " >&6 else ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char res_init (); int main () { return res_init (); ; return 0; } _ACEOF for ac_lib in '' resolv bind; do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi if ac_fn_c_try_link "$LINENO"; then : ac_cv_search_res_init=$ac_res fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext if ${ac_cv_search_res_init+:} false; then : break fi done if ${ac_cv_search_res_init+:} false; then : else ac_cv_search_res_init=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_res_init" >&5 $as_echo "$ac_cv_search_res_init" >&6; } ac_res=$ac_cv_search_res_init if test "$ac_res" != no; then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" $as_echo "#define HAVE_RES_INIT 1" >>confdefs.h fi fi fi ac_fn_c_check_header_mongrel "$LINENO" "resolv.h" "ac_cv_header_resolv_h" "$ac_includes_default" if test "x$ac_cv_header_resolv_h" = xyes; then : $as_echo "#define HAVE_RESOLV_H 1" >>confdefs.h fi # Check whether --enable-largefile was given. if test "${enable_largefile+set}" = set; then : enableval=$enable_largefile; fi if test "$enable_largefile" != no; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for special C compiler options needed for large files" >&5 $as_echo_n "checking for special C compiler options needed for large files... " >&6; } if ${ac_cv_sys_largefile_CC+:} false; then : $as_echo_n "(cached) " >&6 else ac_cv_sys_largefile_CC=no if test "$GCC" != yes; then ac_save_CC=$CC while :; do # IRIX 6.2 and later do not support large files by default, # so use the C compiler's -n32 option if that helps. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include /* Check that off_t can represent 2**63 - 1 correctly. We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ #define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : break fi rm -f core conftest.err conftest.$ac_objext CC="$CC -n32" if ac_fn_c_try_compile "$LINENO"; then : ac_cv_sys_largefile_CC=' -n32'; break fi rm -f core conftest.err conftest.$ac_objext break done CC=$ac_save_CC rm -f conftest.$ac_ext fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_largefile_CC" >&5 $as_echo "$ac_cv_sys_largefile_CC" >&6; } if test "$ac_cv_sys_largefile_CC" != no; then CC=$CC$ac_cv_sys_largefile_CC fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _FILE_OFFSET_BITS value needed for large files" >&5 $as_echo_n "checking for _FILE_OFFSET_BITS value needed for large files... " >&6; } if ${ac_cv_sys_file_offset_bits+:} false; then : $as_echo_n "(cached) " >&6 else while :; do cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include /* Check that off_t can represent 2**63 - 1 correctly. We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ #define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_sys_file_offset_bits=no; break fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #define _FILE_OFFSET_BITS 64 #include /* Check that off_t can represent 2**63 - 1 correctly. We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ #define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_sys_file_offset_bits=64; break fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_cv_sys_file_offset_bits=unknown break done fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_file_offset_bits" >&5 $as_echo "$ac_cv_sys_file_offset_bits" >&6; } case $ac_cv_sys_file_offset_bits in #( no | unknown) ;; *) cat >>confdefs.h <<_ACEOF #define _FILE_OFFSET_BITS $ac_cv_sys_file_offset_bits _ACEOF ;; esac rm -rf conftest* if test $ac_cv_sys_file_offset_bits = unknown; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _LARGE_FILES value needed for large files" >&5 $as_echo_n "checking for _LARGE_FILES value needed for large files... " >&6; } if ${ac_cv_sys_large_files+:} false; then : $as_echo_n "(cached) " >&6 else while :; do cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include /* Check that off_t can represent 2**63 - 1 correctly. We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ #define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_sys_large_files=no; break fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #define _LARGE_FILES 1 #include /* Check that off_t can represent 2**63 - 1 correctly. We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ #define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_sys_large_files=1; break fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_cv_sys_large_files=unknown break done fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_large_files" >&5 $as_echo "$ac_cv_sys_large_files" >&6; } case $ac_cv_sys_large_files in #( no | unknown) ;; *) cat >>confdefs.h <<_ACEOF #define _LARGE_FILES $ac_cv_sys_large_files _ACEOF ;; esac rm -rf conftest* fi fi LARGEFILE="" if test x$enable_largefile != xno; then LARGEFILE="-D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE" if test x$ac_cv_sys_large_files = x1; then LARGEFILE="$LARGEFILE -D_LARGE_FILES" fi if test x$ac_cv_sys_file_offset_bits = x64; then LARGEFILE="$LARGEFILE -D_FILE_OFFSET_BITS=64" fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for long long int" >&5 $as_echo_n "checking for long long int... " >&6; } if ${ac_cv_c_long_long+:} false; then : $as_echo_n "(cached) " >&6 else if test "$GCC" = yes; then ac_cv_c_long_long=yes else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { long long int i; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_c_long_long=yes else ac_cv_c_long_long=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_long_long" >&5 $as_echo "$ac_cv_c_long_long" >&6; } if test $ac_cv_c_long_long = yes; then $as_echo "#define HAVE_LONG_LONG 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "strtoll" "ac_cv_func_strtoll" if test "x$ac_cv_func_strtoll" = xyes; then : $as_echo "#define HAVE_STRTOLL 1" >>confdefs.h fi # Check whether --enable-ssl was given. if test "${enable_ssl+set}" = set; then : enableval=$enable_ssl; fi # Check whether --enable-gnutls was given. if test "${enable_gnutls+set}" = set; then : enableval=$enable_gnutls; fi # Check whether --enable-cdsassl was given. if test "${enable_cdsassl+set}" = set; then : enableval=$enable_cdsassl; fi SSLFLAGS="" SSLLIBS="" have_ssl=0 if test x$enable_ssl != xno; then if test $have_ssl = 0 -a "x$enable_cdsassl" != "xno"; then if test $uname = Darwin; then ac_fn_c_check_header_mongrel "$LINENO" "Security/SecureTransport.h" "ac_cv_header_Security_SecureTransport_h" "$ac_includes_default" if test "x$ac_cv_header_Security_SecureTransport_h" = xyes; then : have_ssl=1 $as_echo "#define HAVE_SSL 1" >>confdefs.h $as_echo "#define HAVE_CDSASSL 1" >>confdefs.h SSLLIBS="-framework Security -framework CoreFoundation" ac_fn_c_check_header_mongrel "$LINENO" "Security/SecureTransportPriv.h" "ac_cv_header_Security_SecureTransportPriv_h" "$ac_includes_default" if test "x$ac_cv_header_Security_SecureTransportPriv_h" = xyes; then : $as_echo "#define HAVE_SECURETRANSPORTPRIV_H 1" >>confdefs.h fi ac_fn_c_check_header_mongrel "$LINENO" "Security/SecCertificate.h" "ac_cv_header_Security_SecCertificate_h" "$ac_includes_default" if test "x$ac_cv_header_Security_SecCertificate_h" = xyes; then : $as_echo "#define HAVE_SECCERTIFICATE_H 1" >>confdefs.h fi ac_fn_c_check_header_mongrel "$LINENO" "Security/SecItem.h" "ac_cv_header_Security_SecItem_h" "$ac_includes_default" if test "x$ac_cv_header_Security_SecItem_h" = xyes; then : $as_echo "#define HAVE_SECITEM_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "Security/SecItemPriv.h" "ac_cv_header_Security_SecItemPriv_h" "#include " if test "x$ac_cv_header_Security_SecItemPriv_h" = xyes; then : $as_echo "#define HAVE_SECITEMPRIV_H 1" >>confdefs.h fi ac_fn_c_check_header_mongrel "$LINENO" "Security/SecPolicy.h" "ac_cv_header_Security_SecPolicy_h" "$ac_includes_default" if test "x$ac_cv_header_Security_SecPolicy_h" = xyes; then : $as_echo "#define HAVE_SECPOLICY_H 1" >>confdefs.h fi ac_fn_c_check_header_mongrel "$LINENO" "Security/SecPolicyPriv.h" "ac_cv_header_Security_SecPolicyPriv_h" "$ac_includes_default" if test "x$ac_cv_header_Security_SecPolicyPriv_h" = xyes; then : $as_echo "#define HAVE_SECPOLICYPRIV_H 1" >>confdefs.h fi ac_fn_c_check_header_mongrel "$LINENO" "Security/SecBasePriv.h" "ac_cv_header_Security_SecBasePriv_h" "$ac_includes_default" if test "x$ac_cv_header_Security_SecBasePriv_h" = xyes; then : $as_echo "#define HAVE_SECBASEPRIV_H 1" >>confdefs.h fi ac_fn_c_check_header_mongrel "$LINENO" "Security/SecIdentitySearchPriv.h" "ac_cv_header_Security_SecIdentitySearchPriv_h" "$ac_includes_default" if test "x$ac_cv_header_Security_SecIdentitySearchPriv_h" = xyes; then : $as_echo "#define HAVE_SECIDENTITYSEARCHPRIV_H 1" >>confdefs.h fi $as_echo "#define HAVE_CSSMERRORSTRING 1" >>confdefs.h $as_echo "#define HAVE_SECKEYCHAINOPEN 1" >>confdefs.h fi if test $uversion -ge 150; then $as_echo "#define HAVE_SSLSETENABLEDCIPHERS 1" >>confdefs.h fi fi fi if test $have_ssl = 0 -a "x$enable_gnutls" != "xno" -a "x$PKGCONFIG" != x; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}libgnutls-config", so it can be a program name with args. set dummy ${ac_tool_prefix}libgnutls-config; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_path_LIBGNUTLSCONFIG+:} false; then : $as_echo_n "(cached) " >&6 else case $LIBGNUTLSCONFIG in [\\/]* | ?:[\\/]*) ac_cv_path_LIBGNUTLSCONFIG="$LIBGNUTLSCONFIG" # Let the user override the test with a path. ;; *) 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_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_path_LIBGNUTLSCONFIG="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac fi LIBGNUTLSCONFIG=$ac_cv_path_LIBGNUTLSCONFIG if test -n "$LIBGNUTLSCONFIG"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LIBGNUTLSCONFIG" >&5 $as_echo "$LIBGNUTLSCONFIG" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_path_LIBGNUTLSCONFIG"; then ac_pt_LIBGNUTLSCONFIG=$LIBGNUTLSCONFIG # Extract the first word of "libgnutls-config", so it can be a program name with args. set dummy libgnutls-config; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_path_ac_pt_LIBGNUTLSCONFIG+:} false; then : $as_echo_n "(cached) " >&6 else case $ac_pt_LIBGNUTLSCONFIG in [\\/]* | ?:[\\/]*) ac_cv_path_ac_pt_LIBGNUTLSCONFIG="$ac_pt_LIBGNUTLSCONFIG" # Let the user override the test with a path. ;; *) 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_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_path_ac_pt_LIBGNUTLSCONFIG="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac fi ac_pt_LIBGNUTLSCONFIG=$ac_cv_path_ac_pt_LIBGNUTLSCONFIG if test -n "$ac_pt_LIBGNUTLSCONFIG"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_pt_LIBGNUTLSCONFIG" >&5 $as_echo "$ac_pt_LIBGNUTLSCONFIG" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_pt_LIBGNUTLSCONFIG" = x; then LIBGNUTLSCONFIG="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac LIBGNUTLSCONFIG=$ac_pt_LIBGNUTLSCONFIG fi else LIBGNUTLSCONFIG="$ac_cv_path_LIBGNUTLSCONFIG" fi if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}libgcrypt-config", so it can be a program name with args. set dummy ${ac_tool_prefix}libgcrypt-config; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_path_LIBGCRYPTCONFIG+:} false; then : $as_echo_n "(cached) " >&6 else case $LIBGCRYPTCONFIG in [\\/]* | ?:[\\/]*) ac_cv_path_LIBGCRYPTCONFIG="$LIBGCRYPTCONFIG" # Let the user override the test with a path. ;; *) 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_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_path_LIBGCRYPTCONFIG="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac fi LIBGCRYPTCONFIG=$ac_cv_path_LIBGCRYPTCONFIG if test -n "$LIBGCRYPTCONFIG"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LIBGCRYPTCONFIG" >&5 $as_echo "$LIBGCRYPTCONFIG" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_path_LIBGCRYPTCONFIG"; then ac_pt_LIBGCRYPTCONFIG=$LIBGCRYPTCONFIG # Extract the first word of "libgcrypt-config", so it can be a program name with args. set dummy libgcrypt-config; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_path_ac_pt_LIBGCRYPTCONFIG+:} false; then : $as_echo_n "(cached) " >&6 else case $ac_pt_LIBGCRYPTCONFIG in [\\/]* | ?:[\\/]*) ac_cv_path_ac_pt_LIBGCRYPTCONFIG="$ac_pt_LIBGCRYPTCONFIG" # Let the user override the test with a path. ;; *) 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_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_path_ac_pt_LIBGCRYPTCONFIG="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac fi ac_pt_LIBGCRYPTCONFIG=$ac_cv_path_ac_pt_LIBGCRYPTCONFIG if test -n "$ac_pt_LIBGCRYPTCONFIG"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_pt_LIBGCRYPTCONFIG" >&5 $as_echo "$ac_pt_LIBGCRYPTCONFIG" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_pt_LIBGCRYPTCONFIG" = x; then LIBGCRYPTCONFIG="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac LIBGCRYPTCONFIG=$ac_pt_LIBGCRYPTCONFIG fi else LIBGCRYPTCONFIG="$ac_cv_path_LIBGCRYPTCONFIG" fi if $PKGCONFIG --exists gnutls; then have_ssl=1 SSLLIBS=`$PKGCONFIG --libs gnutls` SSLFLAGS=`$PKGCONFIG --cflags gnutls` $as_echo "#define HAVE_SSL 1" >>confdefs.h $as_echo "#define HAVE_GNUTLS 1" >>confdefs.h elif test "x$LIBGNUTLSCONFIG" != x; then have_ssl=1 SSLLIBS=`$LIBGNUTLSCONFIG --libs` SSLFLAGS=`$LIBGNUTLSCONFIG --cflags` $as_echo "#define HAVE_SSL 1" >>confdefs.h $as_echo "#define HAVE_GNUTLS 1" >>confdefs.h fi if test $have_ssl = 1; then SAVELIBS="$LIBS" LIBS="$LIBS $SSLLIBS" ac_fn_c_check_func "$LINENO" "gnutls_transport_set_pull_timeout_function" "ac_cv_func_gnutls_transport_set_pull_timeout_function" if test "x$ac_cv_func_gnutls_transport_set_pull_timeout_function" = xyes; then : $as_echo "#define HAVE_GNUTLS_TRANSPORT_SET_PULL_TIMEOUT_FUNCTION 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "gnutls_priority_set_direct" "ac_cv_func_gnutls_priority_set_direct" if test "x$ac_cv_func_gnutls_priority_set_direct" = xyes; then : $as_echo "#define HAVE_GNUTLS_PRIORITY_SET_DIRECT 1" >>confdefs.h fi LIBS="$SAVELIBS" fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: Using SSLFLAGS=\"$SSLFLAGS\", SSLLIBS=\"$SSLLIBS\"" >&5 $as_echo "$as_me: Using SSLFLAGS=\"$SSLFLAGS\", SSLLIBS=\"$SSLLIBS\"" >&6;} POST=: if test "x$with_gui" != xno; then if test "x$FLTKCONFIG" != x; then LIBS="$LIBS `$FLTKCONFIG --use-images --ldflags`" $as_echo "#define HAVE_LIBFLTK 1" >>confdefs.h POST="$FLTKCONFIG --post" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for XpmCreatePixmapFromData in -lXpm" >&5 $as_echo_n "checking for XpmCreatePixmapFromData in -lXpm... " >&6; } if ${ac_cv_lib_Xpm_XpmCreatePixmapFromData+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lXpm $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char XpmCreatePixmapFromData (); int main () { return XpmCreatePixmapFromData (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_Xpm_XpmCreatePixmapFromData=yes else ac_cv_lib_Xpm_XpmCreatePixmapFromData=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_Xpm_XpmCreatePixmapFromData" >&5 $as_echo "$ac_cv_lib_Xpm_XpmCreatePixmapFromData" >&6; } if test "x$ac_cv_lib_Xpm_XpmCreatePixmapFromData" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBXPM 1 _ACEOF LIBS="-lXpm $LIBS" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for XCreateBitmapFromData in -lX11" >&5 $as_echo_n "checking for XCreateBitmapFromData in -lX11... " >&6; } if ${ac_cv_lib_X11_XCreateBitmapFromData+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lX11 $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char XCreateBitmapFromData (); int main () { return XCreateBitmapFromData (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_X11_XCreateBitmapFromData=yes else ac_cv_lib_X11_XCreateBitmapFromData=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_X11_XCreateBitmapFromData" >&5 $as_echo "$ac_cv_lib_X11_XCreateBitmapFromData" >&6; } if test "x$ac_cv_lib_X11_XCreateBitmapFromData" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBX11 1 _ACEOF LIBS="-lX11 $LIBS" fi else { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: FLTK not available so no GUI will be built." >&5 $as_echo "$as_me: WARNING: FLTK not available so no GUI will be built." >&2;} fi fi NEWLIBS="" # Check whether --enable-localjpeg was given. if test "${enable_localjpeg+set}" = set; then : enableval=$enable_localjpeg; fi if test x$enable_localjpeg = xyes; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing jpeg_CreateCompress" >&5 $as_echo_n "checking for library containing jpeg_CreateCompress... " >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: result: local libjpeg" >&5 $as_echo "local libjpeg" >&6; } JPEGINC="-I../jpeg" JPEG="jpeg" NEWLIBS="../jpeg/libjpeg.a $NEWLIBS" else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing jpeg_CreateCompress" >&5 $as_echo_n "checking for library containing jpeg_CreateCompress... " >&6; } if ${ac_cv_search_jpeg_CreateCompress+:} false; then : $as_echo_n "(cached) " >&6 else ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char jpeg_CreateCompress (); int main () { return jpeg_CreateCompress (); ; return 0; } _ACEOF for ac_lib in '' turbojpeg jpeg; do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi if ac_fn_c_try_link "$LINENO"; then : ac_cv_search_jpeg_CreateCompress=$ac_res fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext if ${ac_cv_search_jpeg_CreateCompress+:} false; then : break fi done if ${ac_cv_search_jpeg_CreateCompress+:} false; then : else ac_cv_search_jpeg_CreateCompress=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_jpeg_CreateCompress" >&5 $as_echo "$ac_cv_search_jpeg_CreateCompress" >&6; } ac_res=$ac_cv_search_jpeg_CreateCompress if test "$ac_res" != no; then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" JPEGINC="" JPEG="" else JPEGINC="-I../jpeg" JPEG="jpeg" NEWLIBS="../jpeg/libjpeg.a $NEWLIBS" fi fi # Check whether --enable-localzlib was given. if test "${enable_localzlib+set}" = set; then : enableval=$enable_localzlib; fi if test x$enable_localzlib = xyes; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing gzgets" >&5 $as_echo_n "checking for library containing gzgets... " >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: result: local libz" >&5 $as_echo "local libz" >&6; } ZLIBINC="-I../zlib" ZLIB="zlib" NEWLIBS="../zlib/libz.a $NEWLIBS" else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing gzgets" >&5 $as_echo_n "checking for library containing gzgets... " >&6; } if ${ac_cv_search_gzgets+:} false; then : $as_echo_n "(cached) " >&6 else ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char gzgets (); int main () { return gzgets (); ; return 0; } _ACEOF for ac_lib in '' z; do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi if ac_fn_c_try_link "$LINENO"; then : ac_cv_search_gzgets=$ac_res fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext if ${ac_cv_search_gzgets+:} false; then : break fi done if ${ac_cv_search_gzgets+:} false; then : else ac_cv_search_gzgets=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_gzgets" >&5 $as_echo "$ac_cv_search_gzgets" >&6; } ac_res=$ac_cv_search_gzgets if test "$ac_res" != no; then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" ZLIBINC="" ZLIB="" else ZLIBINC="-I../zlib" ZLIB="zlib" NEWLIBS="../zlib/libz.a $NEWLIBS" fi fi # Check whether --enable-localpng was given. if test "${enable_localpng+set}" = set; then : enableval=$enable_localpng; fi if test x$enable_localpng = xyes; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing png_set_tRNS_to_alpha" >&5 $as_echo_n "checking for library containing png_set_tRNS_to_alpha... " >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: result: local libpng" >&5 $as_echo "local libpng" >&6; } PNGINC="-I../png" PNG="png" NEWLIBS="../png/libpng.a $NEWLIBS" else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing png_set_tRNS_to_alpha" >&5 $as_echo_n "checking for library containing png_set_tRNS_to_alpha... " >&6; } if ${ac_cv_search_png_set_tRNS_to_alpha+:} false; then : $as_echo_n "(cached) " >&6 else ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char png_set_tRNS_to_alpha (); int main () { return png_set_tRNS_to_alpha (); ; return 0; } _ACEOF for ac_lib in '' png; do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi if ac_fn_c_try_link "$LINENO"; then : ac_cv_search_png_set_tRNS_to_alpha=$ac_res fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext if ${ac_cv_search_png_set_tRNS_to_alpha+:} false; then : break fi done if ${ac_cv_search_png_set_tRNS_to_alpha+:} false; then : else ac_cv_search_png_set_tRNS_to_alpha=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_png_set_tRNS_to_alpha" >&5 $as_echo "$ac_cv_search_png_set_tRNS_to_alpha" >&6; } ac_res=$ac_cv_search_png_set_tRNS_to_alpha if test "$ac_res" != no; then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" PNGINC="" PNG="" else PNGINC="-I../png" PNG="png" NEWLIBS="../png/libpng.a $NEWLIBS" fi fi $as_echo "#define HAVE_LIBJPEG 1" >>confdefs.h $as_echo "#define HAVE_LIBPNG 1" >>confdefs.h $as_echo "#define HAVE_LIBZ 1" >>confdefs.h LIBS="$NEWLIBS $LIBS" if test "$prefix" = "NONE"; then prefix="/usr/local" fi if test "$exec_prefix" = "NONE"; then exec_prefix="$prefix" fi if test "$bindir" = "\${exec_prefix}/bin"; then bindir="$exec_prefix/bin" fi if test "$datarootdir" = "\${prefix}/share"; then if test "$prefix" = "/"; then datarootdir="/usr/share" else datarootdir="$prefix/share" fi fi if test "$datadir" = "\${prefix}/share"; then if test "$prefix" = "/"; then datadir="/usr/share" else datadir="$prefix/share" fi elif test "$datadir" = "\${datarootdir}"; then datadir="$datarootdir" fi cat >>confdefs.h <<_ACEOF #define DOCUMENTATION "$datadir/doc/htmldoc" _ACEOF cat >>confdefs.h <<_ACEOF #define HTML_DATA "$datadir/htmldoc" _ACEOF # Check whether --enable-sanitizer was given. if test "${enable_sanitizer+set}" = set; then : enableval=$enable_sanitizer; fi if test -n "$GXX"; then if test x$enable_sanitizer = xyes; then # Use -fsanitize=address with debugging... OPTIM="$OPTIM -g -fsanitize=address" else # Otherwise use the Fortify enhancements to catch any unbounded # string operations... CFLAGS="$CFLAGS -D_FORTIFY_SOURCE=2" CXXFLAGS="$CXXFLAGS -D_FORTIFY_SOURCE=2" fi if test -z "$OPTIM"; then OPTIM="-Os -g" fi OPTIM="-Wall -Wunused -Wno-char-subscripts -Wno-format-y2k $OPTIM" { $as_echo "$as_me:${as_lineno-$LINENO}: checking if GCC supports -fno-rtti" >&5 $as_echo_n "checking if GCC supports -fno-rtti... " >&6; } OLDCFLAGS="$CFLAGS" CFLAGS="$CFLAGS -fno-rtti" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : CXXFLAGS="$CXXFLAGS -fno-rtti" { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext CFLAGS="$OLDCFLAGS" { $as_echo "$as_me:${as_lineno-$LINENO}: checking if GCC supports -fno-exceptions" >&5 $as_echo_n "checking if GCC supports -fno-exceptions... " >&6; } OLDCFLAGS="$CFLAGS" CFLAGS="$CFLAGS -fno-exceptions" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : CXXFLAGS="$CXXFLAGS -fno-exceptions" { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext CFLAGS="$OLDCFLAGS" if test "$uname" = SunOS; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking if GCC supports -fpermissive" >&5 $as_echo_n "checking if GCC supports -fpermissive... " >&6; } OLDCFLAGS="$CFLAGS" CFLAGS="$CFLAGS -fpermissive" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : CXXFLAGS="$CXXFLAGS -fpermissive" { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext CFLAGS="$OLDCFLAGS" fi fi if test "x$with_gui" != xno; then if test "x$FLTKCONFIG" != x; then OPTIM="`$FLTKCONFIG --cflags` $OPTIM" fi fi ac_config_files="$ac_config_files Makedefs Makefile desktop/htmldoc.plist" 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, we kill variables containing newlines. # 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. ( for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space=' '; set) 2>&1` in #( *${as_nl}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 "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) | sed ' /^ac_cv_env_/b end t clear :clear s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ t end s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ :end' >>confcache if diff "$cache_file" confcache >/dev/null 2>&1; then :; else if test -w "$cache_file"; then if test "x$cache_file" != "x/dev/null"; then { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 $as_echo "$as_me: updating cache $cache_file" >&6;} if test ! -f "$cache_file" || test -h "$cache_file"; then cat confcache >"$cache_file" else case $cache_file in #( */* | ?:*) mv -f confcache "$cache_file"$$ && mv -f "$cache_file"$$ "$cache_file" ;; #( *) mv -f confcache "$cache_file" ;; esac fi fi else { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 $as_echo "$as_me: not updating unwritable cache $cache_file" >&6;} 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}' DEFS=-DHAVE_CONFIG_H ac_libobjs= ac_ltlibobjs= U= for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue # 1. Remove the extension, and $U if already installed. ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' ac_i=`$as_echo "$ac_i" | sed "$ac_script"` # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR # will be set to the directory where LIBOBJS objects are built. as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext" as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo' done LIBOBJS=$ac_libobjs LTLIBOBJS=$ac_ltlibobjs : "${CONFIG_STATUS=./config.status}" ac_write_fail=0 ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files $CONFIG_STATUS" { $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 $as_echo "$as_me: creating $CONFIG_STATUS" >&6;} as_write_fail=0 cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1 #! $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} export SHELL _ASEOF cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1 ## -------------------- ## ## M4sh Initialization. ## ## -------------------- ## # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi as_nl=' ' export as_nl # Printing a long string crashes Solaris 7 /usr/bin/printf. as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo # Prefer a ksh shell builtin over an external printf program on Solaris, # but without wasting forks for bash or zsh. if test -z "$BASH_VERSION$ZSH_VERSION" \ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='print -r --' as_echo_n='print -rn --' elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='printf %s\n' as_echo_n='printf %s' else if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' as_echo_n='/usr/ucb/echo -n' else as_echo_body='eval expr "X$1" : "X\\(.*\\)"' as_echo_n_body='eval arg=$1; case $arg in #( *"$as_nl"*) expr "X$arg" : "X\\(.*\\)$as_nl"; arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; esac; expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" ' export as_echo_n_body as_echo_n='sh -c $as_echo_n_body as_echo' fi export as_echo_body as_echo='sh -c $as_echo_body as_echo' fi # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || PATH_SEPARATOR=';' } fi # IFS # We need space, tab and new line, in precisely that order. Quoting is # there to prevent editors from complaining about space-tab. # (If _AS_PATH_WALK were called with IFS unset, it would disable word # splitting by setting IFS to empty value.) IFS=" "" $as_nl" # Find who we are. Look in the path if we contain no directory separator. as_myself= 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 IFS=$as_save_IFS ;; 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 $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi # Unset variables that we do not need and which cause bugs (e.g. in # pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" # suppresses any "Segmentation fault" message there. '((' could # trigger a bug in pdksh 5.2.14. for as_var in BASH_ENV ENV MAIL MAILPATH do eval test x\${$as_var+set} = xset \ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done PS1='$ ' PS2='> ' PS4='+ ' # NLS nuisances. LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE # CDPATH. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH # as_fn_error STATUS ERROR [LINENO LOG_FD] # ---------------------------------------- # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are # provided, also output the error to LOG_FD, referencing LINENO. Then exit the # script with STATUS, using 1 if that was 0. as_fn_error () { as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi $as_echo "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. as_fn_set_status () { return $1 } # as_fn_set_status # as_fn_exit STATUS # ----------------- # Exit the shell with STATUS, even in a "trap 0" or "set -e" context. as_fn_exit () { set +e as_fn_set_status $1 exit $1 } # as_fn_exit # as_fn_unset VAR # --------------- # Portably unset VAR. as_fn_unset () { { eval $1=; unset $1;} } as_unset=as_fn_unset # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : eval 'as_fn_append () { eval $1+=\$2 }' else as_fn_append () { eval $1=\$$1\$2 } fi # as_fn_append # as_fn_arith ARG... # ------------------ # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : eval 'as_fn_arith () { as_val=$(( $* )) }' else as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` } fi # as_fn_arith if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; 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 if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then as_dirname=dirname else as_dirname=false fi as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || $as_echo X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` # 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 ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) case `echo 'xy\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. xy) ECHO_C='\c';; *) echo `echo ksh88 bug on AIX 6.1` > /dev/null ECHO_T=' ';; esac;; *) ECHO_N='-n';; esac rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file else rm -f conf$$.dir mkdir conf$$.dir 2>/dev/null fi if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. # In both cases, we have to default to `cp -pR'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -pR' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -pR' fi else as_ln_s='cp -pR' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null # as_fn_mkdir_p # ------------- # Create "$as_dir" as a directory, including parents if necessary. as_fn_mkdir_p () { case $as_dir in #( -*) as_dir=./$as_dir;; esac test -d "$as_dir" || eval $as_mkdir_p || { as_dirs= while :; do case $as_dir in #( *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" as_dir=`$as_dirname -- "$as_dir" || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` test -d "$as_dir" && break done test -z "$as_dirs" || eval "mkdir $as_dirs" } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" } # as_fn_mkdir_p if mkdir -p . 2>/dev/null; then as_mkdir_p='mkdir -p "$as_dir"' else test -d ./-p && rmdir ./-p as_mkdir_p=false fi # as_fn_executable_p FILE # ----------------------- # Test if FILE is an executable regular file. as_fn_executable_p () { test -f "$1" && test -x "$1" } # as_fn_executable_p as_test_x='test -x' as_executable_p=as_fn_executable_p # 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'" exec 6>&1 ## ----------------------------------- ## ## Main body of $CONFIG_STATUS script. ## ## ----------------------------------- ## _ASEOF test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1 cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # Save the log message, to keep $0 and so on meaningful, and to # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" This file was extended by HTMLDOC $as_me 1.9.7, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES CONFIG_HEADERS = $CONFIG_HEADERS CONFIG_LINKS = $CONFIG_LINKS CONFIG_COMMANDS = $CONFIG_COMMANDS $ $0 $@ on `(hostname || uname -n) 2>/dev/null | sed 1q` " _ACEOF case $ac_config_files in *" "*) set x $ac_config_files; shift; ac_config_files=$*;; esac case $ac_config_headers in *" "*) set x $ac_config_headers; shift; ac_config_headers=$*;; esac cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 # Files that config.status was made for. config_files="$ac_config_files" config_headers="$ac_config_headers" _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 ac_cs_usage="\ \`$as_me' instantiates files and other configuration actions from templates according to the current configuration. Unless the files and actions are specified as TAGs, all are instantiated by default. Usage: $0 [OPTION]... [TAG]... -h, --help print this help, then exit -V, --version print version number and configuration settings, then exit --config print configuration, then exit -q, --quiet, --silent 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 --header=FILE[:TEMPLATE] instantiate the configuration header FILE Configuration files: $config_files Configuration headers: $config_headers Report bugs to . HTMLDOC home page: ." _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ HTMLDOC config.status 1.9.7 configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" Copyright (C) 2012 Free Software Foundation, Inc. This config.status script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it." ac_pwd='$ac_pwd' srcdir='$srcdir' AWK='$AWK' test -n "\$AWK" || AWK=awk _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # The default lists apply if the user does not specify any file. 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=`expr "X$1" : 'X\([^=]*\)='` ac_optarg= ac_shift=: ;; *) ac_option=$1 ac_optarg=$2 ac_shift=shift ;; esac case $ac_option in # Handling of the options. -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) ac_cs_recheck=: ;; --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) $as_echo "$ac_cs_version"; exit ;; --config | --confi | --conf | --con | --co | --c ) $as_echo "$ac_cs_config"; exit ;; --debug | --debu | --deb | --de | --d | -d ) debug=: ;; --file | --fil | --fi | --f ) $ac_shift case $ac_optarg in *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; '') as_fn_error $? "missing file argument" ;; esac as_fn_append CONFIG_FILES " '$ac_optarg'" ac_need_defaults=false;; --header | --heade | --head | --hea ) $ac_shift case $ac_optarg in *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; esac as_fn_append CONFIG_HEADERS " '$ac_optarg'" ac_need_defaults=false;; --he | --h) # Conflict between --help and --header as_fn_error $? "ambiguous option: \`$1' Try \`$0 --help' for more information.";; --help | --hel | -h ) $as_echo "$ac_cs_usage"; exit ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil | --si | --s) ac_cs_silent=: ;; # This is an error. -*) as_fn_error $? "unrecognized option: \`$1' Try \`$0 --help' for more information." ;; *) as_fn_append ac_config_targets " $1" ac_need_defaults=false ;; 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 || ac_write_fail=1 if \$ac_cs_recheck; then set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion shift \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6 CONFIG_SHELL='$SHELL' export CONFIG_SHELL exec "\$@" fi _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 exec 5>>config.log { echo sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX ## Running $as_me. ## _ASBOX $as_echo "$ac_log" } >&5 _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # Handling of arguments. for ac_config_target in $ac_config_targets do case $ac_config_target in "config.h") CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;; "Makedefs") CONFIG_FILES="$CONFIG_FILES Makedefs" ;; "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; "desktop/htmldoc.plist") CONFIG_FILES="$CONFIG_FILES desktop/htmldoc.plist" ;; *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;; 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 test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers fi # Have a temporary directory for convenience. Make it in the build tree # simply because there is no reason against having it here, and in addition, # creating and moving files from /tmp can sometimes cause problems. # Hook for its removal unless debugging. # Note that there is a small window in which the directory will not be cleaned: # after its creation but before its name has been assigned to `$tmp'. $debug || { tmp= ac_tmp= trap 'exit_status=$? : "${ac_tmp:=$tmp}" { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status ' 0 trap 'as_fn_exit 1' 1 2 13 15 } # Create a (secure) tmp directory for tmp files. { tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && test -d "$tmp" } || { tmp=./conf$$-$RANDOM (umask 077 && mkdir "$tmp") } || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5 ac_tmp=$tmp # Set up the scripts for CONFIG_FILES section. # No need to generate them if there are no CONFIG_FILES. # This happens for instance with `./config.status config.h'. if test -n "$CONFIG_FILES"; then ac_cr=`echo X | tr X '\015'` # On cygwin, bash can eat \r inside `` if the user requested igncr. # But we know of no other shell where ac_cr would be empty at this # point, so we can use a bashism as a fallback. if test "x$ac_cr" = x; then eval ac_cr=\$\'\\r\' fi ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' /dev/null` if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then ac_cs_awk_cr='\\r' else ac_cs_awk_cr=$ac_cr fi echo 'BEGIN {' >"$ac_tmp/subs1.awk" && _ACEOF { echo "cat >conf$$subs.awk <<_ACEOF" && echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' && echo "_ACEOF" } >conf$$subs.sh || as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'` ac_delim='%!_!# ' for ac_last_try in false false false false false :; do . ./conf$$subs.sh || as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X` if test $ac_delim_n = $ac_delim_num; then break elif $ac_last_try; then as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 else ac_delim="$ac_delim!$ac_delim _$ac_delim!! " fi done rm -f conf$$subs.sh cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK && _ACEOF sed -n ' h s/^/S["/; s/!.*/"]=/ p g s/^[^!]*!// :repl t repl s/'"$ac_delim"'$// t delim :nl h s/\(.\{148\}\)..*/\1/ t more1 s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/ p n b repl :more1 s/["\\]/\\&/g; s/^/"/; s/$/"\\/ p g s/.\{148\}// t nl :delim h s/\(.\{148\}\)..*/\1/ t more2 s/["\\]/\\&/g; s/^/"/; s/$/"/ p b :more2 s/["\\]/\\&/g; s/^/"/; s/$/"\\/ p g s/.\{148\}// t delim ' >$CONFIG_STATUS || ac_write_fail=1 rm -f conf$$subs.awk cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 _ACAWK cat >>"\$ac_tmp/subs1.awk" <<_ACAWK && for (key in S) S_is_set[key] = 1 FS = "" } { line = $ 0 nfields = split(line, field, "@") substed = 0 len = length(field[1]) for (i = 2; i < nfields; i++) { key = field[i] keylen = length(key) if (S_is_set[key]) { value = S[key] line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3) len += length(value) + length(field[++i]) substed = 1 } else len += 1 + keylen } print line } _ACAWK _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g" else cat fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \ || as_fn_error $? "could not setup config files machinery" "$LINENO" 5 _ACEOF # VPATH may cause trouble with some makes, so we remove sole $(srcdir), # ${srcdir} and @srcdir@ entries 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[ ]*=[ ]*/{ h s/// s/^/:/ s/[ ]*$/:/ s/:\$(srcdir):/:/g s/:\${srcdir}:/:/g s/:@srcdir@:/:/g s/^:*// s/:*$// x s/\(=[ ]*\).*/\1/ G s/\n// s/^[^=]*=[ ]*$// }' fi cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 fi # test -n "$CONFIG_FILES" # Set up the scripts for CONFIG_HEADERS section. # No need to generate them if there are no CONFIG_HEADERS. # This happens for instance with `./config.status Makefile'. if test -n "$CONFIG_HEADERS"; then cat >"$ac_tmp/defines.awk" <<\_ACAWK || BEGIN { _ACEOF # Transform confdefs.h into an awk script `defines.awk', embedded as # here-document in config.status, that substitutes the proper values into # config.h.in to produce config.h. # Create a delimiter string that does not exist in confdefs.h, to ease # handling of long lines. ac_delim='%!_!# ' for ac_last_try in false false :; do ac_tt=`sed -n "/$ac_delim/p" confdefs.h` if test -z "$ac_tt"; then break elif $ac_last_try; then as_fn_error $? "could not make $CONFIG_HEADERS" "$LINENO" 5 else ac_delim="$ac_delim!$ac_delim _$ac_delim!! " fi done # For the awk script, D is an array of macro values keyed by name, # likewise P contains macro parameters if any. Preserve backslash # newline sequences. ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]* sed -n ' s/.\{148\}/&'"$ac_delim"'/g t rset :rset s/^[ ]*#[ ]*define[ ][ ]*/ / t def d :def s/\\$// t bsnl s/["\\]/\\&/g s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ D["\1"]=" \3"/p s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2"/p d :bsnl s/["\\]/\\&/g s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ D["\1"]=" \3\\\\\\n"\\/p t cont s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2\\\\\\n"\\/p t cont d :cont n s/.\{148\}/&'"$ac_delim"'/g t clear :clear s/\\$// t bsnlc s/["\\]/\\&/g; s/^/"/; s/$/"/p d :bsnlc s/["\\]/\\&/g; s/^/"/; s/$/\\\\\\n"\\/p b cont ' >$CONFIG_STATUS || ac_write_fail=1 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 for (key in D) D_is_set[key] = 1 FS = "" } /^[\t ]*#[\t ]*(define|undef)[\t ]+$ac_word_re([\t (]|\$)/ { line = \$ 0 split(line, arg, " ") if (arg[1] == "#") { defundef = arg[2] mac1 = arg[3] } else { defundef = substr(arg[1], 2) mac1 = arg[2] } split(mac1, mac2, "(") #) macro = mac2[1] prefix = substr(line, 1, index(line, defundef) - 1) if (D_is_set[macro]) { # Preserve the white space surrounding the "#". print prefix "define", macro P[macro] D[macro] next } else { # Replace #undef with comments. This is necessary, for example, # in the case of _POSIX_SOURCE, which is predefined and required # on some systems where configure will not decide to define it. if (defundef == "undef") { print "/*", prefix defundef, macro, "*/" next } } } { print } _ACAWK _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 as_fn_error $? "could not setup config headers machinery" "$LINENO" 5 fi # test -n "$CONFIG_HEADERS" eval set X " :F $CONFIG_FILES :H $CONFIG_HEADERS " shift for ac_tag do case $ac_tag in :[FHLC]) ac_mode=$ac_tag; continue;; esac case $ac_mode$ac_tag in :[FHL]*:*);; :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;; :[FH]-) ac_tag=-:-;; :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; esac ac_save_IFS=$IFS IFS=: set x $ac_tag IFS=$ac_save_IFS shift ac_file=$1 shift case $ac_mode in :L) ac_source=$1;; :[FH]) ac_file_inputs= for ac_f do case $ac_f in -) ac_f="$ac_tmp/stdin";; *) # Look for the file first in the build tree, then in the source tree # (if the path is not absolute). The absolute path cannot be DOS-style, # because $ac_f cannot contain `:'. test -f "$ac_f" || case $ac_f in [\\/$]*) false;; *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; esac || as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;; esac case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac as_fn_append ac_file_inputs " '$ac_f'" done # 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. */ configure_input='Generated from '` $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' `' by configure.' if test x"$ac_file" != x-; then configure_input="$ac_file. $configure_input" { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 $as_echo "$as_me: creating $ac_file" >&6;} fi # Neutralize special characters interpreted by sed in replacement strings. case $configure_input in #( *\&* | *\|* | *\\* ) ac_sed_conf_input=`$as_echo "$configure_input" | sed 's/[\\\\&|]/\\\\&/g'`;; #( *) ac_sed_conf_input=$configure_input;; esac case $ac_tag in *:-:* | *:-) cat >"$ac_tmp/stdin" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; esac ;; esac ac_dir=`$as_dirname -- "$ac_file" || $as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$ac_file" : 'X\(//\)[^/]' \| \ X"$ac_file" : 'X\(//\)$' \| \ X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$ac_file" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` as_dir="$ac_dir"; as_fn_mkdir_p ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix case $ac_mode in :F) # # CONFIG_FILE # _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # If the template does not know about datarootdir, expand it. # FIXME: This hack should be removed a few years after 2.60. ac_datarootdir_hack=; ac_datarootdir_seen= ac_sed_dataroot=' /datarootdir/ { p q } /@datadir@/p /@docdir@/p /@infodir@/p /@localedir@/p /@mandir@/p' case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in *datarootdir*) ac_datarootdir_seen=yes;; *@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 $as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_datarootdir_hack=' s&@datadir@&$datadir&g s&@docdir@&$docdir&g s&@infodir@&$infodir&g s&@localedir@&$localedir&g s&@mandir@&$mandir&g s&\\\${datarootdir}&$datarootdir&g' ;; esac _ACEOF # Neutralize VPATH when `$srcdir' = `.'. # Shell code in configure.ac might set extrasub. # FIXME: do we really want to maintain this feature? cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_sed_extra="$ac_vpsub $extrasub _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 :t /@[a-zA-Z_][a-zA-Z_0-9]*@/!b s|@configure_input@|$ac_sed_conf_input|;t t s&@top_builddir@&$ac_top_builddir_sub&;t t s&@top_build_prefix@&$ac_top_build_prefix&;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&@abs_top_builddir@&$ac_abs_top_builddir&;t t $ac_datarootdir_hack " eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \ >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5 test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } && { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \ "$ac_tmp/out"`; test -z "$ac_out"; } && { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined" >&5 $as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined" >&2;} rm -f "$ac_tmp/stdin" case $ac_file in -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";; *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";; esac \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; :H) # # CONFIG_HEADER # if test x"$ac_file" != x-; then { $as_echo "/* $configure_input */" \ && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" } >"$ac_tmp/config.h" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 if diff "$ac_file" "$ac_tmp/config.h" >/dev/null 2>&1; then { $as_echo "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5 $as_echo "$as_me: $ac_file is unchanged" >&6;} else rm -f "$ac_file" mv "$ac_tmp/config.h" "$ac_file" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 fi else $as_echo "/* $configure_input */" \ && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" \ || as_fn_error $? "could not create -" "$LINENO" 5 fi ;; esac done # for ac_tag as_fn_exit 0 _ACEOF ac_clean_files=$ac_clean_files_save test $ac_write_fail = 0 || as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5 # 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 || as_fn_exit 1 fi if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} fi htmldoc-1.9.7/configure.ac000066400000000000000000000261061354715574200154720ustar00rootroot00000000000000# # Configuration script for HTMLDOC, an HTML document processing program. # # Copyright © 2011-2019 by Michael R Sweet. # Copyright © 1997-2010 by Easy Software Products. # # This program is free software. Distribution and use rights are outlined in # the file "COPYING". # AC_INIT([HTMLDOC], [1.9.7], [https://github.com/michaelrsweet/htmldoc/issues], [htmldoc], [https://michaelrsweet.github.io/htmldoc]) AC_CONFIG_HEADER(config.h) dnl Define the version number... SVERSION="AC_PACKAGE_VERSION" AC_SUBST(SVERSION) AC_DEFINE_UNQUOTED(SVERSION, "$SVERSION") dnl Get the operating system and version number... uname=`uname` uversion=`uname -r | sed -e '1,$s/[[^0-9]]//g'` if test "$uname" = "IRIX64"; then uname="IRIX" fi dnl Clear the debugging options unless the user asks for them... INSTALL_STRIP="-s" AC_SUBST(INSTALL_STRIP) OPTIM="${OPTIM:=}" AC_SUBST(OPTIM) CFLAGS="${CFLAGS:=}" CXXFLAGS="${CXXFLAGS:=}" LDFLAGS="${LDFLAGS:=}" AC_ARG_ENABLE(debug, [ --enable-debug turn on debugging, default=no], [if eval "test x$enable_debug = xyes"; then INSTALL_STRIP="" OPTIM="-g " fi]) AC_ARG_WITH(gui, [ --without-gui do not compile the GUI version of HTMLDOC, default=yes]) dnl Checks for programs... AC_PROG_AWK AC_PROG_CC(clang cc gcc) AC_PROG_CXX(clang++ c++ g++) AC_PROG_CPP AC_PROG_RANLIB AC_PATH_PROG(AR,ar) AC_PATH_PROG(CHMOD,chmod) AC_PATH_PROG(CP,cp) AC_PATH_PROG(FLTKCONFIG,fltk-config) AC_MSG_CHECKING(for install-sh script) INSTALL="`pwd`/install-sh" AC_SUBST(INSTALL) AC_MSG_RESULT(using $INSTALL) AC_PATH_PROG(MV,mv) AC_PATH_PROG(MKDIR,mkdir) AC_PATH_PROG(RM,rm) AC_PATH_TOOL(PKGCONFIG, pkg-config) dnl See if we need a .exe extension on executables... AC_EXEEXT dnl Figure out the correct "ar" command flags... if test "$ac_cv_prog_ranlib" = ":"; then ARFLAGS="crs" else ARFLAGS="cr" fi AC_SUBST(ARFLAGS) dnl Checks for header files. AC_HEADER_STDC AC_CHECK_HEADER(strings.h, AC_DEFINE(HAVE_STRINGS_H)) AC_CHECK_HEADER(locale.h, AC_DEFINE(HAVE_LOCALE_H)) dnl Checks for string functions. AC_CHECK_FUNCS(strdup strcasecmp strncasecmp strlcat strlcpy) if test "$uname" = "HP-UX" -a "$uversion" = "1020"; then AC_MSG_WARN(Forcing snprintf emulation for HP-UX...) else AC_CHECK_FUNCS(snprintf vsnprintf) fi dnl Check for random number functions... AC_CHECK_FUNCS(random lrand48 arc4random) dnl See if the tm structure has the tm_gmtoff member... AC_MSG_CHECKING(for tm_gmtoff member in tm structure) AC_TRY_COMPILE([#include ],[struct tm t; int o = t.tm_gmtoff;], AC_MSG_RESULT(yes) AC_DEFINE(HAVE_TM_GMTOFF), AC_MSG_RESULT(no)) dnl Check for libraries... LDFLAGS="${LDFLAGS:=}" AC_SUBST(LDFLAGS) AC_CHECK_LIB(m,pow) AC_CHECK_FUNC(poll, AC_DEFINE(HAVE_POLL)) AC_SEARCH_LIBS(socket, socket) AC_SEARCH_LIBS(gethostbyaddr, nsl) AC_SEARCH_LIBS(getaddrinfo, nsl, AC_DEFINE(HAVE_GETADDRINFO)) AC_SEARCH_LIBS(getnameinfo, nsl, AC_DEFINE(HAVE_GETNAMEINFO)) AC_SEARCH_LIBS(hstrerror, nsl socket resolv, AC_DEFINE(HAVE_HSTRERROR)) AC_SEARCH_LIBS(__res_init, resolv bind, AC_DEFINE(HAVE_RES_INIT), AC_SEARCH_LIBS(res_9_init, resolv bind, AC_DEFINE(HAVE_RES_INIT), AC_SEARCH_LIBS(res_init, resolv bind, AC_DEFINE(HAVE_RES_INIT)))) AC_CHECK_HEADER(resolv.h, AC_DEFINE(HAVE_RESOLV_H)) dnl Check for largefile support... AC_SYS_LARGEFILE dnl Define largefile options as needed... LARGEFILE="" if test x$enable_largefile != xno; then LARGEFILE="-D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE" if test x$ac_cv_sys_large_files = x1; then LARGEFILE="$LARGEFILE -D_LARGE_FILES" fi if test x$ac_cv_sys_file_offset_bits = x64; then LARGEFILE="$LARGEFILE -D_FILE_OFFSET_BITS=64" fi fi AC_SUBST(LARGEFILE) dnl Check for "long long" support... AC_CACHE_CHECK(for long long int, ac_cv_c_long_long, [if test "$GCC" = yes; then ac_cv_c_long_long=yes else AC_TRY_COMPILE(,[long long int i;], ac_cv_c_long_long=yes, ac_cv_c_long_long=no) fi]) if test $ac_cv_c_long_long = yes; then AC_DEFINE(HAVE_LONG_LONG) fi AC_CHECK_FUNC(strtoll, AC_DEFINE(HAVE_STRTOLL)) dnl Check for TLS/SSL libraries... AC_ARG_ENABLE(ssl, [ --enable-ssl turn on SSL/TLS support, default=yes]) AC_ARG_ENABLE(gnutls, [ --enable-gnutls use GNU TLS for SSL/TLS support, default=yes]) AC_ARG_ENABLE(cdsassl, [ --enable-cdsassl use CDSA for SSL/TLS support, default=yes]) SSLFLAGS="" SSLLIBS="" have_ssl=0 if test x$enable_ssl != xno; then dnl Look for CDSA... if test $have_ssl = 0 -a "x$enable_cdsassl" != "xno"; then if test $uname = Darwin; then AC_CHECK_HEADER(Security/SecureTransport.h, [ have_ssl=1 AC_DEFINE(HAVE_SSL) AC_DEFINE(HAVE_CDSASSL) SSLLIBS="-framework Security -framework CoreFoundation" AC_CHECK_HEADER(Security/SecureTransportPriv.h, AC_DEFINE(HAVE_SECURETRANSPORTPRIV_H)) AC_CHECK_HEADER(Security/SecCertificate.h, AC_DEFINE(HAVE_SECCERTIFICATE_H)) AC_CHECK_HEADER(Security/SecItem.h, AC_DEFINE(HAVE_SECITEM_H)) AC_CHECK_HEADER(Security/SecItemPriv.h, AC_DEFINE(HAVE_SECITEMPRIV_H),, [#include ]) AC_CHECK_HEADER(Security/SecPolicy.h, AC_DEFINE(HAVE_SECPOLICY_H)) AC_CHECK_HEADER(Security/SecPolicyPriv.h, AC_DEFINE(HAVE_SECPOLICYPRIV_H)) AC_CHECK_HEADER(Security/SecBasePriv.h, AC_DEFINE(HAVE_SECBASEPRIV_H)) AC_CHECK_HEADER(Security/SecIdentitySearchPriv.h, AC_DEFINE(HAVE_SECIDENTITYSEARCHPRIV_H)) AC_DEFINE(HAVE_CSSMERRORSTRING) AC_DEFINE(HAVE_SECKEYCHAINOPEN)]) if test $uversion -ge 150; then AC_DEFINE(HAVE_SSLSETENABLEDCIPHERS) fi fi fi dnl Then look for GNU TLS... if test $have_ssl = 0 -a "x$enable_gnutls" != "xno" -a "x$PKGCONFIG" != x; then AC_PATH_TOOL(LIBGNUTLSCONFIG,libgnutls-config) AC_PATH_TOOL(LIBGCRYPTCONFIG,libgcrypt-config) if $PKGCONFIG --exists gnutls; then have_ssl=1 SSLLIBS=`$PKGCONFIG --libs gnutls` SSLFLAGS=`$PKGCONFIG --cflags gnutls` AC_DEFINE(HAVE_SSL) AC_DEFINE(HAVE_GNUTLS) elif test "x$LIBGNUTLSCONFIG" != x; then have_ssl=1 SSLLIBS=`$LIBGNUTLSCONFIG --libs` SSLFLAGS=`$LIBGNUTLSCONFIG --cflags` AC_DEFINE(HAVE_SSL) AC_DEFINE(HAVE_GNUTLS) fi if test $have_ssl = 1; then SAVELIBS="$LIBS" LIBS="$LIBS $SSLLIBS" AC_CHECK_FUNC(gnutls_transport_set_pull_timeout_function, AC_DEFINE(HAVE_GNUTLS_TRANSPORT_SET_PULL_TIMEOUT_FUNCTION)) AC_CHECK_FUNC(gnutls_priority_set_direct, AC_DEFINE(HAVE_GNUTLS_PRIORITY_SET_DIRECT)) LIBS="$SAVELIBS" fi fi fi AC_MSG_NOTICE([Using SSLFLAGS="$SSLFLAGS", SSLLIBS="$SSLLIBS"]) AC_SUBST(SSLFLAGS) AC_SUBST(SSLLIBS) dnl Check for GUI libraries... POST=: if test "x$with_gui" != xno; then if test "x$FLTKCONFIG" != x; then LIBS="$LIBS `$FLTKCONFIG --use-images --ldflags`" AC_DEFINE(HAVE_LIBFLTK) POST="$FLTKCONFIG --post" AC_CHECK_LIB(Xpm,XpmCreatePixmapFromData) AC_CHECK_LIB(X11,XCreateBitmapFromData) else AC_MSG_WARN(FLTK not available so no GUI will be built.) fi fi AC_SUBST(POST) dnl Check for image libraries... NEWLIBS="" AC_ARG_ENABLE(localjpeg, [ --enable-localjpeg use local JPEG library, default=auto]) if test x$enable_localjpeg = xyes; then AC_MSG_CHECKING([for library containing jpeg_CreateCompress]) AC_MSG_RESULT([local libjpeg]) JPEGINC="-I../jpeg" JPEG="jpeg" NEWLIBS="../jpeg/libjpeg.a $NEWLIBS" else AC_SEARCH_LIBS(jpeg_CreateCompress,turbojpeg jpeg, JPEGINC="" JPEG="", JPEGINC="-I../jpeg" JPEG="jpeg" NEWLIBS="../jpeg/libjpeg.a $NEWLIBS") fi AC_ARG_ENABLE(localzlib, [ --enable-localzlib use local ZLIB library, default=auto]) if test x$enable_localzlib = xyes; then AC_MSG_CHECKING([for library containing gzgets]) AC_MSG_RESULT([local libz]) ZLIBINC="-I../zlib" ZLIB="zlib" NEWLIBS="../zlib/libz.a $NEWLIBS" else AC_SEARCH_LIBS(gzgets,z, ZLIBINC="" ZLIB="", ZLIBINC="-I../zlib" ZLIB="zlib" NEWLIBS="../zlib/libz.a $NEWLIBS") fi AC_ARG_ENABLE(localpng, [ --enable-localpng use local PNG library, default=auto]) if test x$enable_localpng = xyes; then AC_MSG_CHECKING([for library containing png_set_tRNS_to_alpha]) AC_MSG_RESULT([local libpng]) PNGINC="-I../png" PNG="png" NEWLIBS="../png/libpng.a $NEWLIBS" else AC_SEARCH_LIBS(png_set_tRNS_to_alpha,png, PNGINC="" PNG="", PNGINC="-I../png" PNG="png" NEWLIBS="../png/libpng.a $NEWLIBS") fi AC_SUBST(JPEG) AC_SUBST(JPEGINC) AC_SUBST(PNG) AC_SUBST(PNGINC) AC_SUBST(ZLIB) AC_SUBST(ZLIBINC) AC_DEFINE(HAVE_LIBJPEG) AC_DEFINE(HAVE_LIBPNG) AC_DEFINE(HAVE_LIBZ) LIBS="$NEWLIBS $LIBS" dnl Directories for config.h... if test "$prefix" = "NONE"; then prefix="/usr/local" fi if test "$exec_prefix" = "NONE"; then exec_prefix="$prefix" fi if test "$bindir" = "\${exec_prefix}/bin"; then bindir="$exec_prefix/bin" fi dnl Fix "datarootdir" variable if it hasn't been specified... if test "$datarootdir" = "\${prefix}/share"; then if test "$prefix" = "/"; then datarootdir="/usr/share" else datarootdir="$prefix/share" fi fi dnl Fix "datadir" variable if it hasn't been specified... if test "$datadir" = "\${prefix}/share"; then if test "$prefix" = "/"; then datadir="/usr/share" else datadir="$prefix/share" fi elif test "$datadir" = "\${datarootdir}"; then datadir="$datarootdir" fi AC_DEFINE_UNQUOTED(DOCUMENTATION, "$datadir/doc/htmldoc") AC_DEFINE_UNQUOTED(HTML_DATA, "$datadir/htmldoc") dnl Update compiler options... AC_ARG_ENABLE(sanitizer, [ --enable-sanitizer build with AddressSanitizer]) if test -n "$GXX"; then if test x$enable_sanitizer = xyes; then # Use -fsanitize=address with debugging... OPTIM="$OPTIM -g -fsanitize=address" else # Otherwise use the Fortify enhancements to catch any unbounded # string operations... CFLAGS="$CFLAGS -D_FORTIFY_SOURCE=2" CXXFLAGS="$CXXFLAGS -D_FORTIFY_SOURCE=2" fi dnl Set optimization flags... if test -z "$OPTIM"; then OPTIM="-Os -g" fi dnl Show all standard warnings + unused variables when compiling... OPTIM="-Wall -Wunused -Wno-char-subscripts -Wno-format-y2k $OPTIM" dnl See if GCC supports -fno-rtti... AC_MSG_CHECKING(if GCC supports -fno-rtti) OLDCFLAGS="$CFLAGS" CFLAGS="$CFLAGS -fno-rtti" AC_TRY_COMPILE(,, CXXFLAGS="$CXXFLAGS -fno-rtti" AC_MSG_RESULT(yes), AC_MSG_RESULT(no)) CFLAGS="$OLDCFLAGS" dnl See if GCC supports -fno-exceptions... AC_MSG_CHECKING(if GCC supports -fno-exceptions) OLDCFLAGS="$CFLAGS" CFLAGS="$CFLAGS -fno-exceptions" AC_TRY_COMPILE(,, CXXFLAGS="$CXXFLAGS -fno-exceptions" AC_MSG_RESULT(yes), AC_MSG_RESULT(no)) CFLAGS="$OLDCFLAGS" dnl See if we are running Solaris; if so, try the -fpermissive option... if test "$uname" = SunOS; then AC_MSG_CHECKING(if GCC supports -fpermissive) OLDCFLAGS="$CFLAGS" CFLAGS="$CFLAGS -fpermissive" AC_TRY_COMPILE(,, CXXFLAGS="$CXXFLAGS -fpermissive" AC_MSG_RESULT(yes), AC_MSG_RESULT(no)) CFLAGS="$OLDCFLAGS" fi fi if test "x$with_gui" != xno; then if test "x$FLTKCONFIG" != x; then OPTIM="`$FLTKCONFIG --cflags` $OPTIM" fi fi dnl Generate the top-level Makefile and Makedefs file... AC_OUTPUT(Makedefs Makefile desktop/htmldoc.plist) htmldoc-1.9.7/data/000077500000000000000000000000001354715574200141105ustar00rootroot00000000000000htmldoc-1.9.7/data/Makefile000066400000000000000000000015371354715574200155560ustar00rootroot00000000000000# # Makefile for HTMLDOC data files. # # Copyright 2011-2017 by Michael R Sweet. # Copyright 1997-2010 by Easy Software Products. # # This program is free software. Distribution and use rights are outlined in # the file "COPYING". # # # Include common definitions... # include ../Makedefs # # Character set/glyph files... # FILES = cp-1250 cp-1251 cp-1252 cp-1253 cp-1254 cp-1255 \ cp-1256 cp-1257 cp-1258 cp-874 \ iso-8859-1 iso-8859-14 iso-8859-15 iso-8859-2 iso-8859-3 \ iso-8859-4 iso-8859-5 iso-8859-6 iso-8859-7 iso-8859-8 \ iso-8859-9 \ koi8-r prolog.ps psglyphs # # Make everything... # all: # # Install everything... # install: $(INSTALL_DIR) $(BUILDROOT)$(datadir)/htmldoc/data for file in $(FILES); do \ $(INSTALL_DATA) $$file $(BUILDROOT)$(datadir)/htmldoc/data; \ done # # Clean out object and library files... # clean: htmldoc-1.9.7/data/cp-1250000066400000000000000000000033301354715574200150210ustar00rootroot0000000000000020 0020 21 0021 22 0022 23 0023 24 0024 25 0025 26 0026 27 0027 28 0028 29 0029 2A 002A 2B 002B 2C 002C 2D 002D 2E 002E 2F 002F 30 0030 31 0031 32 0032 33 0033 34 0034 35 0035 36 0036 37 0037 38 0038 39 0039 3A 003A 3B 003B 3C 003C 3D 003D 3E 003E 3F 003F 40 0040 41 0041 42 0042 43 0043 44 0044 45 0045 46 0046 47 0047 48 0048 49 0049 4A 004A 4B 004B 4C 004C 4D 004D 4E 004E 4F 004F 50 0050 51 0051 52 0052 53 0053 54 0054 55 0055 56 0056 57 0057 58 0058 59 0059 5A 005A 5B 005B 5C 005C 5D 005D 5E 005E 5F 005F 60 0060 61 0061 62 0062 63 0063 64 0064 65 0065 66 0066 67 0067 68 0068 69 0069 6A 006A 6B 006B 6C 006C 6D 006D 6E 006E 6F 006F 70 0070 71 0071 72 0072 73 0073 74 0074 75 0075 76 0076 77 0077 78 0078 79 0079 7A 007A 7B 007B 7C 007C 7D 007D 7E 007E 7F 007F 80 20AC 82 201A 84 201E 85 2026 86 2020 87 2021 89 2030 8A 0160 8B 2039 8C 015A 8D 0164 8E 017D 8F 0179 91 2018 92 2019 93 201C 94 201D 95 2022 96 2013 97 2014 99 2122 9A 0161 9B 203A 9C 015B 9D 0165 9E 017E 9F 017A A0 00A0 A1 02C7 A2 02D8 A3 0141 A4 00A4 A5 0104 A6 00A6 A7 00A7 A8 00A8 A9 00A9 AA 015E AB 00AB AC 00AC AD 00AD AE 00AE AF 017B B0 00B0 B1 00B1 B2 02DB B3 0142 B4 00B4 B5 00B5 B6 00B6 B7 00B7 B8 00B8 B9 0105 BA 015F BB 00BB BC 013D BD 02DD BE 013E BF 017C C0 0154 C1 00C1 C2 00C2 C3 0102 C4 00C4 C5 0139 C6 0106 C7 00C7 C8 010C C9 00C9 CA 0118 CB 00CB CC 011A CD 00CD CE 00CE CF 010E D0 0110 D1 0143 D2 0147 D3 00D3 D4 00D4 D5 0150 D6 00D6 D7 00D7 D8 0158 D9 016E DA 00DA DB 0170 DC 00DC DD 00DD DE 0162 DF 00DF E0 0155 E1 00E1 E2 00E2 E3 0103 E4 00E4 E5 013A E6 0107 E7 00E7 E8 010D E9 00E9 EA 0119 EB 00EB EC 011B ED 00ED EE 00EE EF 010F F0 0111 F1 0144 F2 0148 F3 00F3 F4 00F4 F5 0151 F6 00F6 F7 00F7 F8 0159 F9 016F FA 00FA FB 0171 FC 00FC FD 00FD FE 0163 FF 02D9 htmldoc-1.9.7/data/cp-1251000066400000000000000000000033701354715574200150260ustar00rootroot0000000000000020 0020 21 0021 22 0022 23 0023 24 0024 25 0025 26 0026 27 0027 28 0028 29 0029 2A 002A 2B 002B 2C 002C 2D 002D 2E 002E 2F 002F 30 0030 31 0031 32 0032 33 0033 34 0034 35 0035 36 0036 37 0037 38 0038 39 0039 3A 003A 3B 003B 3C 003C 3D 003D 3E 003E 3F 003F 40 0040 41 0041 42 0042 43 0043 44 0044 45 0045 46 0046 47 0047 48 0048 49 0049 4A 004A 4B 004B 4C 004C 4D 004D 4E 004E 4F 004F 50 0050 51 0051 52 0052 53 0053 54 0054 55 0055 56 0056 57 0057 58 0058 59 0059 5A 005A 5B 005B 5C 005C 5D 005D 5E 005E 5F 005F 60 0060 61 0061 62 0062 63 0063 64 0064 65 0065 66 0066 67 0067 68 0068 69 0069 6A 006A 6B 006B 6C 006C 6D 006D 6E 006E 6F 006F 70 0070 71 0071 72 0072 73 0073 74 0074 75 0075 76 0076 77 0077 78 0078 79 0079 7A 007A 7B 007B 7C 007C 7D 007D 7E 007E 7F 007F 80 0402 81 0403 82 201A 83 0453 84 201E 85 2026 86 2020 87 2021 88 20AC 89 2030 8A 0409 8B 2039 8C 040A 8D 040C 8E 040B 8F 040F 90 0452 91 2018 92 2019 93 201C 94 201D 95 2022 96 2013 97 2014 99 2122 9A 0459 9B 203A 9C 045A 9D 045C 9E 045B 9F 045F A0 00A0 A1 040E A2 045E A3 0408 A4 00A4 A5 0490 A6 00A6 A7 00A7 A8 0401 A9 00A9 AA 0404 AB 00AB AC 00AC AD 00AD AE 00AE AF 0407 B0 00B0 B1 00B1 B2 0406 B3 0456 B4 0491 B5 00B5 B6 00B6 B7 00B7 B8 0451 B9 2116 BA 0454 BB 00BB BC 0458 BD 0405 BE 0455 BF 0457 C0 0410 C1 0411 C2 0412 C3 0413 C4 0414 C5 0415 C6 0416 C7 0417 C8 0418 C9 0419 CA 041A CB 041B CC 041C CD 041D CE 041E CF 041F D0 0420 D1 0421 D2 0422 D3 0423 D4 0424 D5 0425 D6 0426 D7 0427 D8 0428 D9 0429 DA 042A DB 042B DC 042C DD 042D DE 042E DF 042F E0 0430 E1 0431 E2 0432 E3 0433 E4 0434 E5 0435 E6 0436 E7 0437 E8 0438 E9 0439 EA 043A EB 043B EC 043C ED 043D EE 043E EF 043F F0 0440 F1 0441 F2 0442 F3 0443 F4 0444 F5 0445 F6 0446 F7 0447 F8 0448 F9 0449 FA 044A FB 044B FC 044C FD 044D FE 044E FF 044F htmldoc-1.9.7/data/cp-1252000066400000000000000000000033301354715574200150230ustar00rootroot0000000000000020 0020 21 0021 22 0022 23 0023 24 0024 25 0025 26 0026 27 0027 28 0028 29 0029 2A 002A 2B 002B 2C 002C 2D 002D 2E 002E 2F 002F 30 0030 31 0031 32 0032 33 0033 34 0034 35 0035 36 0036 37 0037 38 0038 39 0039 3A 003A 3B 003B 3C 003C 3D 003D 3E 003E 3F 003F 40 0040 41 0041 42 0042 43 0043 44 0044 45 0045 46 0046 47 0047 48 0048 49 0049 4A 004A 4B 004B 4C 004C 4D 004D 4E 004E 4F 004F 50 0050 51 0051 52 0052 53 0053 54 0054 55 0055 56 0056 57 0057 58 0058 59 0059 5A 005A 5B 005B 5C 005C 5D 005D 5E 005E 5F 005F 60 0060 61 0061 62 0062 63 0063 64 0064 65 0065 66 0066 67 0067 68 0068 69 0069 6A 006A 6B 006B 6C 006C 6D 006D 6E 006E 6F 006F 70 0070 71 0071 72 0072 73 0073 74 0074 75 0075 76 0076 77 0077 78 0078 79 0079 7A 007A 7B 007B 7C 007C 7D 007D 7E 007E 7F 007F 80 20AC 82 201A 83 0192 84 201E 85 2026 86 2020 87 2021 88 02C6 89 2030 8A 0160 8B 2039 8C 0152 8E 017D 91 2018 92 2019 93 201C 94 201D 95 2022 96 2013 97 2014 98 02DC 99 2122 9A 0161 9B 203A 9C 0153 9E 017E 9F 0178 A0 00A0 A1 00A1 A2 00A2 A3 00A3 A4 00A4 A5 00A5 A6 00A6 A7 00A7 A8 00A8 A9 00A9 AA 00AA AB 00AB AC 00AC AD 00AD AE 00AE AF 00AF B0 00B0 B1 00B1 B2 00B2 B3 00B3 B4 00B4 B5 00B5 B6 00B6 B7 00B7 B8 00B8 B9 00B9 BA 00BA BB 00BB BC 00BC BD 00BD BE 00BE BF 00BF C0 00C0 C1 00C1 C2 00C2 C3 00C3 C4 00C4 C5 00C5 C6 00C6 C7 00C7 C8 00C8 C9 00C9 CA 00CA CB 00CB CC 00CC CD 00CD CE 00CE CF 00CF D0 00D0 D1 00D1 D2 00D2 D3 00D3 D4 00D4 D5 00D5 D6 00D6 D7 00D7 D8 00D8 D9 00D9 DA 00DA DB 00DB DC 00DC DD 00DD DE 00DE DF 00DF E0 00E0 E1 00E1 E2 00E2 E3 00E3 E4 00E4 E5 00E5 E6 00E6 E7 00E7 E8 00E8 E9 00E9 EA 00EA EB 00EB EC 00EC ED 00ED EE 00EE EF 00EF F0 00F0 F1 00F1 F2 00F2 F3 00F3 F4 00F4 F5 00F5 F6 00F6 F7 00F7 F8 00F8 F9 00F9 FA 00FA FB 00FB FC 00FC FD 00FD FE 00FE FF 00FF htmldoc-1.9.7/data/cp-1253000066400000000000000000000031701354715574200150260ustar00rootroot0000000000000020 0020 21 0021 22 0022 23 0023 24 0024 25 0025 26 0026 27 0027 28 0028 29 0029 2A 002A 2B 002B 2C 002C 2D 002D 2E 002E 2F 002F 30 0030 31 0031 32 0032 33 0033 34 0034 35 0035 36 0036 37 0037 38 0038 39 0039 3A 003A 3B 003B 3C 003C 3D 003D 3E 003E 3F 003F 40 0040 41 0041 42 0042 43 0043 44 0044 45 0045 46 0046 47 0047 48 0048 49 0049 4A 004A 4B 004B 4C 004C 4D 004D 4E 004E 4F 004F 50 0050 51 0051 52 0052 53 0053 54 0054 55 0055 56 0056 57 0057 58 0058 59 0059 5A 005A 5B 005B 5C 005C 5D 005D 5E 005E 5F 005F 60 0060 61 0061 62 0062 63 0063 64 0064 65 0065 66 0066 67 0067 68 0068 69 0069 6A 006A 6B 006B 6C 006C 6D 006D 6E 006E 6F 006F 70 0070 71 0071 72 0072 73 0073 74 0074 75 0075 76 0076 77 0077 78 0078 79 0079 7A 007A 7B 007B 7C 007C 7D 007D 7E 007E 7F 007F 80 20AC 82 201A 83 0192 84 201E 85 2026 86 2020 87 2021 89 2030 8B 2039 91 2018 92 2019 93 201C 94 201D 95 2022 96 2013 97 2014 99 2122 9B 203A A0 00A0 A1 0385 A2 0386 A3 00A3 A4 00A4 A5 00A5 A6 00A6 A7 00A7 A8 00A8 A9 00A9 AB 00AB AC 00AC AD 00AD AE 00AE AF 2015 B0 00B0 B1 00B1 B2 00B2 B3 00B3 B4 0384 B5 00B5 B6 00B6 B7 00B7 B8 0388 B9 0389 BA 038A BB 00BB BC 038C BD 00BD BE 038E BF 038F C0 0390 C1 0391 C2 0392 C3 0393 C4 0394 C5 0395 C6 0396 C7 0397 C8 0398 C9 0399 CA 039A CB 039B CC 039C CD 039D CE 039E CF 039F D0 03A0 D1 03A1 D3 03A3 D4 03A4 D5 03A5 D6 03A6 D7 03A7 D8 03A8 D9 03A9 DA 03AA DB 03AB DC 03AC DD 03AD DE 03AE DF 03AF E0 03B0 E1 03B1 E2 03B2 E3 03B3 E4 03B4 E5 03B5 E6 03B6 E7 03B7 E8 03B8 E9 03B9 EA 03BA EB 03BB EC 03BC ED 03BD EE 03BE EF 03BF F0 03C0 F1 03C1 F2 03C2 F3 03C3 F4 03C4 F5 03C5 F6 03C6 F7 03C7 F8 03C8 F9 03C9 FA 03CA FB 03CB FC 03CC FD 03CD FE 03CE htmldoc-1.9.7/data/cp-1254000066400000000000000000000033101354715574200150230ustar00rootroot0000000000000020 0020 21 0021 22 0022 23 0023 24 0024 25 0025 26 0026 27 0027 28 0028 29 0029 2A 002A 2B 002B 2C 002C 2D 002D 2E 002E 2F 002F 30 0030 31 0031 32 0032 33 0033 34 0034 35 0035 36 0036 37 0037 38 0038 39 0039 3A 003A 3B 003B 3C 003C 3D 003D 3E 003E 3F 003F 40 0040 41 0041 42 0042 43 0043 44 0044 45 0045 46 0046 47 0047 48 0048 49 0049 4A 004A 4B 004B 4C 004C 4D 004D 4E 004E 4F 004F 50 0050 51 0051 52 0052 53 0053 54 0054 55 0055 56 0056 57 0057 58 0058 59 0059 5A 005A 5B 005B 5C 005C 5D 005D 5E 005E 5F 005F 60 0060 61 0061 62 0062 63 0063 64 0064 65 0065 66 0066 67 0067 68 0068 69 0069 6A 006A 6B 006B 6C 006C 6D 006D 6E 006E 6F 006F 70 0070 71 0071 72 0072 73 0073 74 0074 75 0075 76 0076 77 0077 78 0078 79 0079 7A 007A 7B 007B 7C 007C 7D 007D 7E 007E 7F 007F 80 20AC 82 201A 83 0192 84 201E 85 2026 86 2020 87 2021 88 02C6 89 2030 8A 0160 8B 2039 8C 0152 91 2018 92 2019 93 201C 94 201D 95 2022 96 2013 97 2014 98 02DC 99 2122 9A 0161 9B 203A 9C 0153 9F 0178 A0 00A0 A1 00A1 A2 00A2 A3 00A3 A4 00A4 A5 00A5 A6 00A6 A7 00A7 A8 00A8 A9 00A9 AA 00AA AB 00AB AC 00AC AD 00AD AE 00AE AF 00AF B0 00B0 B1 00B1 B2 00B2 B3 00B3 B4 00B4 B5 00B5 B6 00B6 B7 00B7 B8 00B8 B9 00B9 BA 00BA BB 00BB BC 00BC BD 00BD BE 00BE BF 00BF C0 00C0 C1 00C1 C2 00C2 C3 00C3 C4 00C4 C5 00C5 C6 00C6 C7 00C7 C8 00C8 C9 00C9 CA 00CA CB 00CB CC 00CC CD 00CD CE 00CE CF 00CF D0 011E D1 00D1 D2 00D2 D3 00D3 D4 00D4 D5 00D5 D6 00D6 D7 00D7 D8 00D8 D9 00D9 DA 00DA DB 00DB DC 00DC DD 0130 DE 015E DF 00DF E0 00E0 E1 00E1 E2 00E2 E3 00E3 E4 00E4 E5 00E5 E6 00E6 E7 00E7 E8 00E8 E9 00E9 EA 00EA EB 00EB EC 00EC ED 00ED EE 00EE EF 00EF F0 011F F1 00F1 F2 00F2 F3 00F3 F4 00F4 F5 00F5 F6 00F6 F7 00F7 F8 00F8 F9 00F9 FA 00FA FB 00FB FC 00FC FD 0131 FE 015F FF 00FF htmldoc-1.9.7/data/cp-1255000066400000000000000000000031101354715574200150220ustar00rootroot0000000000000020 0020 21 0021 22 0022 23 0023 24 0024 25 0025 26 0026 27 0027 28 0028 29 0029 2A 002A 2B 002B 2C 002C 2D 002D 2E 002E 2F 002F 30 0030 31 0031 32 0032 33 0033 34 0034 35 0035 36 0036 37 0037 38 0038 39 0039 3A 003A 3B 003B 3C 003C 3D 003D 3E 003E 3F 003F 40 0040 41 0041 42 0042 43 0043 44 0044 45 0045 46 0046 47 0047 48 0048 49 0049 4A 004A 4B 004B 4C 004C 4D 004D 4E 004E 4F 004F 50 0050 51 0051 52 0052 53 0053 54 0054 55 0055 56 0056 57 0057 58 0058 59 0059 5A 005A 5B 005B 5C 005C 5D 005D 5E 005E 5F 005F 60 0060 61 0061 62 0062 63 0063 64 0064 65 0065 66 0066 67 0067 68 0068 69 0069 6A 006A 6B 006B 6C 006C 6D 006D 6E 006E 6F 006F 70 0070 71 0071 72 0072 73 0073 74 0074 75 0075 76 0076 77 0077 78 0078 79 0079 7A 007A 7B 007B 7C 007C 7D 007D 7E 007E 7F 007F 80 20AC 82 201A 83 0192 84 201E 85 2026 86 2020 87 2021 88 02C6 89 2030 8B 2039 91 2018 92 2019 93 201C 94 201D 95 2022 96 2013 97 2014 98 02DC 99 2122 9B 203A A0 00A0 A1 00A1 A2 00A2 A3 00A3 A4 20AA A5 00A5 A6 00A6 A7 00A7 A8 00A8 A9 00A9 AA 00D7 AB 00AB AC 00AC AD 00AD AE 00AE AF 00AF B0 00B0 B1 00B1 B2 00B2 B3 00B3 B4 00B4 B5 00B5 B6 00B6 B7 00B7 B8 00B8 B9 00B9 BA 00F7 BB 00BB BC 00BC BD 00BD BE 00BE BF 00BF C0 05B0 C1 05B1 C2 05B2 C3 05B3 C4 05B4 C5 05B5 C6 05B6 C7 05B7 C8 05B8 C9 05B9 CB 05BB CC 05BC CD 05BD CE 05BE CF 05BF D0 05C0 D1 05C1 D2 05C2 D3 05C3 D4 05F0 D5 05F1 D6 05F2 D7 05F3 D8 05F4 E0 05D0 E1 05D1 E2 05D2 E3 05D3 E4 05D4 E5 05D5 E6 05D6 E7 05D7 E8 05D8 E9 05D9 EA 05DA EB 05DB EC 05DC ED 05DD EE 05DE EF 05DF F0 05E0 F1 05E1 F2 05E2 F3 05E3 F4 05E4 F5 05E5 F6 05E6 F7 05E7 F8 05E8 F9 05E9 FA 05EA FD 200E FE 200F htmldoc-1.9.7/data/cp-1256000066400000000000000000000034001354715574200150250ustar00rootroot0000000000000020 0020 21 0021 22 0022 23 0023 24 0024 25 0025 26 0026 27 0027 28 0028 29 0029 2A 002A 2B 002B 2C 002C 2D 002D 2E 002E 2F 002F 30 0030 31 0031 32 0032 33 0033 34 0034 35 0035 36 0036 37 0037 38 0038 39 0039 3A 003A 3B 003B 3C 003C 3D 003D 3E 003E 3F 003F 40 0040 41 0041 42 0042 43 0043 44 0044 45 0045 46 0046 47 0047 48 0048 49 0049 4A 004A 4B 004B 4C 004C 4D 004D 4E 004E 4F 004F 50 0050 51 0051 52 0052 53 0053 54 0054 55 0055 56 0056 57 0057 58 0058 59 0059 5A 005A 5B 005B 5C 005C 5D 005D 5E 005E 5F 005F 60 0060 61 0061 62 0062 63 0063 64 0064 65 0065 66 0066 67 0067 68 0068 69 0069 6A 006A 6B 006B 6C 006C 6D 006D 6E 006E 6F 006F 70 0070 71 0071 72 0072 73 0073 74 0074 75 0075 76 0076 77 0077 78 0078 79 0079 7A 007A 7B 007B 7C 007C 7D 007D 7E 007E 7F 007F 80 20AC 81 067E 82 201A 83 0192 84 201E 85 2026 86 2020 87 2021 88 02C6 89 2030 8A 0679 8B 2039 8C 0152 8D 0686 8E 0698 8F 0688 90 06AF 91 2018 92 2019 93 201C 94 201D 95 2022 96 2013 97 2014 98 06A9 99 2122 9A 0691 9B 203A 9C 0153 9D 200C 9E 200D 9F 06BA A0 00A0 A1 060C A2 00A2 A3 00A3 A4 00A4 A5 00A5 A6 00A6 A7 00A7 A8 00A8 A9 00A9 AA 06BE AB 00AB AC 00AC AD 00AD AE 00AE AF 00AF B0 00B0 B1 00B1 B2 00B2 B3 00B3 B4 00B4 B5 00B5 B6 00B6 B7 00B7 B8 00B8 B9 00B9 BA 061B BB 00BB BC 00BC BD 00BD BE 00BE BF 061F C0 06C1 C1 0621 C2 0622 C3 0623 C4 0624 C5 0625 C6 0626 C7 0627 C8 0628 C9 0629 CA 062A CB 062B CC 062C CD 062D CE 062E CF 062F D0 0630 D1 0631 D2 0632 D3 0633 D4 0634 D5 0635 D6 0636 D7 00D7 D8 0637 D9 0638 DA 0639 DB 063A DC 0640 DD 0641 DE 0642 DF 0643 E0 00E0 E1 0644 E2 00E2 E3 0645 E4 0646 E5 0647 E6 0648 E7 00E7 E8 00E8 E9 00E9 EA 00EA EB 00EB EC 0649 ED 064A EE 00EE EF 00EF F0 064B F1 064C F2 064D F3 064E F4 00F4 F5 064F F6 0650 F7 00F7 F8 0651 F9 00F9 FA 0652 FB 00FB FC 00FC FD 200E FE 200F FF 06D2 htmldoc-1.9.7/data/cp-1257000066400000000000000000000032401354715574200150300ustar00rootroot0000000000000020 0020 21 0021 22 0022 23 0023 24 0024 25 0025 26 0026 27 0027 28 0028 29 0029 2A 002A 2B 002B 2C 002C 2D 002D 2E 002E 2F 002F 30 0030 31 0031 32 0032 33 0033 34 0034 35 0035 36 0036 37 0037 38 0038 39 0039 3A 003A 3B 003B 3C 003C 3D 003D 3E 003E 3F 003F 40 0040 41 0041 42 0042 43 0043 44 0044 45 0045 46 0046 47 0047 48 0048 49 0049 4A 004A 4B 004B 4C 004C 4D 004D 4E 004E 4F 004F 50 0050 51 0051 52 0052 53 0053 54 0054 55 0055 56 0056 57 0057 58 0058 59 0059 5A 005A 5B 005B 5C 005C 5D 005D 5E 005E 5F 005F 60 0060 61 0061 62 0062 63 0063 64 0064 65 0065 66 0066 67 0067 68 0068 69 0069 6A 006A 6B 006B 6C 006C 6D 006D 6E 006E 6F 006F 70 0070 71 0071 72 0072 73 0073 74 0074 75 0075 76 0076 77 0077 78 0078 79 0079 7A 007A 7B 007B 7C 007C 7D 007D 7E 007E 7F 007F 80 20AC 82 201A 84 201E 85 2026 86 2020 87 2021 89 2030 8B 2039 8D 00A8 8E 02C7 8F 00B8 91 2018 92 2019 93 201C 94 201D 95 2022 96 2013 97 2014 99 2122 9B 203A 9D 00AF 9E 02DB A0 00A0 A2 00A2 A3 00A3 A4 00A4 A6 00A6 A7 00A7 A8 00D8 A9 00A9 AA 0156 AB 00AB AC 00AC AD 00AD AE 00AE AF 00C6 B0 00B0 B1 00B1 B2 00B2 B3 00B3 B4 00B4 B5 00B5 B6 00B6 B7 00B7 B8 00F8 B9 00B9 BA 0157 BB 00BB BC 00BC BD 00BD BE 00BE BF 00E6 C0 0104 C1 012E C2 0100 C3 0106 C4 00C4 C5 00C5 C6 0118 C7 0112 C8 010C C9 00C9 CA 0179 CB 0116 CC 0122 CD 0136 CE 012A CF 013B D0 0160 D1 0143 D2 0145 D3 00D3 D4 014C D5 00D5 D6 00D6 D7 00D7 D8 0172 D9 0141 DA 015A DB 016A DC 00DC DD 017B DE 017D DF 00DF E0 0105 E1 012F E2 0101 E3 0107 E4 00E4 E5 00E5 E6 0119 E7 0113 E8 010D E9 00E9 EA 017A EB 0117 EC 0123 ED 0137 EE 012B EF 013C F0 0161 F1 0144 F2 0146 F3 00F3 F4 014D F5 00F5 F6 00F6 F7 00F7 F8 0173 F9 0142 FA 015B FB 016B FC 00FC FD 017C FE 017E FF 02D9 htmldoc-1.9.7/data/cp-1258000066400000000000000000000032701354715574200150340ustar00rootroot0000000000000020 0020 21 0021 22 0022 23 0023 24 0024 25 0025 26 0026 27 0027 28 0028 29 0029 2A 002A 2B 002B 2C 002C 2D 002D 2E 002E 2F 002F 30 0030 31 0031 32 0032 33 0033 34 0034 35 0035 36 0036 37 0037 38 0038 39 0039 3A 003A 3B 003B 3C 003C 3D 003D 3E 003E 3F 003F 40 0040 41 0041 42 0042 43 0043 44 0044 45 0045 46 0046 47 0047 48 0048 49 0049 4A 004A 4B 004B 4C 004C 4D 004D 4E 004E 4F 004F 50 0050 51 0051 52 0052 53 0053 54 0054 55 0055 56 0056 57 0057 58 0058 59 0059 5A 005A 5B 005B 5C 005C 5D 005D 5E 005E 5F 005F 60 0060 61 0061 62 0062 63 0063 64 0064 65 0065 66 0066 67 0067 68 0068 69 0069 6A 006A 6B 006B 6C 006C 6D 006D 6E 006E 6F 006F 70 0070 71 0071 72 0072 73 0073 74 0074 75 0075 76 0076 77 0077 78 0078 79 0079 7A 007A 7B 007B 7C 007C 7D 007D 7E 007E 7F 007F 80 20AC 82 201A 83 0192 84 201E 85 2026 86 2020 87 2021 88 02C6 89 2030 8B 2039 8C 0152 91 2018 92 2019 93 201C 94 201D 95 2022 96 2013 97 2014 98 02DC 99 2122 9B 203A 9C 0153 9F 0178 A0 00A0 A1 00A1 A2 00A2 A3 00A3 A4 00A4 A5 00A5 A6 00A6 A7 00A7 A8 00A8 A9 00A9 AA 00AA AB 00AB AC 00AC AD 00AD AE 00AE AF 00AF B0 00B0 B1 00B1 B2 00B2 B3 00B3 B4 00B4 B5 00B5 B6 00B6 B7 00B7 B8 00B8 B9 00B9 BA 00BA BB 00BB BC 00BC BD 00BD BE 00BE BF 00BF C0 00C0 C1 00C1 C2 00C2 C3 0102 C4 00C4 C5 00C5 C6 00C6 C7 00C7 C8 00C8 C9 00C9 CA 00CA CB 00CB CC 0300 CD 00CD CE 00CE CF 00CF D0 0110 D1 00D1 D2 0309 D3 00D3 D4 00D4 D5 01A0 D6 00D6 D7 00D7 D8 00D8 D9 00D9 DA 00DA DB 00DB DC 00DC DD 01AF DE 0303 DF 00DF E0 00E0 E1 00E1 E2 00E2 E3 0103 E4 00E4 E5 00E5 E6 00E6 E7 00E7 E8 00E8 E9 00E9 EA 00EA EB 00EB EC 0301 ED 00ED EE 00EE EF 00EF F0 0111 F1 00F1 F2 0323 F3 00F3 F4 00F4 F5 01A1 F6 00F6 F7 00F7 F8 00F8 F9 00F9 FA 00FA FB 00FB FC 00FC FD 01B0 FE 20AB FF 00FF htmldoc-1.9.7/data/cp-874000066400000000000000000000030101354715574200147470ustar00rootroot0000000000000020 0020 21 0021 22 0022 23 0023 24 0024 25 0025 26 0026 27 0027 28 0028 29 0029 2A 002A 2B 002B 2C 002C 2D 002D 2E 002E 2F 002F 30 0030 31 0031 32 0032 33 0033 34 0034 35 0035 36 0036 37 0037 38 0038 39 0039 3A 003A 3B 003B 3C 003C 3D 003D 3E 003E 3F 003F 40 0040 41 0041 42 0042 43 0043 44 0044 45 0045 46 0046 47 0047 48 0048 49 0049 4A 004A 4B 004B 4C 004C 4D 004D 4E 004E 4F 004F 50 0050 51 0051 52 0052 53 0053 54 0054 55 0055 56 0056 57 0057 58 0058 59 0059 5A 005A 5B 005B 5C 005C 5D 005D 5E 005E 5F 005F 60 0060 61 0061 62 0062 63 0063 64 0064 65 0065 66 0066 67 0067 68 0068 69 0069 6A 006A 6B 006B 6C 006C 6D 006D 6E 006E 6F 006F 70 0070 71 0071 72 0072 73 0073 74 0074 75 0075 76 0076 77 0077 78 0078 79 0079 7A 007A 7B 007B 7C 007C 7D 007D 7E 007E 7F 007F 80 20AC 85 2026 91 2018 92 2019 93 201C 94 201D 95 2022 96 2013 97 2014 A0 00A0 A1 0E01 A2 0E02 A3 0E03 A4 0E04 A5 0E05 A6 0E06 A7 0E07 A8 0E08 A9 0E09 AA 0E0A AB 0E0B AC 0E0C AD 0E0D AE 0E0E AF 0E0F B0 0E10 B1 0E11 B2 0E12 B3 0E13 B4 0E14 B5 0E15 B6 0E16 B7 0E17 B8 0E18 B9 0E19 BA 0E1A BB 0E1B BC 0E1C BD 0E1D BE 0E1E BF 0E1F C0 0E20 C1 0E21 C2 0E22 C3 0E23 C4 0E24 C5 0E25 C6 0E26 C7 0E27 C8 0E28 C9 0E29 CA 0E2A CB 0E2B CC 0E2C CD 0E2D CE 0E2E CF 0E2F D0 0E30 D1 0E31 D2 0E32 D3 0E33 D4 0E34 D5 0E35 D6 0E36 D7 0E37 D8 0E38 D9 0E39 DA 0E3A DF 0E3F E0 0E40 E1 0E41 E2 0E42 E3 0E43 E4 0E44 E5 0E45 E6 0E46 E7 0E47 E8 0E48 E9 0E49 EA 0E4A EB 0E4B EC 0E4C ED 0E4D EE 0E4E EF 0E4F F0 0E50 F1 0E51 F2 0E52 F3 0E53 F4 0E54 F5 0E55 F6 0E56 F7 0E57 F8 0E58 F9 0E59 FA 0E5A FB 0E5B htmldoc-1.9.7/data/iso-8859-1000066400000000000000000000043641354715574200154050ustar00rootroot000000000000000x20 0x0020 0x21 0x0021 0x22 0x0022 0x23 0x0023 0x24 0x0024 0x25 0x0025 0x26 0x0026 0x27 0x0027 0x28 0x0028 0x29 0x0029 0x2a 0x002a 0x2b 0x002b 0x2c 0x002c 0x2d 0x002d 0x2e 0x002e 0x2f 0x002f 0x30 0x0030 0x31 0x0031 0x32 0x0032 0x33 0x0033 0x34 0x0034 0x35 0x0035 0x36 0x0036 0x37 0x0037 0x38 0x0038 0x39 0x0039 0x3a 0x003a 0x3b 0x003b 0x3c 0x003c 0x3d 0x003d 0x3e 0x003e 0x3f 0x003f 0x40 0x0040 0x41 0x0041 0x42 0x0042 0x43 0x0043 0x44 0x0044 0x45 0x0045 0x46 0x0046 0x47 0x0047 0x48 0x0048 0x49 0x0049 0x4a 0x004a 0x4b 0x004b 0x4c 0x004c 0x4d 0x004d 0x4e 0x004e 0x4f 0x004f 0x50 0x0050 0x51 0x0051 0x52 0x0052 0x53 0x0053 0x54 0x0054 0x55 0x0055 0x56 0x0056 0x57 0x0057 0x58 0x0058 0x59 0x0059 0x5a 0x005a 0x5b 0x005b 0x5c 0x005c 0x5d 0x005d 0x5e 0x005e 0x5f 0x005f 0x60 0x0060 0x61 0x0061 0x62 0x0062 0x63 0x0063 0x64 0x0064 0x65 0x0065 0x66 0x0066 0x67 0x0067 0x68 0x0068 0x69 0x0069 0x6a 0x006a 0x6b 0x006b 0x6c 0x006c 0x6d 0x006d 0x6e 0x006e 0x6f 0x006f 0x70 0x0070 0x71 0x0071 0x72 0x0072 0x73 0x0073 0x74 0x0074 0x75 0x0075 0x76 0x0076 0x77 0x0077 0x78 0x0078 0x79 0x0079 0x7a 0x007a 0x7b 0x007b 0x7c 0x007c 0x7d 0x007d 0x7e 0x007e 0xa0 0x00a0 0xa1 0x00a1 0xa2 0x00a2 0xa3 0x00a3 0xa4 0x00a4 0xa5 0x00a5 0xa6 0x00a6 0xa7 0x00a7 0xa8 0x00a8 0xa9 0x00a9 0xaa 0x00aa 0xab 0x00ab 0xac 0x00ac 0xad 0x00ad 0xae 0x00ae 0xaf 0x00af 0xb0 0x00b0 0xb1 0x00b1 0xb2 0x00b2 0xb3 0x00b3 0xb4 0x00b4 0xb5 0x00b5 0xb6 0x00b6 0xb7 0x00b7 0xb8 0x00b8 0xb9 0x00b9 0xba 0x00ba 0xbb 0x00bb 0xbc 0x00bc 0xbd 0x00bd 0xbe 0x00be 0xbf 0x00bf 0xc0 0x00c0 0xc1 0x00c1 0xc2 0x00c2 0xc3 0x00c3 0xc4 0x00c4 0xc5 0x00c5 0xc6 0x00c6 0xc7 0x00c7 0xc8 0x00c8 0xc9 0x00c9 0xca 0x00ca 0xcb 0x00cb 0xcc 0x00cc 0xcd 0x00cd 0xce 0x00ce 0xcf 0x00cf 0xd0 0x00d0 0xd1 0x00d1 0xd2 0x00d2 0xd3 0x00d3 0xd4 0x00d4 0xd5 0x00d5 0xd6 0x00d6 0xd7 0x00d7 0xd8 0x00d8 0xd9 0x00d9 0xda 0x00da 0xdb 0x00db 0xdc 0x00dc 0xdd 0x00dd 0xde 0x00de 0xdf 0x00df 0xe0 0x00e0 0xe1 0x00e1 0xe2 0x00e2 0xe3 0x00e3 0xe4 0x00e4 0xe5 0x00e5 0xe6 0x00e6 0xe7 0x00e7 0xe8 0x00e8 0xe9 0x00e9 0xea 0x00ea 0xeb 0x00eb 0xec 0x00ec 0xed 0x00ed 0xee 0x00ee 0xef 0x00ef 0xf0 0x00f0 0xf1 0x00f1 0xf2 0x00f2 0xf3 0x00f3 0xf4 0x00f4 0xf5 0x00f5 0xf6 0x00f6 0xf7 0x00f7 0xf8 0x00f8 0xf9 0x00f9 0xfa 0x00fa 0xfb 0x00fb 0xfc 0x00fc 0xfd 0x00fd 0xfe 0x00fe 0xff 0x00ff htmldoc-1.9.7/data/iso-8859-14000066400000000000000000000043661354715574200154730ustar00rootroot000000000000000x20 0x0020 0x21 0x0021 0x22 0x0022 0x23 0x0023 0x24 0x0024 0x25 0x0025 0x26 0x0026 0x27 0x0027 0x28 0x0028 0x29 0x0029 0x2a 0x002a 0x2b 0x002b 0x2c 0x002c 0x2d 0x002d 0x2e 0x002e 0x2f 0x002f 0x30 0x0030 0x31 0x0031 0x32 0x0032 0x33 0x0033 0x34 0x0034 0x35 0x0035 0x36 0x0036 0x37 0x0037 0x38 0x0038 0x39 0x0039 0x3a 0x003a 0x3b 0x003b 0x3c 0x003c 0x3d 0x003d 0x3e 0x003e 0x3f 0x003f 0x40 0x0040 0x41 0x0041 0x42 0x0042 0x43 0x0043 0x44 0x0044 0x45 0x0045 0x46 0x0046 0x47 0x0047 0x48 0x0048 0x49 0x0049 0x4a 0x004a 0x4b 0x004b 0x4c 0x004c 0x4d 0x004d 0x4e 0x004e 0x4f 0x004f 0x50 0x0050 0x51 0x0051 0x52 0x0052 0x53 0x0053 0x54 0x0054 0x55 0x0055 0x56 0x0056 0x57 0x0057 0x58 0x0058 0x59 0x0059 0x5a 0x005a 0x5b 0x005b 0x5c 0x005c 0x5d 0x005d 0x5e 0x005e 0x5f 0x005f 0x60 0x0060 0x61 0x0061 0x62 0x0062 0x63 0x0063 0x64 0x0064 0x65 0x0065 0x66 0x0066 0x67 0x0067 0x68 0x0068 0x69 0x0069 0x6a 0x006a 0x6b 0x006b 0x6c 0x006c 0x6d 0x006d 0x6e 0x006e 0x6f 0x006f 0x70 0x0070 0x71 0x0071 0x72 0x0072 0x73 0x0073 0x74 0x0074 0x75 0x0075 0x76 0x0076 0x77 0x0077 0x78 0x0078 0x79 0x0079 0x7a 0x007a 0x7b 0x007b 0x7c 0x007c 0x7d 0x007d 0x7e 0x007e 0xa0 0x00a0 0xa1 0x1e02 0xa2 0x1e03 0xa3 0x00a3 0xa4 0x010a 0xa5 0x010b 0xa6 0x1e0a 0xa7 0x00a7 0xa8 0x1e80 0xa9 0x00a9 0xaa 0x1e82 0xab 0x1e0b 0xac 0x1ef2 0xad 0x00ad 0xae 0x00ae 0xaf 0x0178 0xb0 0x1e1e 0xb1 0x1e1f 0xb2 0x0120 0xb3 0x0121 0xb4 0x1e40 0xb5 0x1e41 0xb6 0x00b6 0xb7 0x1e56 0xb8 0x1e81 0xb9 0x1e57 0xba 0x1e83 0xbb 0x1e60 0xbc 0x1ef3 0xbd 0x1e84 0xbe 0x1e85 0xbf 0x1e61 0xc0 0x00c0 0xc1 0x00c1 0xc2 0x00c2 0xc3 0x00c3 0xc4 0x00c4 0xc5 0x00c5 0xc6 0x00c6 0xc7 0x00c7 0xc8 0x00c8 0xc9 0x00c9 0xca 0x00ca 0xcb 0x00cb 0xcc 0x00cc 0xcd 0x00cd 0xce 0x00ce 0xcf 0x00cf 0xd0 0x0174 0xd1 0x00d1 0xd2 0x00d2 0xd3 0x00d3 0xd4 0x00d4 0xd5 0x00d5 0xd6 0x00d6 0xd7 0x1e6a 0xd8 0x00d8 0xd9 0x00d9 0xda 0x00da 0xdb 0x00db 0xdc 0x00dc 0xdd 0x00dd 0xde 0x0176 0xdf 0x00df 0xe0 0x00e0 0xe1 0x00e1 0xe2 0x00e2 0xe3 0x00e3 0xe4 0x00e4 0xe5 0x00e5 0xe6 0x00e6 0xe7 0x00e7 0xe8 0x00e8 0xe9 0x00e9 0xea 0x00ea 0xeb 0x00eb 0xec 0x00ec 0xed 0x00ed 0xee 0x00ee 0xef 0x00ef 0xf0 0x0175 0xf1 0x00f1 0xf2 0x00f2 0xf3 0x00f3 0xf4 0x00f4 0xf5 0x00f5 0xf6 0x00f6 0xf7 0x1e6b 0xf8 0x00f8 0xf9 0x00f9 0xfa 0x00fa 0xfb 0x00fb 0xfc 0x00fc 0xfd 0x00fd 0xfe 0x0177 0xff 0x00ff htmldoc-1.9.7/data/iso-8859-15000066400000000000000000000043661354715574200154740ustar00rootroot000000000000000x20 0x0020 0x21 0x0021 0x22 0x0022 0x23 0x0023 0x24 0x0024 0x25 0x0025 0x26 0x0026 0x27 0x0027 0x28 0x0028 0x29 0x0029 0x2a 0x002a 0x2b 0x002b 0x2c 0x002c 0x2d 0x002d 0x2e 0x002e 0x2f 0x002f 0x30 0x0030 0x31 0x0031 0x32 0x0032 0x33 0x0033 0x34 0x0034 0x35 0x0035 0x36 0x0036 0x37 0x0037 0x38 0x0038 0x39 0x0039 0x3a 0x003a 0x3b 0x003b 0x3c 0x003c 0x3d 0x003d 0x3e 0x003e 0x3f 0x003f 0x40 0x0040 0x41 0x0041 0x42 0x0042 0x43 0x0043 0x44 0x0044 0x45 0x0045 0x46 0x0046 0x47 0x0047 0x48 0x0048 0x49 0x0049 0x4a 0x004a 0x4b 0x004b 0x4c 0x004c 0x4d 0x004d 0x4e 0x004e 0x4f 0x004f 0x50 0x0050 0x51 0x0051 0x52 0x0052 0x53 0x0053 0x54 0x0054 0x55 0x0055 0x56 0x0056 0x57 0x0057 0x58 0x0058 0x59 0x0059 0x5a 0x005a 0x5b 0x005b 0x5c 0x005c 0x5d 0x005d 0x5e 0x005e 0x5f 0x005f 0x60 0x0060 0x61 0x0061 0x62 0x0062 0x63 0x0063 0x64 0x0064 0x65 0x0065 0x66 0x0066 0x67 0x0067 0x68 0x0068 0x69 0x0069 0x6a 0x006a 0x6b 0x006b 0x6c 0x006c 0x6d 0x006d 0x6e 0x006e 0x6f 0x006f 0x70 0x0070 0x71 0x0071 0x72 0x0072 0x73 0x0073 0x74 0x0074 0x75 0x0075 0x76 0x0076 0x77 0x0077 0x78 0x0078 0x79 0x0079 0x7a 0x007a 0x7b 0x007b 0x7c 0x007c 0x7d 0x007d 0x7e 0x007e 0xa0 0x00a0 0xa1 0x00a1 0xa2 0x00a2 0xa3 0x00a3 0xa4 0x20ac 0xa5 0x00a5 0xa6 0x0160 0xa7 0x00a7 0xa8 0x0161 0xa9 0x00a9 0xaa 0x00aa 0xab 0x00ab 0xac 0x00ac 0xad 0x00ad 0xae 0x00ae 0xaf 0x00af 0xb0 0x00b0 0xb1 0x00b1 0xb2 0x00b2 0xb3 0x00b3 0xb4 0x017d 0xb5 0x00b5 0xb6 0x00b6 0xb7 0x00b7 0xb8 0x017e 0xb9 0x00b9 0xba 0x00ba 0xbb 0x00bb 0xbc 0x0152 0xbd 0x0153 0xbe 0x0178 0xbf 0x00bf 0xc0 0x00c0 0xc1 0x00c1 0xc2 0x00c2 0xc3 0x00c3 0xc4 0x00c4 0xc5 0x00c5 0xc6 0x00c6 0xc7 0x00c7 0xc8 0x00c8 0xc9 0x00c9 0xca 0x00ca 0xcb 0x00cb 0xcc 0x00cc 0xcd 0x00cd 0xce 0x00ce 0xcf 0x00cf 0xd0 0x00d0 0xd1 0x00d1 0xd2 0x00d2 0xd3 0x00d3 0xd4 0x00d4 0xd5 0x00d5 0xd6 0x00d6 0xd7 0x00d7 0xd8 0x00d8 0xd9 0x00d9 0xda 0x00da 0xdb 0x00db 0xdc 0x00dc 0xdd 0x00dd 0xde 0x00de 0xdf 0x00df 0xe0 0x00e0 0xe1 0x00e1 0xe2 0x00e2 0xe3 0x00e3 0xe4 0x00e4 0xe5 0x00e5 0xe6 0x00e6 0xe7 0x00e7 0xe8 0x00e8 0xe9 0x00e9 0xea 0x00ea 0xeb 0x00eb 0xec 0x00ec 0xed 0x00ed 0xee 0x00ee 0xef 0x00ef 0xf0 0x00f0 0xf1 0x00f1 0xf2 0x00f2 0xf3 0x00f3 0xf4 0x00f4 0xf5 0x00f5 0xf6 0x00f6 0xf7 0x00f7 0xf8 0x00f8 0xf9 0x00f9 0xfa 0x00fa 0xfb 0x00fb 0xfc 0x00fc 0xfd 0x00fd 0xfe 0x00fe 0xff 0x00ff htmldoc-1.9.7/data/iso-8859-2000066400000000000000000000043641354715574200154060ustar00rootroot000000000000000x20 0x0020 0x21 0x0021 0x22 0x0022 0x23 0x0023 0x24 0x0024 0x25 0x0025 0x26 0x0026 0x27 0x0027 0x28 0x0028 0x29 0x0029 0x2a 0x002a 0x2b 0x002b 0x2c 0x002c 0x2d 0x002d 0x2e 0x002e 0x2f 0x002f 0x30 0x0030 0x31 0x0031 0x32 0x0032 0x33 0x0033 0x34 0x0034 0x35 0x0035 0x36 0x0036 0x37 0x0037 0x38 0x0038 0x39 0x0039 0x3a 0x003a 0x3b 0x003b 0x3c 0x003c 0x3d 0x003d 0x3e 0x003e 0x3f 0x003f 0x40 0x0040 0x41 0x0041 0x42 0x0042 0x43 0x0043 0x44 0x0044 0x45 0x0045 0x46 0x0046 0x47 0x0047 0x48 0x0048 0x49 0x0049 0x4a 0x004a 0x4b 0x004b 0x4c 0x004c 0x4d 0x004d 0x4e 0x004e 0x4f 0x004f 0x50 0x0050 0x51 0x0051 0x52 0x0052 0x53 0x0053 0x54 0x0054 0x55 0x0055 0x56 0x0056 0x57 0x0057 0x58 0x0058 0x59 0x0059 0x5a 0x005a 0x5b 0x005b 0x5c 0x005c 0x5d 0x005d 0x5e 0x005e 0x5f 0x005f 0x60 0x0060 0x61 0x0061 0x62 0x0062 0x63 0x0063 0x64 0x0064 0x65 0x0065 0x66 0x0066 0x67 0x0067 0x68 0x0068 0x69 0x0069 0x6a 0x006a 0x6b 0x006b 0x6c 0x006c 0x6d 0x006d 0x6e 0x006e 0x6f 0x006f 0x70 0x0070 0x71 0x0071 0x72 0x0072 0x73 0x0073 0x74 0x0074 0x75 0x0075 0x76 0x0076 0x77 0x0077 0x78 0x0078 0x79 0x0079 0x7a 0x007a 0x7b 0x007b 0x7c 0x007c 0x7d 0x007d 0x7e 0x007e 0xa0 0x00a0 0xa1 0x0104 0xa2 0x02d8 0xa3 0x0141 0xa4 0x00a4 0xa5 0x013d 0xa6 0x015a 0xa7 0x00a7 0xa8 0x00a8 0xa9 0x0160 0xaa 0x015e 0xab 0x0164 0xac 0x0179 0xad 0x00ad 0xae 0x017d 0xaf 0x017b 0xb0 0x00b0 0xb1 0x0105 0xb2 0x02db 0xb3 0x0142 0xb4 0x00b4 0xb5 0x013e 0xb6 0x015b 0xb7 0x02c7 0xb8 0x00b8 0xb9 0x0161 0xba 0x015f 0xbb 0x0165 0xbc 0x017a 0xbd 0x02dd 0xbe 0x017e 0xbf 0x017c 0xc0 0x0154 0xc1 0x00c1 0xc2 0x00c2 0xc3 0x0102 0xc4 0x00c4 0xc5 0x0139 0xc6 0x0106 0xc7 0x00c7 0xc8 0x010c 0xc9 0x00c9 0xca 0x0118 0xcb 0x00cb 0xcc 0x011a 0xcd 0x00cd 0xce 0x00ce 0xcf 0x010e 0xd0 0x0110 0xd1 0x0143 0xd2 0x0147 0xd3 0x00d3 0xd4 0x00d4 0xd5 0x0150 0xd6 0x00d6 0xd7 0x00d7 0xd8 0x0158 0xd9 0x016e 0xda 0x00da 0xdb 0x0170 0xdc 0x00dc 0xdd 0x00dd 0xde 0x0162 0xdf 0x00df 0xe0 0x0155 0xe1 0x00e1 0xe2 0x00e2 0xe3 0x0103 0xe4 0x00e4 0xe5 0x013a 0xe6 0x0107 0xe7 0x00e7 0xe8 0x010d 0xe9 0x00e9 0xea 0x0119 0xeb 0x00eb 0xec 0x011b 0xed 0x00ed 0xee 0x00ee 0xef 0x010f 0xf0 0x0111 0xf1 0x0144 0xf2 0x0148 0xf3 0x00f3 0xf4 0x00f4 0xf5 0x0151 0xf6 0x00f6 0xf7 0x00f7 0xf8 0x0159 0xf9 0x016f 0xfa 0x00fa 0xfb 0x0171 0xfc 0x00fc 0xfd 0x00fd 0xfe 0x0163 0xff 0x02d9 htmldoc-1.9.7/data/iso-8859-3000066400000000000000000000042401354715574200154000ustar00rootroot000000000000000x20 0x0020 0x21 0x0021 0x22 0x0022 0x23 0x0023 0x24 0x0024 0x25 0x0025 0x26 0x0026 0x27 0x0027 0x28 0x0028 0x29 0x0029 0x2a 0x002a 0x2b 0x002b 0x2c 0x002c 0x2d 0x002d 0x2e 0x002e 0x2f 0x002f 0x30 0x0030 0x31 0x0031 0x32 0x0032 0x33 0x0033 0x34 0x0034 0x35 0x0035 0x36 0x0036 0x37 0x0037 0x38 0x0038 0x39 0x0039 0x3a 0x003a 0x3b 0x003b 0x3c 0x003c 0x3d 0x003d 0x3e 0x003e 0x3f 0x003f 0x40 0x0040 0x41 0x0041 0x42 0x0042 0x43 0x0043 0x44 0x0044 0x45 0x0045 0x46 0x0046 0x47 0x0047 0x48 0x0048 0x49 0x0049 0x4a 0x004a 0x4b 0x004b 0x4c 0x004c 0x4d 0x004d 0x4e 0x004e 0x4f 0x004f 0x50 0x0050 0x51 0x0051 0x52 0x0052 0x53 0x0053 0x54 0x0054 0x55 0x0055 0x56 0x0056 0x57 0x0057 0x58 0x0058 0x59 0x0059 0x5a 0x005a 0x5b 0x005b 0x5c 0x005c 0x5d 0x005d 0x5e 0x005e 0x5f 0x005f 0x60 0x0060 0x61 0x0061 0x62 0x0062 0x63 0x0063 0x64 0x0064 0x65 0x0065 0x66 0x0066 0x67 0x0067 0x68 0x0068 0x69 0x0069 0x6a 0x006a 0x6b 0x006b 0x6c 0x006c 0x6d 0x006d 0x6e 0x006e 0x6f 0x006f 0x70 0x0070 0x71 0x0071 0x72 0x0072 0x73 0x0073 0x74 0x0074 0x75 0x0075 0x76 0x0076 0x77 0x0077 0x78 0x0078 0x79 0x0079 0x7a 0x007a 0x7b 0x007b 0x7c 0x007c 0x7d 0x007d 0x7e 0x007e 0xa0 0x00a0 0xa1 0x0126 0xa2 0x02d8 0xa3 0x00a3 0xa4 0x00a4 0xa6 0x0124 0xa7 0x00a7 0xa8 0x00a8 0xa9 0x0130 0xaa 0x015e 0xab 0x011e 0xac 0x0134 0xad 0x00ad 0xaf 0x017b 0xb0 0x00b0 0xb1 0x0127 0xb2 0x00b2 0xb3 0x00b3 0xb4 0x00b4 0xb5 0x00b5 0xb6 0x0125 0xb7 0x00b7 0xb8 0x00b8 0xb9 0x0131 0xba 0x015f 0xbb 0x011f 0xbc 0x0135 0xbd 0x00bd 0xbf 0x017c 0xc0 0x00c0 0xc1 0x00c1 0xc2 0x00c2 0xc4 0x00c4 0xc5 0x010a 0xc6 0x0108 0xc7 0x00c7 0xc8 0x00c8 0xc9 0x00c9 0xca 0x00ca 0xcb 0x00cb 0xcc 0x00cc 0xcd 0x00cd 0xce 0x00ce 0xcf 0x00cf 0xd1 0x00d1 0xd2 0x00d2 0xd3 0x00d3 0xd4 0x00d4 0xd5 0x0120 0xd6 0x00d6 0xd7 0x00d7 0xd8 0x011c 0xd9 0x00d9 0xda 0x00da 0xdb 0x00db 0xdc 0x00dc 0xdd 0x016c 0xde 0x015c 0xdf 0x00df 0xe0 0x00e0 0xe1 0x00e1 0xe2 0x00e2 0xe4 0x00e4 0xe5 0x010b 0xe6 0x0109 0xe7 0x00e7 0xe8 0x00e8 0xe9 0x00e9 0xea 0x00ea 0xeb 0x00eb 0xec 0x00ec 0xed 0x00ed 0xee 0x00ee 0xef 0x00ef 0xf1 0x00f1 0xf2 0x00f2 0xf3 0x00f3 0xf4 0x00f4 0xf5 0x0121 0xf6 0x00f6 0xf7 0x00f7 0xf8 0x011d 0xf9 0x00f9 0xfa 0x00fa 0xfb 0x00fb 0xfc 0x00fc 0xfd 0x016d 0xfe 0x015d 0xff 0x02d9 htmldoc-1.9.7/data/iso-8859-4000066400000000000000000000043641354715574200154100ustar00rootroot000000000000000x20 0x0020 0x21 0x0021 0x22 0x0022 0x23 0x0023 0x24 0x0024 0x25 0x0025 0x26 0x0026 0x27 0x0027 0x28 0x0028 0x29 0x0029 0x2a 0x002a 0x2b 0x002b 0x2c 0x002c 0x2d 0x002d 0x2e 0x002e 0x2f 0x002f 0x30 0x0030 0x31 0x0031 0x32 0x0032 0x33 0x0033 0x34 0x0034 0x35 0x0035 0x36 0x0036 0x37 0x0037 0x38 0x0038 0x39 0x0039 0x3a 0x003a 0x3b 0x003b 0x3c 0x003c 0x3d 0x003d 0x3e 0x003e 0x3f 0x003f 0x40 0x0040 0x41 0x0041 0x42 0x0042 0x43 0x0043 0x44 0x0044 0x45 0x0045 0x46 0x0046 0x47 0x0047 0x48 0x0048 0x49 0x0049 0x4a 0x004a 0x4b 0x004b 0x4c 0x004c 0x4d 0x004d 0x4e 0x004e 0x4f 0x004f 0x50 0x0050 0x51 0x0051 0x52 0x0052 0x53 0x0053 0x54 0x0054 0x55 0x0055 0x56 0x0056 0x57 0x0057 0x58 0x0058 0x59 0x0059 0x5a 0x005a 0x5b 0x005b 0x5c 0x005c 0x5d 0x005d 0x5e 0x005e 0x5f 0x005f 0x60 0x0060 0x61 0x0061 0x62 0x0062 0x63 0x0063 0x64 0x0064 0x65 0x0065 0x66 0x0066 0x67 0x0067 0x68 0x0068 0x69 0x0069 0x6a 0x006a 0x6b 0x006b 0x6c 0x006c 0x6d 0x006d 0x6e 0x006e 0x6f 0x006f 0x70 0x0070 0x71 0x0071 0x72 0x0072 0x73 0x0073 0x74 0x0074 0x75 0x0075 0x76 0x0076 0x77 0x0077 0x78 0x0078 0x79 0x0079 0x7a 0x007a 0x7b 0x007b 0x7c 0x007c 0x7d 0x007d 0x7e 0x007e 0xa0 0x00a0 0xa1 0x0104 0xa2 0x0138 0xa3 0x0156 0xa4 0x00a4 0xa5 0x0128 0xa6 0x013b 0xa7 0x00a7 0xa8 0x00a8 0xa9 0x0160 0xaa 0x0112 0xab 0x0122 0xac 0x0166 0xad 0x00ad 0xae 0x017d 0xaf 0x00af 0xb0 0x00b0 0xb1 0x0105 0xb2 0x02db 0xb3 0x0157 0xb4 0x00b4 0xb5 0x0129 0xb6 0x013c 0xb7 0x02c7 0xb8 0x00b8 0xb9 0x0161 0xba 0x0113 0xbb 0x0123 0xbc 0x0167 0xbd 0x014a 0xbe 0x017e 0xbf 0x014b 0xc0 0x0100 0xc1 0x00c1 0xc2 0x00c2 0xc3 0x00c3 0xc4 0x00c4 0xc5 0x00c5 0xc6 0x00c6 0xc7 0x012e 0xc8 0x010c 0xc9 0x00c9 0xca 0x0118 0xcb 0x00cb 0xcc 0x0116 0xcd 0x00cd 0xce 0x00ce 0xcf 0x012a 0xd0 0x0110 0xd1 0x0145 0xd2 0x014c 0xd3 0x0136 0xd4 0x00d4 0xd5 0x00d5 0xd6 0x00d6 0xd7 0x00d7 0xd8 0x00d8 0xd9 0x0172 0xda 0x00da 0xdb 0x00db 0xdc 0x00dc 0xdd 0x0168 0xde 0x016a 0xdf 0x00df 0xe0 0x0101 0xe1 0x00e1 0xe2 0x00e2 0xe3 0x00e3 0xe4 0x00e4 0xe5 0x00e5 0xe6 0x00e6 0xe7 0x012f 0xe8 0x010d 0xe9 0x00e9 0xea 0x0119 0xeb 0x00eb 0xec 0x0117 0xed 0x00ed 0xee 0x00ee 0xef 0x012b 0xf0 0x0111 0xf1 0x0146 0xf2 0x014d 0xf3 0x0137 0xf4 0x00f4 0xf5 0x00f5 0xf6 0x00f6 0xf7 0x00f7 0xf8 0x00f8 0xf9 0x0173 0xfa 0x00fa 0xfb 0x00fb 0xfc 0x00fc 0xfd 0x0169 0xfe 0x016b 0xff 0x02d9 htmldoc-1.9.7/data/iso-8859-5000066400000000000000000000043641354715574200154110ustar00rootroot000000000000000x20 0x0020 0x21 0x0021 0x22 0x0022 0x23 0x0023 0x24 0x0024 0x25 0x0025 0x26 0x0026 0x27 0x0027 0x28 0x0028 0x29 0x0029 0x2a 0x002a 0x2b 0x002b 0x2c 0x002c 0x2d 0x002d 0x2e 0x002e 0x2f 0x002f 0x30 0x0030 0x31 0x0031 0x32 0x0032 0x33 0x0033 0x34 0x0034 0x35 0x0035 0x36 0x0036 0x37 0x0037 0x38 0x0038 0x39 0x0039 0x3a 0x003a 0x3b 0x003b 0x3c 0x003c 0x3d 0x003d 0x3e 0x003e 0x3f 0x003f 0x40 0x0040 0x41 0x0041 0x42 0x0042 0x43 0x0043 0x44 0x0044 0x45 0x0045 0x46 0x0046 0x47 0x0047 0x48 0x0048 0x49 0x0049 0x4a 0x004a 0x4b 0x004b 0x4c 0x004c 0x4d 0x004d 0x4e 0x004e 0x4f 0x004f 0x50 0x0050 0x51 0x0051 0x52 0x0052 0x53 0x0053 0x54 0x0054 0x55 0x0055 0x56 0x0056 0x57 0x0057 0x58 0x0058 0x59 0x0059 0x5a 0x005a 0x5b 0x005b 0x5c 0x005c 0x5d 0x005d 0x5e 0x005e 0x5f 0x005f 0x60 0x0060 0x61 0x0061 0x62 0x0062 0x63 0x0063 0x64 0x0064 0x65 0x0065 0x66 0x0066 0x67 0x0067 0x68 0x0068 0x69 0x0069 0x6a 0x006a 0x6b 0x006b 0x6c 0x006c 0x6d 0x006d 0x6e 0x006e 0x6f 0x006f 0x70 0x0070 0x71 0x0071 0x72 0x0072 0x73 0x0073 0x74 0x0074 0x75 0x0075 0x76 0x0076 0x77 0x0077 0x78 0x0078 0x79 0x0079 0x7a 0x007a 0x7b 0x007b 0x7c 0x007c 0x7d 0x007d 0x7e 0x007e 0xa0 0x00a0 0xa1 0x0401 0xa2 0x0402 0xa3 0x0403 0xa4 0x0404 0xa5 0x0405 0xa6 0x0406 0xa7 0x0407 0xa8 0x0408 0xa9 0x0409 0xaa 0x040a 0xab 0x040b 0xac 0x040c 0xad 0x00ad 0xae 0x040e 0xaf 0x040f 0xb0 0x0410 0xb1 0x0411 0xb2 0x0412 0xb3 0x0413 0xb4 0x0414 0xb5 0x0415 0xb6 0x0416 0xb7 0x0417 0xb8 0x0418 0xb9 0x0419 0xba 0x041a 0xbb 0x041b 0xbc 0x041c 0xbd 0x041d 0xbe 0x041e 0xbf 0x041f 0xc0 0x0420 0xc1 0x0421 0xc2 0x0422 0xc3 0x0423 0xc4 0x0424 0xc5 0x0425 0xc6 0x0426 0xc7 0x0427 0xc8 0x0428 0xc9 0x0429 0xca 0x042a 0xcb 0x042b 0xcc 0x042c 0xcd 0x042d 0xce 0x042e 0xcf 0x042f 0xd0 0x0430 0xd1 0x0431 0xd2 0x0432 0xd3 0x0433 0xd4 0x0434 0xd5 0x0435 0xd6 0x0436 0xd7 0x0437 0xd8 0x0438 0xd9 0x0439 0xda 0x043a 0xdb 0x043b 0xdc 0x043c 0xdd 0x043d 0xde 0x043e 0xdf 0x043f 0xe0 0x0440 0xe1 0x0441 0xe2 0x0442 0xe3 0x0443 0xe4 0x0444 0xe5 0x0445 0xe6 0x0446 0xe7 0x0447 0xe8 0x0448 0xe9 0x0449 0xea 0x044a 0xeb 0x044b 0xec 0x044c 0xed 0x044d 0xee 0x044e 0xef 0x044f 0xf0 0x2116 0xf1 0x0451 0xf2 0x0452 0xf3 0x0453 0xf4 0x0454 0xf5 0x0455 0xf6 0x0456 0xf7 0x0457 0xf8 0x0458 0xf9 0x0459 0xfa 0x045a 0xfb 0x045b 0xfc 0x045c 0xfd 0x00a7 0xfe 0x045e 0xff 0x045f htmldoc-1.9.7/data/iso-8859-6000066400000000000000000000033301354715574200154020ustar00rootroot000000000000000x20 0x0020 0x21 0x0021 0x22 0x0022 0x23 0x0023 0x24 0x0024 0x25 0x0025 0x26 0x0026 0x27 0x0027 0x28 0x0028 0x29 0x0029 0x2a 0x002a 0x2b 0x002b 0x2c 0x002c 0x2d 0x002d 0x2e 0x002e 0x2f 0x002f 0x30 0x0660 0x31 0x0661 0x32 0x0662 0x33 0x0663 0x34 0x0664 0x35 0x0665 0x36 0x0666 0x37 0x0667 0x38 0x0668 0x39 0x0669 0x3a 0x003a 0x3b 0x003b 0x3c 0x003c 0x3d 0x003d 0x3e 0x003e 0x3f 0x003f 0x40 0x0040 0x41 0x0041 0x42 0x0042 0x43 0x0043 0x44 0x0044 0x45 0x0045 0x46 0x0046 0x47 0x0047 0x48 0x0048 0x49 0x0049 0x4a 0x004a 0x4b 0x004b 0x4c 0x004c 0x4d 0x004d 0x4e 0x004e 0x4f 0x004f 0x50 0x0050 0x51 0x0051 0x52 0x0052 0x53 0x0053 0x54 0x0054 0x55 0x0055 0x56 0x0056 0x57 0x0057 0x58 0x0058 0x59 0x0059 0x5a 0x005a 0x5b 0x005b 0x5c 0x005c 0x5d 0x005d 0x5e 0x005e 0x5f 0x005f 0x60 0x0060 0x61 0x0061 0x62 0x0062 0x63 0x0063 0x64 0x0064 0x65 0x0065 0x66 0x0066 0x67 0x0067 0x68 0x0068 0x69 0x0069 0x6a 0x006a 0x6b 0x006b 0x6c 0x006c 0x6d 0x006d 0x6e 0x006e 0x6f 0x006f 0x70 0x0070 0x71 0x0071 0x72 0x0072 0x73 0x0073 0x74 0x0074 0x75 0x0075 0x76 0x0076 0x77 0x0077 0x78 0x0078 0x79 0x0079 0x7a 0x007a 0x7b 0x007b 0x7c 0x007c 0x7d 0x007d 0x7e 0x007e 0xa0 0x00a0 0xa4 0x00a4 0xac 0x060c 0xad 0x00ad 0xbb 0x061b 0xbf 0x061f 0xc1 0x0621 0xc2 0x0622 0xc3 0x0623 0xc4 0x0624 0xc5 0x0625 0xc6 0x0626 0xc7 0x0627 0xc8 0x0628 0xc9 0x0629 0xca 0x062a 0xcb 0x062b 0xcc 0x062c 0xcd 0x062d 0xce 0x062e 0xcf 0x062f 0xd0 0x0630 0xd1 0x0631 0xd2 0x0632 0xd3 0x0633 0xd4 0x0634 0xd5 0x0635 0xd6 0x0636 0xd7 0x0637 0xd8 0x0638 0xd9 0x0639 0xda 0x063a 0xe0 0x0640 0xe1 0x0641 0xe2 0x0642 0xe3 0x0643 0xe4 0x0644 0xe5 0x0645 0xe6 0x0646 0xe7 0x0647 0xe8 0x0648 0xe9 0x0649 0xea 0x064a 0xeb 0x064b 0xec 0x064c 0xed 0x064d 0xee 0x064e 0xef 0x064f 0xf0 0x0650 0xf1 0x0651 0xf2 0x0652 htmldoc-1.9.7/data/iso-8859-7000066400000000000000000000042541354715574200154110ustar00rootroot000000000000000x20 0x0020 0x21 0x0021 0x22 0x0022 0x23 0x0023 0x24 0x0024 0x25 0x0025 0x26 0x0026 0x27 0x0027 0x28 0x0028 0x29 0x0029 0x2a 0x002a 0x2b 0x002b 0x2c 0x002c 0x2d 0x002d 0x2e 0x002e 0x2f 0x002f 0x30 0x0030 0x31 0x0031 0x32 0x0032 0x33 0x0033 0x34 0x0034 0x35 0x0035 0x36 0x0036 0x37 0x0037 0x38 0x0038 0x39 0x0039 0x3a 0x003a 0x3b 0x003b 0x3c 0x003c 0x3d 0x003d 0x3e 0x003e 0x3f 0x003f 0x40 0x0040 0x41 0x0041 0x42 0x0042 0x43 0x0043 0x44 0x0044 0x45 0x0045 0x46 0x0046 0x47 0x0047 0x48 0x0048 0x49 0x0049 0x4a 0x004a 0x4b 0x004b 0x4c 0x004c 0x4d 0x004d 0x4e 0x004e 0x4f 0x004f 0x50 0x0050 0x51 0x0051 0x52 0x0052 0x53 0x0053 0x54 0x0054 0x55 0x0055 0x56 0x0056 0x57 0x0057 0x58 0x0058 0x59 0x0059 0x5a 0x005a 0x5b 0x005b 0x5c 0x005c 0x5d 0x005d 0x5e 0x005e 0x5f 0x005f 0x60 0x0060 0x61 0x0061 0x62 0x0062 0x63 0x0063 0x64 0x0064 0x65 0x0065 0x66 0x0066 0x67 0x0067 0x68 0x0068 0x69 0x0069 0x6a 0x006a 0x6b 0x006b 0x6c 0x006c 0x6d 0x006d 0x6e 0x006e 0x6f 0x006f 0x70 0x0070 0x71 0x0071 0x72 0x0072 0x73 0x0073 0x74 0x0074 0x75 0x0075 0x76 0x0076 0x77 0x0077 0x78 0x0078 0x79 0x0079 0x7a 0x007a 0x7b 0x007b 0x7c 0x007c 0x7d 0x007d 0x7e 0x007e 0xa0 0x00a0 0xa1 0x02bd 0xa2 0x02bc 0xa3 0x00a3 0xa6 0x00a6 0xa7 0x00a7 0xa8 0x00a8 0xa9 0x00a9 0xab 0x00ab 0xac 0x00ac 0xad 0x00ad 0xaf 0x2015 0xb0 0x00b0 0xb1 0x00b1 0xb2 0x00b2 0xb3 0x00b3 0xb4 0x0384 0xb5 0x0385 0xb6 0x0386 0xb7 0x00b7 0xb8 0x0388 0xb9 0x0389 0xba 0x038a 0xbb 0x00bb 0xbc 0x038c 0xbd 0x00bd 0xbe 0x038e 0xbf 0x038f 0xc0 0x0390 0xc1 0x0391 0xc2 0x0392 0xc3 0x0393 0xc4 0x0394 0xc5 0x0395 0xc6 0x0396 0xc7 0x0397 0xc8 0x0398 0xc9 0x0399 0xca 0x039a 0xcb 0x039b 0xcc 0x039c 0xcd 0x039d 0xce 0x039e 0xcf 0x039f 0xd0 0x03a0 0xd1 0x03a1 0xd3 0x03a3 0xd4 0x03a4 0xd5 0x03a5 0xd6 0x03a6 0xd7 0x03a7 0xd8 0x03a8 0xd9 0x03a9 0xda 0x03aa 0xdb 0x03ab 0xdc 0x03ac 0xdd 0x03ad 0xde 0x03ae 0xdf 0x03af 0xe0 0x03b0 0xe1 0x03b1 0xe2 0x03b2 0xe3 0x03b3 0xe4 0x03b4 0xe5 0x03b5 0xe6 0x03b6 0xe7 0x03b7 0xe8 0x03b8 0xe9 0x03b9 0xea 0x03ba 0xeb 0x03bb 0xec 0x03bc 0xed 0x03bd 0xee 0x03be 0xef 0x03bf 0xf0 0x03c0 0xf1 0x03c1 0xf2 0x03c2 0xf3 0x03c3 0xf4 0x03c4 0xf5 0x03c5 0xf6 0x03c6 0xf7 0x03c7 0xf8 0x03c8 0xf9 0x03c9 0xfa 0x03ca 0xfb 0x03cb 0xfc 0x03cc 0xfd 0x03cd 0xfe 0x03ce htmldoc-1.9.7/data/iso-8859-8000066400000000000000000000034541354715574200154130ustar00rootroot000000000000000x20 0x0020 0x21 0x0021 0x22 0x0022 0x23 0x0023 0x24 0x0024 0x25 0x0025 0x26 0x0026 0x27 0x0027 0x28 0x0028 0x29 0x0029 0x2a 0x002a 0x2b 0x002b 0x2c 0x002c 0x2d 0x002d 0x2e 0x002e 0x2f 0x002f 0x30 0x0030 0x31 0x0031 0x32 0x0032 0x33 0x0033 0x34 0x0034 0x35 0x0035 0x36 0x0036 0x37 0x0037 0x38 0x0038 0x39 0x0039 0x3a 0x003a 0x3b 0x003b 0x3c 0x003c 0x3d 0x003d 0x3e 0x003e 0x3f 0x003f 0x40 0x0040 0x41 0x0041 0x42 0x0042 0x43 0x0043 0x44 0x0044 0x45 0x0045 0x46 0x0046 0x47 0x0047 0x48 0x0048 0x49 0x0049 0x4a 0x004a 0x4b 0x004b 0x4c 0x004c 0x4d 0x004d 0x4e 0x004e 0x4f 0x004f 0x50 0x0050 0x51 0x0051 0x52 0x0052 0x53 0x0053 0x54 0x0054 0x55 0x0055 0x56 0x0056 0x57 0x0057 0x58 0x0058 0x59 0x0059 0x5a 0x005a 0x5b 0x005b 0x5c 0x005c 0x5d 0x005d 0x5e 0x005e 0x5f 0x005f 0x60 0x0060 0x61 0x0061 0x62 0x0062 0x63 0x0063 0x64 0x0064 0x65 0x0065 0x66 0x0066 0x67 0x0067 0x68 0x0068 0x69 0x0069 0x6a 0x006a 0x6b 0x006b 0x6c 0x006c 0x6d 0x006d 0x6e 0x006e 0x6f 0x006f 0x70 0x0070 0x71 0x0071 0x72 0x0072 0x73 0x0073 0x74 0x0074 0x75 0x0075 0x76 0x0076 0x77 0x0077 0x78 0x0078 0x79 0x0079 0x7a 0x007a 0x7b 0x007b 0x7c 0x007c 0x7d 0x007d 0x7e 0x007e 0xa0 0x00a0 0xa2 0x00a2 0xa3 0x00a3 0xa4 0x00a4 0xa5 0x00a5 0xa6 0x00a6 0xa7 0x00a7 0xa8 0x00a8 0xa9 0x00a9 0xaa 0x00d7 0xab 0x00ab 0xac 0x00ac 0xad 0x00ad 0xae 0x00ae 0xaf 0x203e 0xb0 0x00b0 0xb1 0x00b1 0xb2 0x00b2 0xb3 0x00b3 0xb4 0x00b4 0xb5 0x00b5 0xb6 0x00b6 0xb7 0x00b7 0xb8 0x00b8 0xb9 0x00b9 0xba 0x00f7 0xbb 0x00bb 0xbc 0x00bc 0xbd 0x00bd 0xbe 0x00be 0xdf 0x2017 0xe0 0x05d0 0xe1 0x05d1 0xe2 0x05d2 0xe3 0x05d3 0xe4 0x05d4 0xe5 0x05d5 0xe6 0x05d6 0xe7 0x05d7 0xe8 0x05d8 0xe9 0x05d9 0xea 0x05da 0xeb 0x05db 0xec 0x05dc 0xed 0x05dd 0xee 0x05de 0xef 0x05df 0xf0 0x05e0 0xf1 0x05e1 0xf2 0x05e2 0xf3 0x05e3 0xf4 0x05e4 0xf5 0x05e5 0xf6 0x05e6 0xf7 0x05e7 0xf8 0x05e8 0xf9 0x05e9 0xfa 0x05ea htmldoc-1.9.7/data/iso-8859-9000066400000000000000000000043701354715574200154120ustar00rootroot000000000000000x20 0x0020 0x21 0x0021 0x22 0x0022 0x23 0x0023 0x24 0x0024 0x25 0x0025 0x26 0x0026 0x27 0x0027 0x28 0x0028 0x29 0x0029 0x2a 0x002a 0x2b 0x002b 0x2c 0x002c 0x2d 0x002d 0x2e 0x002e 0x2f 0x002f 0x30 0x0030 0x31 0x0031 0x32 0x0032 0x33 0x0033 0x34 0x0034 0x35 0x0035 0x36 0x0036 0x37 0x0037 0x38 0x0038 0x39 0x0039 0x3a 0x003a 0x3b 0x003b 0x3c 0x003c 0x3d 0x003d 0x3e 0x003e 0x3f 0x003f 0x40 0x0040 0x41 0x0041 0x42 0x0042 0x43 0x0043 0x44 0x0044 0x45 0x0045 0x46 0x0046 0x47 0x0047 0x48 0x0048 0x49 0x0049 0x4a 0x004a 0x4b 0x004b 0x4c 0x004c 0x4d 0x004d 0x4e 0x004e 0x4f 0x004f 0x50 0x0050 0x51 0x0051 0x52 0x0052 0x53 0x0053 0x54 0x0054 0x55 0x0055 0x56 0x0056 0x57 0x0057 0x58 0x0058 0x59 0x0059 0x5a 0x005a 0x5b 0x005b 0x5c 0x005c 0x5d 0x005d 0x5e 0x005e 0x5f 0x005f 0x60 0x0060 0x61 0x0061 0x62 0x0062 0x63 0x0063 0x64 0x0064 0x65 0x0065 0x66 0x0066 0x67 0x0067 0x68 0x0068 0x69 0x0069 0x6a 0x006a 0x6b 0x006b 0x6c 0x006c 0x6d 0x006d 0x6e 0x006e 0x6f 0x006f 0x70 0x0070 0x71 0x0071 0x72 0x0072 0x73 0x0073 0x74 0x0074 0x75 0x0075 0x76 0x0076 0x77 0x0077 0x78 0x0078 0x79 0x0079 0x7a 0x007a 0x7b 0x007b 0x7c 0x007c 0x7d 0x007d 0x7e 0x007e 0xa0 0x00a0 0xa1 0x00a1 0xa2 0x00a2 0xa3 0x00a3 0xa4 0x00a4 0xa5 0x00a5 0xa6 0x00a6 0xa7 0x00a7 0xa8 0x00a8 0xa9 0x00a9 0xaa 0x00aa 0xab 0x00ab 0xac 0x00ac 0xad 0x00ad 0xae 0x00ae 0xaf 0x00af 0xb0 0x00b0 0xb1 0x00b1 0xb2 0x00b2 0xb3 0x00b3 0xb4 0x00b4 0xb5 0x00b5 0xb6 0x00b6 0xb7 0x00b7 0xb8 0x00b8 0xb9 0x00b9 0xba 0x00ba 0xbb 0x00bb 0xbc 0x00bc 0xbd 0x00bd 0xbe 0x00be 0xbf 0x00bf 0xc0 0x00c0 0xc1 0x00c1 0xc2 0x00c2 0xc3 0x00c3 0xc4 0x00c4 0xc5 0x00c5 0xc6 0x00c6 0xc7 0x00c7 0xc8 0x00c8 0xc9 0x00c9 0xca 0x00ca 0xcb 0x00cb 0xcc 0x00cc 0xcd 0x00cd 0xce 0x00ce 0xcf 0x00cf 0xd0 0x011e 0xd1 0x00d1 0xd2 0x00d2 0xd3 0x00d3 0xd4 0x00d4 0xd5 0x00d5 0xd6 0x00d6 0xd7 0x00d7 0xd8 0x00d8 0xd9 0x00d9 0xda 0x00da 0xdb 0x00db 0xdc 0x00dc 0xdd 0x0130 0xde 0x015e 0xdf 0x00df 0xe0 0x00e0 0xe1 0x00e1 0xe2 0x00e2 0xe3 0x00e3 0xe4 0x00e4 0xe5 0x00e5 0xe6 0x00e6 0xe7 0x00e7 0xe8 0x00e8 0xe9 0x00e9 0xea 0x00ea 0xeb 0x00eb 0xec 0x00ec 0xed 0x00ed 0xee 0x00ee 0xef 0x00ef 0xf0 0x011f 0xf1 0x00f1 0xf2 0x00f2 0xf3 0x00f3 0xf4 0x00f4 0xf5 0x00f5 0xf6 0x00f6 0xf7 0x00f7 0xf8 0x00f8 0xf9 0x00f9 0xfa 0x00fa 0xfb 0x00fb 0xfc 0x00fc 0xfd 0x0131 0xfe 0x015f 0xff 0x00ff htmldoc-1.9.7/data/koi8-r000066400000000000000000000051641354715574200151520ustar00rootroot000000000000000x20 0x0020 0x21 0x0021 0x22 0x0022 0x23 0x0023 0x24 0x0024 0x25 0x0025 0x26 0x0026 0x27 0x0027 0x28 0x0028 0x29 0x0029 0x2a 0x002a 0x2b 0x002b 0x2c 0x002c 0x2d 0x002d 0x2e 0x002e 0x2f 0x002f 0x30 0x0030 0x31 0x0031 0x32 0x0032 0x33 0x0033 0x34 0x0034 0x35 0x0035 0x36 0x0036 0x37 0x0037 0x38 0x0038 0x39 0x0039 0x3a 0x003a 0x3b 0x003b 0x3c 0x003c 0x3d 0x003d 0x3e 0x003e 0x3f 0x003f 0x40 0x0040 0x41 0x0041 0x42 0x0042 0x43 0x0043 0x44 0x0044 0x45 0x0045 0x46 0x0046 0x47 0x0047 0x48 0x0048 0x49 0x0049 0x4a 0x004a 0x4b 0x004b 0x4c 0x004c 0x4d 0x004d 0x4e 0x004e 0x4f 0x004f 0x50 0x0050 0x51 0x0051 0x52 0x0052 0x53 0x0053 0x54 0x0054 0x55 0x0055 0x56 0x0056 0x57 0x0057 0x58 0x0058 0x59 0x0059 0x5a 0x005a 0x5b 0x005b 0x5c 0x005c 0x5d 0x005d 0x5e 0x005e 0x5f 0x005f 0x60 0x0060 0x61 0x0061 0x62 0x0062 0x63 0x0063 0x64 0x0064 0x65 0x0065 0x66 0x0066 0x67 0x0067 0x68 0x0068 0x69 0x0069 0x6a 0x006a 0x6b 0x006b 0x6c 0x006c 0x6d 0x006d 0x6e 0x006e 0x6f 0x006f 0x70 0x0070 0x71 0x0071 0x72 0x0072 0x73 0x0073 0x74 0x0074 0x75 0x0075 0x76 0x0076 0x77 0x0077 0x78 0x0078 0x79 0x0079 0x7a 0x007a 0x7b 0x007b 0x7c 0x007c 0x7d 0x007d 0x7e 0x007e 0x80 0x2500 0x81 0x2502 0x82 0x250C 0x83 0x2510 0x84 0x2514 0x85 0x2518 0x86 0x251C 0x87 0x2524 0x88 0x252C 0x89 0x2534 0x8A 0x253C 0x8B 0x2580 0x8C 0x2584 0x8D 0x2588 0x8E 0x258C 0x8F 0x2590 0x90 0x2591 0x91 0x2592 0x92 0x2593 0x93 0x2320 0x94 0x25A0 0x95 0x2219 0x96 0x221A 0x97 0x2248 0x98 0x2264 0x99 0x2265 0x9A 0x00A0 0x9B 0x2321 0x9C 0x00B0 0x9D 0x00B2 0x9E 0x00B7 0x9F 0x00F7 0xA0 0x2550 0xA1 0x2551 0xA2 0x2552 0xA3 0x0451 0xA4 0x2553 0xA5 0x2554 0xA6 0x2555 0xA7 0x2556 0xA8 0x2557 0xA9 0x2558 0xAA 0x2559 0xAB 0x255A 0xAC 0x255B 0xAD 0x255C 0xAE 0x255D 0xAF 0x255E 0xB0 0x255F 0xB1 0x2560 0xB2 0x2561 0xB3 0x0401 0xB4 0x2562 0xB5 0x2563 0xB6 0x2564 0xB7 0x2565 0xB8 0x2566 0xB9 0x2567 0xBA 0x2568 0xBB 0x2569 0xBC 0x256A 0xBD 0x256B 0xBE 0x256C 0xBF 0x00A9 0xC0 0x044E 0xC1 0x0430 0xC2 0x0431 0xC3 0x0446 0xC4 0x0434 0xC5 0x0435 0xC6 0x0444 0xC7 0x0433 0xC8 0x0445 0xC9 0x0438 0xCA 0x0439 0xCB 0x043A 0xCC 0x043B 0xCD 0x043C 0xCE 0x043D 0xCF 0x043E 0xD0 0x043F 0xD1 0x044F 0xD2 0x0440 0xD3 0x0441 0xD4 0x0442 0xD5 0x0443 0xD6 0x0436 0xD7 0x0432 0xD8 0x044C 0xD9 0x044B 0xDA 0x0437 0xDB 0x0448 0xDC 0x044D 0xDD 0x0449 0xDE 0x0447 0xDF 0x044A 0xE0 0x042E 0xE1 0x0410 0xE2 0x0411 0xE3 0x0426 0xE4 0x0414 0xE5 0x0415 0xE6 0x0424 0xE7 0x0413 0xE8 0x0425 0xE9 0x0418 0xEA 0x0419 0xEB 0x041A 0xEC 0x041B 0xED 0x041C 0xEE 0x041D 0xEF 0x041E 0xF0 0x041F 0xF1 0x042F 0xF2 0x0420 0xF3 0x0421 0xF4 0x0422 0xF5 0x0423 0xF6 0x0416 0xF7 0x0412 0xF8 0x042C 0xF9 0x042B 0xFA 0x0417 0xFB 0x0428 0xFC 0x042D 0xFD 0x0429 0xFE 0x0427 0xFF 0x042A htmldoc-1.9.7/data/prolog.ps000066400000000000000000000173521354715574200157660ustar00rootroot00000000000000%%BeginResource: procset htmldoc-device 1.8 24 % % The following procedures use setpagedevice, which is not supported by % Level 1 PostScript interpreters. For these systems, make setpagedevice % a no-op. % languagelevel 1 eq { /setpagedevice {pop} BD } if % % trayMap % % The trayMap variable defines an array of tray positions that are % used when looking up the "MEDIA POSITION nnn" page comment. The % array should be exactly 8 elements long. Unavailable trays should % be set to -1. % /trayMap [-1 -1 -1 -1 -1 -1 -1 -1] def product (Xerox DocuPrint N4025 PS3) eq { /trayMap [0 1 2 3 4 -1 -1 -1] def } if product (Xerox DocuPrint N2025 PS) eq { /trayMap [0 1 2 3 -1 -1 -1 -1] def } if product (HP LaserJet 5Si/5Si MX PS) eq { /trayMap [3 0 1 4 -1 -1 -1 -1] def } if product (HP LaserJet 2100 Series) eq { /trayMap [3 0 1 -1 -1 -1 -1 -1] def } if product (HP LaserJet 5000 Series) eq { /trayMap [3 0 1 4 -1 -1 -1 -1] def } if product (Xerox Document Centre 220/230) eq { /trayMap [1 2 3 4 -1 5 -1 -1] def } if product (Xerox Document Centre 332/340) eq { /trayMap [1 2 3 4 -1 5 -1 -1] def } if %product (Insert ModelName string here) eq % { /trayMap [-1 -1 -1 -1 -1 -1 -1 -1] def } if % % haveMediaColor % % The haveMediaColor variable defines whether a printer supports the % MediaColor attribute in the page device dictionary. % /haveMediaColor product (Xerox Document Centre 220/230) eq product (Xerox Document Centre 332/340) eq or product (Xerox DocuPrint 100 NPS PS2) eq or product (Xerox DocuPrint 2000 Series 100 EPS) eq or % product (Insert ModelName string here) eq or def % % haveMediaPosition % % The haveMediaPosition variable defines whether a printer supports % the MediaPosition attribute in the page device dictionary. % /haveMediaPosition product (Xerox DocuPrint N2025 PS) eq product (Xerox DocuPrint N4025 PS3) eq or product (Xerox Document Centre 220/230) eq or product (Xerox Document Centre 332/340) eq or product (HP LaserJet 5Si/5Si MX PS) eq or product (HP LaserJet 2100 Series) eq or product (HP LaserJet 5000 Series) eq or % product (Insert ModelName string here) eq or def % % haveMediaType % % The haveMediaType variable defines whether a printer supports % the MediaType attribute in the page device dictionary. % /haveMediaType product (Xerox DocuPrint N2025 PS) eq product (Xerox DocuPrint N4025 PS3) eq or product (Xerox Document Centre 220/230) eq or product (Xerox Document Centre 332/340) eq or product (HP LaserJet 5Si/5Si MX PS) eq or product (HP LaserJet 5000 Series) eq or product (Xerox DocuPrint 100 NPS PS2) eq or product (Xerox DocuPrint 2000 Series 100 EPS) eq or % product (Insert ModelName string here) eq or def % % haveDeferredMediaSelection % % The haveDeferredMediaSelection variable defines whether a printer supports % the DeferredMediaSelection attribute in the page device dictionary. % /haveDeferredMediaSelection product (Xerox DocuPrint N2025 PS) eq product (Xerox DocuPrint N4025 PS3) eq or product (HP LaserJet 5Si/5Si MX PS) eq or % product (Insert ModelName string here) eq or not def % % haveManualFeed % % The haveManualFeed variable defines whether a printer supports % the ManualFeed attribute in the page device dictionary. % /haveManualFeed product (Xerox DocuPrint N2025 PS) eq product (Xerox DocuPrint N4025 PS3) eq or product (HP LaserJet 5Si/5Si MX PS) eq or product (HP LaserJet 2100 Series) eq or product (HP LaserJet 5000 Series) eq or product (Xerox Document Centre 220/230) eq or product (Xerox Document Centre 332/340) eq or % product (Insert ModelName string here) eq or not def % % haveTraySwitch % % The haveTraySwitch variable defines whether a printer supports % the TraySwitch attribute in the page device dictionary. % /haveTraySwitch product (Xerox DocuPrint N2025 PS) eq product (Xerox DocuPrint N4025 PS3) eq or product (Xerox Document Centre 220/230) eq or product (Xerox Document Centre 332/340) eq or % product (Insert ModelName string here) eq or not def % % copies SetCopies - % % Set the number of copies to print. % /SetCopies { % Set the number of copies of each page. For Level 1 printers, use the % #copies variable; otherwise, use the NumCopies attribute in the % page device dictionary... languagelevel 1 eq { /#copies 1 index def } { 2 dict begin /NumCopies 1 index currentdict end setpagedevice } ifelse % Discard the argument on the stack... pop } BD % % duplex tumble SetDuplexMode - % % Set the duplexing mode; "duplex" and "tumble" are boolean values. % /CurrentDuplex false def /CurrentTumble false def /SetDuplexMode { % See if the duplex settings have changed; if not, don't change % them, otherwise some printers will reset their state and you % end up with single-sided output... 1 index CurrentDuplex ne 1 index CurrentTumble ne or { % Build a page device dictionary with the Duplex and Tumble % attributes... 4 dict begin /Duplex 2 index def /Tumble 1 index def currentdict end % Register the new attributes... setpagedevice } if % Save the arguments on the stack... /CurrentTumble exch def /CurrentDuplex exch def } BD % % string SetMediaColor - % % Set the media color for the output. % /CurrentMediaColor () def /SetMediaColor { dup CurrentMediaColor ne { haveMediaType { haveMediaColor { % Build a page device dictionary with the MediaColor attribute set to % the argument... 2 dict begin /MediaColor 1 index def currentdict end } { % Build a page device dictionary with the MediaType attribute set to % "Color"... 2 dict begin /MediaType (Color) def currentdict end } ifelse % Register any new attributes... setpagedevice } if } if % Save the media color on the stack... /CurrentMediaColor exch def } BD % % number SetMediaPosition - % % Set the media position (tray) for the output. % /CurrentMediaPosition -1 def /SetMediaPosition { dup CurrentMediaPosition ne { haveMediaPosition { % Add any tray position offset to the tray number. trayMap exch 1 sub get dup 0 ge { % Build a page device dictionary with the MediaPosition, % DeferredMediaSelection, ManualFeed, and TraySwitch attributes... 8 dict begin /MediaPosition 1 index def haveDeferredMediaSelection { /DeferredMediaSelection true def } if haveTraySwitch { /TraySwitch false def } if haveManualFeed { /ManualFeed false def } if currentdict end % Register the new attributes... setpagedevice } { pop } ifelse } if } if % Save the media position on the stack... /CurrentMediaPosition exch def } BD % % string SetMediaType - % % Set the media type for the output. Use a null string to do auto selection. % /CurrentMediaType () def /SetMediaType { dup CurrentMediaType ne { haveMediaType { % Build a page device dictionary with the MediaType attribute... 2 dict begin /MediaType 1 index def currentdict end % Register the new attribute... setpagedevice } if } if % Save the media type on the stack... /CurrentMediaType exch def } BD % % width height SetPageSize - % % Set the media size for the output. % /CurrentPageWidth 0 def /CurrentPageLength 0 def /SetPageSize { 1 index CurrentPageWidth ne 1 index CurrentPageLength ne or { % Put the arguments in an array... 2 copy 2 array astore % Build a page device dictionary with the PageSize and ImageableArea % attributes... 4 dict begin /PageSize 1 index def /ImageableArea null def currentdict end % Register the new attributes... setpagedevice % Don't need the page size array anymore... pop } if % Save the size on the stack... /CurrentPageLength exch def /CurrentPageWidth exch def } BD %%EndResource htmldoc-1.9.7/data/psglyphs000066400000000000000000000351541354715574200157140ustar00rootroot000000000000000020 space 0021 exclam 0022 quotedbl 0023 numbersign 0024 dollar 0025 percent 0026 ampersand 0027 quotesingle 0028 parenleft 0029 parenright 002a asterisk 002b plus 002c comma 002d hyphen 002e period 002f slash 0030 zero 0031 one 0032 two 0033 three 0034 four 0035 five 0036 six 0037 seven 0038 eight 0039 nine 003a colon 003b semicolon 003c less 003d equal 003e greater 003f question 0040 at 0041 A 0042 B 0043 C 0044 D 0045 E 0046 F 0047 G 0048 H 0049 I 004a J 004b K 004c L 004d M 004e N 004f O 0050 P 0051 Q 0052 R 0053 S 0054 T 0055 U 0056 V 0057 W 0058 X 0059 Y 005a Z 005b bracketleft 005c backslash 005d bracketright 005e asciicircum 005f underscore 0060 grave 0061 a 0062 b 0063 c 0064 d 0065 e 0066 f 0067 g 0068 h 0069 i 006a j 006b k 006c l 006d m 006e n 006f o 0070 p 0071 q 0072 r 0073 s 0074 t 0075 u 0076 v 0077 w 0078 x 0079 y 007a z 007b braceleft 007c bar 007d braceright 007e asciitilde 00a0 space 00a1 exclamdown 00a2 cent 00a3 sterling 00a4 currency 00a5 yen 00a6 brokenbar 00a7 section 00a8 dieresis 00a9 copyright 00aa ordfeminine 00ab guillemotleft 00ac logicalnot 00ad minus 00ae registered 00af macron 00b0 degree 00b1 plusminus 00b2 twosuperior 00b3 threesuperior 00b4 acute 00b5 mu 00b6 paragraph 00b7 periodcentered 00b8 cedilla 00b9 onesuperior 00ba ordmasculine 00bb guillemotright 00bc onequarter 00bd onehalf 00be threequarters 00bf questiondown 00c0 Agrave 00c1 Aacute 00c2 Acircumflex 00c3 Atilde 00c4 Adieresis 00c5 Aring 00c6 AE 00c7 Ccedilla 00c8 Egrave 00c9 Eacute 00ca Ecircumflex 00cb Edieresis 00cc Igrave 00cd Iacute 00ce Icircumflex 00cf Idieresis 00d0 Eth 00d1 Ntilde 00d2 Ograve 00d3 Oacute 00d4 Ocircumflex 00d5 Otilde 00d6 Odieresis 00d7 multiply 00d8 Oslash 00d9 Ugrave 00da Uacute 00db Ucircumflex 00dc Udieresis 00dd Yacute 00de Thorn 00df germandbls 00e0 agrave 00e1 aacute 00e2 acircumflex 00e3 atilde 00e4 adieresis 00e5 aring 00e6 ae 00e7 ccedilla 00e8 egrave 00e9 eacute 00ea ecircumflex 00eb edieresis 00ec igrave 00ed iacute 00ee icircumflex 00ef idieresis 00f0 eth 00f1 ntilde 00f2 ograve 00f3 oacute 00f4 ocircumflex 00f5 otilde 00f6 odieresis 00f7 divide 00f8 oslash 00f9 ugrave 00fa uacute 00fb ucircumflex 00fc udieresis 00fd yacute 00fe thorn 00ff ydieresis 0100 Amacron 0101 amacron 0102 Abreve 0103 abreve 0104 Aogonek 0105 aogonek 0106 Cacute 0107 cacute 0108 Ccircumflex 0109 ccircumflex 010a Cdotaccent 010b cdotaccent 010c Ccaron 010d ccaron 010e Dcaron 010f dcaron 0110 Dcroat 0111 dcroat 0112 Emacron 0113 emacron 0114 Ebreve 0115 ebreve 0116 Edotaccent 0117 edotaccent 0118 Eogonek 0119 eogonek 011a Ecaron 011b ecaron 011c Gcircumflex 011d gcircumflex 011e Gbreve 011f gbreve 0120 Gdotaccent 0121 gdotaccent 0122 Gcommaaccent 0123 gcommaaccent 0124 Hcircumflex 0125 hcircumflex 0126 Hbar 0127 hbar 0128 Itilde 0129 itilde 012a Imacron 012b imacron 012c Ibreve 012d ibreve 012e Iogonek 012f iogonek 0130 Idotaccent 0131 dotlessi 0132 IJ 0133 ij 0134 Jcircumflex 0135 jcircumflex 0136 Kcommaaccent 0137 kcommaaccent 0138 kgreenlandic 0139 Lacute 013a lacute 013b Lcommaaccent 013c lcommaaccent 013d Lcaron 013e lcaron 013f Ldot 0140 ldot 0141 Lslash 0142 lslash 0143 Nacute 0144 nacute 0145 Ncommaaccent 0146 ncommaaccent 0147 Ncaron 0148 ncaron 0149 napostrophe 014a Eng 014b eng 014c Omacron 014d omacron 014e Obreve 014f obreve 0150 Ohungarumlaut 0151 ohungarumlaut 0152 OE 0153 oe 0154 Racute 0155 racute 0156 Rcommaaccent 0157 rcommaaccent 0158 Rcaron 0159 rcaron 015a Sacute 015b sacute 015c Scircumflex 015d scircumflex 015e Scedilla 015f scedilla 0160 Scaron 0161 scaron 0162 Tcommaaccent 0163 tcommaaccent 0164 Tcaron 0165 tcaron 0166 Tbar 0167 tbar 0168 Utilde 0169 utilde 016a Umacron 016b umacron 016c Ubreve 016d ubreve 016e Uring 016f uring 0170 Uhungarumlaut 0171 uhungarumlaut 0172 Uogonek 0173 uogonek 0174 Wcircumflex 0175 wcircumflex 0176 Ycircumflex 0177 ycircumflex 0178 Ydieresis 0179 Zacute 017a zacute 017b Zdotaccent 017c zdotaccent 017d Zcaron 017e zcaron 017f longs 0192 florin 01a0 Ohorn 01a1 ohorn 01af Uhorn 01b0 uhorn 01e6 Gcaron 01e7 gcaron 01fa Aringacute 01fb aringacute 01fc AEacute 01fd aeacute 01fe Oslashacute 01ff oslashacute 0218 Scommaaccent 0219 scommaaccent 021a Tcommaaccent 021b tcommaaccent 02bc afii57929 02bd afii64937 02c6 circumflex 02c7 caron 02c9 macron 02d8 breve 02d9 dotaccent 02da ring 02db ogonek 02dc tilde 02dd hungarumlaut 0300 gravecomb 0301 acutecomb 0303 tildecomb 0309 hookabovecomb 0323 dotbelowcomb 0384 tonos 0385 dieresistonos 0386 Alphatonos 0387 anoteleia 0388 Epsilontonos 0389 Etatonos 038a Iotatonos 038c Omicrontonos 038e Upsilontonos 038f Omegatonos 0390 iotadieresistonos 0391 Alpha 0392 Beta 0393 Gamma 0394 Delta 0395 Epsilon 0396 Zeta 0397 Eta 0398 Theta 0399 Iota 039a Kappa 039b Lambda 039c Mu 039d Nu 039e Xi 039f Omicron 03a0 Pi 03a1 Rho 03a3 Sigma 03a4 Tau 03a5 Upsilon 03a6 Phi 03a7 Chi 03a8 Psi 03a9 Omega 03aa Iotadieresis 03ab Upsilondieresis 03ac alphatonos 03ad epsilontonos 03ae etatonos 03af iotatonos 03b0 upsilondieresistonos 03b1 alpha 03b2 beta 03b3 gamma 03b4 delta 03b5 epsilon 03b6 zeta 03b7 eta 03b8 theta 03b9 iota 03ba kappa 03bb lambda 03bc mu 03bd nu 03be xi 03bf omicron 03c0 pi 03c1 rho 03c2 sigma1 03c3 sigma 03c4 tau 03c5 upsilon 03c6 phi 03c7 chi 03c8 psi 03c9 omega 03ca iotadieresis 03cb upsilondieresis 03cc omicrontonos 03cd upsilontonos 03ce omegatonos 03d1 theta1 03d2 Upsilon1 03d5 phi1 03d6 omega1 0401 afii10023 0402 afii10051 0403 afii10052 0404 afii10053 0405 afii10054 0406 afii10055 0407 afii10056 0408 afii10057 0409 afii10058 040a afii10059 040b afii10060 040c afii10061 040e afii10062 040f afii10145 0410 afii10017 0411 afii10018 0412 afii10019 0413 afii10020 0414 afii10021 0415 afii10022 0416 afii10024 0417 afii10025 0418 afii10026 0419 afii10027 041a afii10028 041b afii10029 041c afii10030 041d afii10031 041e afii10032 041f afii10033 0420 afii10034 0421 afii10035 0422 afii10036 0423 afii10037 0424 afii10038 0425 afii10039 0426 afii10040 0427 afii10041 0428 afii10042 0429 afii10043 042a afii10044 042b afii10045 042c afii10046 042d afii10047 042e afii10048 042f afii10049 0430 afii10065 0431 afii10066 0432 afii10067 0433 afii10068 0434 afii10069 0435 afii10070 0436 afii10072 0437 afii10073 0438 afii10074 0439 afii10075 043a afii10076 043b afii10077 043c afii10078 043d afii10079 043e afii10080 043f afii10081 0440 afii10082 0441 afii10083 0442 afii10084 0443 afii10085 0444 afii10086 0445 afii10087 0446 afii10088 0447 afii10089 0448 afii10090 0449 afii10091 044a afii10092 044b afii10093 044c afii10094 044d afii10095 044e afii10096 044f afii10097 0451 afii10071 0452 afii10099 0453 afii10100 0454 afii10101 0455 afii10102 0456 afii10103 0457 afii10104 0458 afii10105 0459 afii10106 045a afii10107 045b afii10108 045c afii10109 045e afii10110 045f afii10193 0462 afii10146 0463 afii10194 0472 afii10147 0473 afii10195 0474 afii10148 0475 afii10196 0490 afii10050 0491 afii10098 04d9 afii10846 05b0 afii57799 05b1 afii57801 05b2 afii57800 05b3 afii57802 05b4 afii57793 05b5 afii57794 05b6 afii57795 05b7 afii57798 05b8 afii57797 05b9 afii57806 05bb afii57796 05bc afii57807 05bd afii57839 05be afii57645 05bf afii57841 05c0 afii57842 05c1 afii57804 05c2 afii57803 05c3 afii57658 05d0 afii57664 05d1 afii57665 05d2 afii57666 05d3 afii57667 05d4 afii57668 05d5 afii57669 05d6 afii57670 05d7 afii57671 05d8 afii57672 05d9 afii57673 05da afii57674 05db afii57675 05dc afii57676 05dd afii57677 05de afii57678 05df afii57679 05e0 afii57680 05e1 afii57681 05e2 afii57682 05e3 afii57683 05e4 afii57684 05e5 afii57685 05e6 afii57686 05e7 afii57687 05e8 afii57688 05e9 afii57689 05ea afii57690 05f0 afii57716 05f1 afii57717 05f2 afii57718 060c afii57388 061b afii57403 061f afii57407 0621 afii57409 0622 afii57410 0623 afii57411 0624 afii57412 0625 afii57413 0626 afii57414 0627 afii57415 0628 afii57416 0629 afii57417 062a afii57418 062b afii57419 062c afii57420 062d afii57421 062e afii57422 062f afii57423 0630 afii57424 0631 afii57425 0632 afii57426 0633 afii57427 0634 afii57428 0635 afii57429 0636 afii57430 0637 afii57431 0638 afii57432 0639 afii57433 063a afii57434 0640 afii57440 0641 afii57441 0642 afii57442 0643 afii57443 0644 afii57444 0645 afii57445 0646 afii57446 0647 afii57470 0648 afii57448 0649 afii57449 064a afii57450 064b afii57451 064c afii57452 064d afii57453 064e afii57454 064f afii57455 0650 afii57456 0651 afii57457 0652 afii57458 0660 afii57392 0661 afii57393 0662 afii57394 0663 afii57395 0664 afii57396 0665 afii57397 0666 afii57398 0667 afii57399 0668 afii57400 0669 afii57401 066a afii57381 066d afii63167 0679 afii57511 067e afii57506 0686 afii57507 0688 afii57512 0691 afii57513 0698 afii57508 06a4 afii57505 06af afii57509 06ba afii57514 06d2 afii57519 06d5 afii57534 1e80 Wgrave 1e81 wgrave 1e82 Wacute 1e83 wacute 1e84 Wdieresis 1e85 wdieresis 1ef2 Ygrave 1ef3 ygrave 200c afii61664 200d afii301 200e afii299 200f afii300 2012 figuredash 2013 endash 2014 emdash 2015 afii00208 2017 underscoredbl 2018 quoteleft 2019 quoteright 201a quotesinglbase 201b quotereversed 201c quotedblleft 201d quotedblright 201e quotedblbase 2020 dagger 2021 daggerdbl 2022 bullet 2024 onedotenleader 2025 twodotenleader 2026 ellipsis 202c afii61573 202d afii61574 202e afii61575 2030 perthousand 2032 minute 2033 second 2039 guilsinglleft 203a guilsinglright 203c exclamdbl 2044 fraction 2070 zerosuperior 2074 foursuperior 2075 fivesuperior 2076 sixsuperior 2077 sevensuperior 2078 eightsuperior 2079 ninesuperior 207d parenleftsuperior 207e parenrightsuperior 207f nsuperior 2080 zeroinferior 2081 oneinferior 2082 twoinferior 2083 threeinferior 2084 fourinferior 2085 fiveinferior 2086 sixinferior 2087 seveninferior 2088 eightinferior 2089 nineinferior 208d parenleftinferior 208e parenrightinferior 20a1 colonmonetary 20a3 franc 20a4 lira 20a7 peseta 20aa afii57636 20ab dong 20ac Euro 2105 afii61248 2111 Ifraktur 2113 afii61289 2116 afii61352 2118 weierstrass 211c Rfraktur 211e prescription 2122 trademark 2126 Omega 212e estimated 2135 aleph 2153 onethird 2154 twothirds 215b oneeighth 215c threeeighths 215d fiveeighths 215e seveneighths 2190 arrowleft 2191 arrowup 2192 arrowright 2193 arrowdown 2194 arrowboth 2195 arrowupdn 21a8 arrowupdnbse 21b5 carriagereturn 21d0 arrowdblleft 21d1 arrowdblup 21d2 arrowdblright 21d3 arrowdbldown 21d4 arrowdblboth 2200 universal 2202 partialdiff 2203 existential 2205 emptyset 2206 Delta 2207 gradient 2208 element 2209 notelement 220b suchthat 220f product 2211 summation 2212 minus 2215 fraction 2217 asteriskmath 2219 periodcentered 221a radical 221d proportional 221e infinity 221f orthogonal 2220 angle 2227 logicaland 2228 logicalor 2229 intersection 222a union 222b integral 2234 therefore 223c similar 2245 congruent 2248 approxequal 2260 notequal 2261 equivalence 2264 lessequal 2265 greaterequal 2282 propersubset 2283 propersuperset 2284 notsubset 2286 reflexsubset 2287 reflexsuperset 2295 circleplus 2297 circlemultiply 22a5 perpendicular 22c5 dotmath 2302 house 2310 revlogicalnot 2320 integraltp 2321 integralbt 2329 angleleft 232a angleright 2500 SF100000 2502 SF110000 250c SF010000 2510 SF030000 2514 SF020000 2518 SF040000 251c SF080000 2524 SF090000 252c SF060000 2534 SF070000 253c SF050000 2550 SF430000 2551 SF240000 2552 SF510000 2553 SF520000 2554 SF390000 2555 SF220000 2556 SF210000 2557 SF250000 2558 SF500000 2559 SF490000 255a SF380000 255b SF280000 255c SF270000 255d SF260000 255e SF360000 255f SF370000 2560 SF420000 2561 SF190000 2562 SF200000 2563 SF230000 2564 SF470000 2565 SF480000 2566 SF410000 2567 SF450000 2568 SF460000 2569 SF400000 256a SF540000 256b SF530000 256c SF440000 2580 upblock 2584 dnblock 2588 block 258c lfblock 2590 rtblock 2591 ltshade 2592 shade 2593 dkshade 25a0 filledbox 25a1 H22073 25aa H18543 25ab H18551 25ac filledrect 25b2 triagup 25ba triagrt 25bc triagdn 25c4 triaglf 25ca lozenge 25cb circle 25cf H18533 25d8 invbullet 25d9 invcircle 25e6 openbullet 263a smileface 263b invsmileface 263c sun 2640 female 2642 male 2660 spade 2663 club 2665 heart 2666 diamond 266a musicalnote 266b musicalnotedbl f6be dotlessj f6bf LL f6c0 ll f6c1 Scedilla f6c2 scedilla f6c3 commaaccent f6c4 afii10063 f6c5 afii10064 f6c6 afii10192 f6c7 afii10831 f6c8 afii10832 f6c9 Acute f6ca Caron f6cb Dieresis f6cc DieresisAcute f6cd DieresisGrave f6ce Grave f6cf Hungarumlaut f6d0 Macron f6d1 cyrBreve f6d2 cyrFlex f6d3 dblGrave f6d4 cyrbreve f6d5 cyrflex f6d6 dblgrave f6d7 dieresisacute f6d8 dieresisgrave f6d9 copyrightserif f6da registerserif f6db trademarkserif f6dc onefitted f6dd rupiah f6de threequartersemdash f6df centinferior f6e0 centsuperior f6e1 commainferior f6e2 commasuperior f6e3 dollarinferior f6e4 dollarsuperior f6e5 hypheninferior f6e6 hyphensuperior f6e7 periodinferior f6e8 periodsuperior f6e9 asuperior f6ea bsuperior f6eb dsuperior f6ec esuperior f6ed isuperior f6ee lsuperior f6ef msuperior f6f0 osuperior f6f1 rsuperior f6f2 ssuperior f6f3 tsuperior f6f4 Brevesmall f6f5 Caronsmall f6f6 Circumflexsmall f6f7 Dotaccentsmall f6f8 Hungarumlautsmall f6f9 Lslashsmall f6fa OEsmall f6fb Ogoneksmall f6fc Ringsmall f6fd Scaronsmall f6fe Tildesmall f6ff Zcaronsmall f721 exclamsmall f724 dollaroldstyle f726 ampersandsmall f730 zerooldstyle f731 oneoldstyle f732 twooldstyle f733 threeoldstyle f734 fouroldstyle f735 fiveoldstyle f736 sixoldstyle f737 sevenoldstyle f738 eightoldstyle f739 nineoldstyle f73f questionsmall f760 Gravesmall f761 Asmall f762 Bsmall f763 Csmall f764 Dsmall f765 Esmall f766 Fsmall f767 Gsmall f768 Hsmall f769 Ismall f76a Jsmall f76b Ksmall f76c Lsmall f76d Msmall f76e Nsmall f76f Osmall f770 Psmall f771 Qsmall f772 Rsmall f773 Ssmall f774 Tsmall f775 Usmall f776 Vsmall f777 Wsmall f778 Xsmall f779 Ysmall f77a Zsmall f7a1 exclamdownsmall f7a2 centoldstyle f7a8 Dieresissmall f7af Macronsmall f7b4 Acutesmall f7b8 Cedillasmall f7bf questiondownsmall f7e0 Agravesmall f7e1 Aacutesmall f7e2 Acircumflexsmall f7e3 Atildesmall f7e4 Adieresissmall f7e5 Aringsmall f7e6 AEsmall f7e7 Ccedillasmall f7e8 Egravesmall f7e9 Eacutesmall f7ea Ecircumflexsmall f7eb Edieresissmall f7ec Igravesmall f7ed Iacutesmall f7ee Icircumflexsmall f7ef Idieresissmall f7f0 Ethsmall f7f1 Ntildesmall f7f2 Ogravesmall f7f3 Oacutesmall f7f4 Ocircumflexsmall f7f5 Otildesmall f7f6 Odieresissmall f7f8 Oslashsmall f7f9 Ugravesmall f7fa Uacutesmall f7fb Ucircumflexsmall f7fc Udieresissmall f7fd Yacutesmall f7fe Thornsmall f7ff Ydieresissmall f8e5 radicalex f8e6 arrowvertex f8e7 arrowhorizex f8e8 registersans f8e9 copyrightsans f8ea trademarksans f8eb parenlefttp f8ec parenleftex f8ed parenleftbt f8ee bracketlefttp f8ef bracketleftex f8f0 bracketleftbt f8f1 bracelefttp f8f2 braceleftmid f8f3 braceleftbt f8f4 braceex f8f5 integralex f8f6 parenrighttp f8f7 parenrightex f8f8 parenrightbt f8f9 bracketrighttp f8fa bracketrightex f8fb bracketrightbt f8fc bracerighttp f8fd bracerightmid f8fe bracerightbt fb00 ff fb01 fi fb02 fl fb03 ffi fb04 ffl fb1f afii57705 fb2a afii57694 fb2b afii57695 fb35 afii57723 fb4b afii57700 htmldoc-1.9.7/desktop/000077500000000000000000000000001354715574200146505ustar00rootroot00000000000000htmldoc-1.9.7/desktop/Makefile000066400000000000000000000014711354715574200163130ustar00rootroot00000000000000# # Makefile for HTMLDOC desktop files. # # Copyright 2017 by Michael R Sweet. # Copyright 1997-2010 by Easy Software Products. # # This program is free software. Distribution and use rights are outlined in # the file "COPYING". # # # Include common definitions... # include ../Makedefs # # Make everything... # all: # # Install everything... # install: if test `uname` = Linux; then \ $(INSTALL_DIR) $(BUILDROOT)$(datadir)/applications; \ $(INSTALL_DATA) htmldoc.desktop $(BUILDROOT)$(datadir)/applications; \ $(INSTALL_DIR) $(BUILDROOT)$(datadir)/mime/packages; \ $(INSTALL_DATA) htmldoc.xml $(BUILDROOT)$(datadir)/mime/packages; \ $(INSTALL_DIR) $(BUILDROOT)$(datadir)/pixmaps; \ $(INSTALL_DATA) htmldoc.xpm $(BUILDROOT)$(datadir)/pixmaps; \ fi # # Clean out object and library files... # clean: htmldoc-1.9.7/desktop/htmldoc-128.png000066400000000000000000000053431354715574200173250ustar00rootroot00000000000000PNG  IHDRsRGBiTXtXML:com.adobe.xmp Michael Sweet Copyright 2017 Michael Sweet New Icon yP~PLTE   "()*+/2568<= > B C D E F L N O P S U W X Z [ \ ] _cdfhiqrtuyz| !!"""####$$$$$$%%%%%%&kJetRNS  !"')*+,-.138=@AFGJLMOPQVWY]_aehklnoqstwyz{~X{IDATx[@pj lVԁκJ1p np{[q_ajJJ[}cx.{s SOcOrWi{p2YNWȋ7!@P@{hyEe@Q1 5 9p6<9XXsT G&@?,f8OH+Ql.K?iB?@ù.DSO~+ c}||Vœ(BA7.kyr)#Qn)dnz*_\v3bA+KxVqvC";/%, r.X|;ᷳ 2c;mOh߭iނ[>ї9,DPK)^|b/ȍb;RHQαe$=/pP|ǹy,G^d7f?N!A@@@@@ u:`=z]86h`Vh7qݘ~>k# M\DVhS꧴2EGS^>Ry>&IHBzR}\hSU15&ugK64TS ̆C_e>:ܸe) U{`Z66EÔ-(c}s͚[,-ҼYFƨM<b̉ J9T/֠GH[LBu5j2֮#HjkլCUJTS5t&\cC | IENDB`htmldoc-1.9.7/desktop/htmldoc-256.png000066400000000000000000000125221354715574200173240ustar00rootroot00000000000000PNG  IHDR\rfsRGBiTXtXML:com.adobe.xmp Michael Sweet Copyright 2017 Michael Sweet New Icon yP~(IDATx{\Ugݝ}vw>xZ-Д XlK)oZ(Ђ!D#&E A0 (Z #ã>xpwۙݹ3|ni;s~DpWqxxHx[˻շoR___jc*M|g2RW.O6yn0@N<4*C^߱x 0&V ]@p2k68xPP^T&QM4vPt`SʸPUJ:_mM(*7+{%O~  7\VL ÿ@, ˋ!p{h|X2{htXqH y$ t@8m344@,yF-uT+T= xd@2;Q@x_q )Z)0h2aQeVN_#,Qb[3Q@' ;3 ?Ѡ^U=F9z8𒳕Ќ@ItKQ'7'2'ACxpsɬ7@ Y\IgiH/yVL5 X?h7=4$Qە`@nmKVsVB] 5rKm{@P1h@RB^lmS`. 5s[{[h@,3^ģf7i@V 4 ,Pg+PG@Y `r8@ @  @ @ @ @ @ PBYNCwQ?PhNWUq?Ywp @  @@@ :jkOH?ѓHjBwL_"}N"@1 =tp O.`"@Q}NjG"@ {@G@XV@.<}+ (F@P"@>GOW@vAw%ҟl@Q`Y}"Y7'+vF3>݀ 6[F#Pg{Ta>'ȏ$߱6"@ oLK9 ̲~M["F"xTEzZ9$LH_j n"_.k-omNюX@aMfQ'T}ߝMTMOhLU"(?Dl L@*7],9f~Q"(D|7sJUbz2Pй6cyp_A߲mX ?Wkm&_}!Ua7KS鎪x$PlFs6Joa3y"u `|4XP77g6 m9';‹(!"zȦVP&xrċ6EcnYRGGC`=\nPʯ`:3D1'SЉ[)W txUM}vcV^j@7X, n߉6 o#ߜ]{7w| a_hf+q+$"9*?h/{;3SUe qdNי}MދdfZ_ܭ8DoUr+\Z5U>ہݰm =-7Dp뎶Ɗ'Oϓ@nzќ >``( h#E,3gNTp_3˟ݔY'mC[ɿҖ9S3cD}2s\z{L4_pP zE;hxա&{´" (΀[8w?{gh~!(H7]<rEI^̀ {ݻ%QOWWK)>:LP8nA[? /wt?]"(SpZH}ҺL*;$Gn91 _bvlf/s O܏Kn9N+Z2{*O#1 z(~YdSas[2(\]m=r.(_nˬDۆlEF-yo?\/nEJ-y@P"JmK)-D+WqZKC1ۖ3@zk @B    @@@ @@ @   @ @ @@ @ @Ј,whD/yx !hH/yaX`tpjV10l0;.MUsg ̗aV}<n@Ix@\L.SFU<4 pUm\5ǻEe^Y\lK#܉"}]6Gnq 7( 1oSNY -Q\c?R*>L4D$eڤp*j|J_|Mϋ%e@П_>EبLUFWf)Csel2*EG@0EؤZ8 B"Xai2j|=6qhH+A?ެ}딅 AeSj M,N"SuX'K-U1X qܴ)2w|#}ӳǻەVeb2R6/IENDB`htmldoc-1.9.7/desktop/htmldoc-32.png000066400000000000000000000026771354715574200172460ustar00rootroot00000000000000PNG  IHDR(p sRGBiTXtXML:com.adobe.xmp Michael Sweet Copyright 2017 Michael Sweet New Icon yP~PLTE     #'(,.013345799 ;= C C D E H K P P S U V [\]_beefiinpqrryz  !"###$#%$%%OtRNSV#IDAT(c`F<3## vy/')FFY O-,|Vչʌ:Qά|(!yn$75iPFUuAPIDzXI:(Vɪ+ҙQT'3__$[_(4ƪ(ȩ^S + 0R/,Kjفg)M@I7$F~9הh Michael Sweet Copyright 2017 Michael Sweet New Icon yP~5IDATX WOA}wC>(& K , QX[kP((h:!ĘA@Q4'{;~xb[%owg7ﷳ3;>!jyCBϮTI`@gx}O*]g]$R>f^,!ZM@-{@487:uy߫Ep)\so&sZMTr?{-@hRv S| mCr'0u |!%pOy bB6HsB\x>9 OY;';Maf|遹 Kߦ6맜pJk ȎMיj /l.d#iYtsbmN6lf2NyFYtɝp]&8Ȕ G}fY=" ;ۥsvЗWXc$Zl=,hZUqHuN@H1BVHise%" _/?(j:爷D7c?IENDB`ic12PNG  IHDR@@iqsRGB pHYs%%IR$iTXtXML:com.adobe.xmp Michael Sweet Copyright 2017 Michael Sweet New Icon yP~YIDATx_UefYd)bPZQPI=DA!SHX> AQPA=C/eAT&DEQ ޵Uk\vwwuν;rsg99gΙ5+`Q#/:eLg][pn4k+LvQchReY-6aNA η(Hg+PJ~ y̯4|/ &E.g8R,H.E"*̝9 &ڜ aLjsqC t̛<3t.X;W.<ܝ;W.<ܝ6̖#E%37ͮ\2qw{̦*C&Zy {4Isew5֥xт1u)5;\.C7GUZ =s>.&@wL\ur'a*! S _?Klp¬'nW(yħxD#w؄zM}f3;Me?CDzfdG'Hw5soA}Aj=V|rOflFu3̞fqcf-á]-6۽ग_c54;xȳH$"mfO3;F^l=D\D) [DQ(TXNL&w488b%}V"}//X;Xv[v}ߌ ^∙el`W6 ӭЏ *#^|LґM_Y&>\[zJ熫Q5͞ F4W!yQ(RE2_;r,xsGCQ 4lÒϗKhcVw>Zg5a8O"<㖚-}fs^Pe"UrxщxƮH"ry9x!QeB%6HPzR9!mIѥN(YRsbSk ZkI[3Vx }` l&u&ݲвiR h-L-k&u, zm:q|._g5{Lx ꇖ7BNd<&Zhڊb#@ s@@+;v_ Q)[bm򷥰jϣ}( 6wW5hWxC["ڋ*n#V bHD84k8݈n@Kh?c}+&\ DAT3ܐLN5lH 0щ< *H L8yTD* Sd̓"5_̓r̓̓̓̓̓ &&&&&&&& && &&&& &$ &&& &$ &&& &$ &&& &$ &$ &&&$ &"&&%&$ & &&%&$ & &&$&$ & &#&"&$ &%& &$ &$& &% &#& & &$ && &!& %&"&% &#& && &&$&% %&$&&&"$&&&#&"&#&& &%  & &&&$ %&&& &"$&&& & !&&& &%  &&&& &$&&&&&&&&&&&&t8mk@ VəV !!,,"" ))ee   !! ''**,,................................................................................................................................................................................,,**'OO' !@@!  8kk8 .MM."@aa@"1OzzO1"=YY="+F__F+ 1JassaJ1  3J_nɈn_J3 1FYhq~ʧ~qhYF1 +=O]hotwyzz{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{zzywtoh]O=+  "1@MW_ehkllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllkhe_WM@1" ".8AGLOPQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQPOLGA8." !'*-........................................................................................-*'! ic08PNG  IHDR\rfsRGB pHYs  iTXtXML:com.adobe.xmp Michael Sweet Copyright 2017 Michael Sweet New Icon yP~cIDATx -U}ʪ@"J )4Ĕ -,$"!E!F!e*!((A)P (""Yþ/73.3wzgt߾}}}2) @ @ @ @4 jQAbzc$JYccq*~*Ń9KseUT/S 6/7*.S\I1i6 *١1 (U<5\x(R AG_Zq JEVwST0 L X;PI&o{6UnmAr@qX+`.mŦUlm@#߃UDOj䋙Yu& y-~ƒ*H@uh[cv k{w')H@ Xl\ \# =~$@Uk6 ܵ +;  k6Nv gY]C`_[t}/.rh2kڍ^@z>3/kl~BF>@&`ZalW:8NV` x֮5l-w{iM0" Ȏ= Fi. ` XE{{~ ȏk ;зfGT`I@~b`RNv$@ ?nRGD^,V8Dߙ}3 ȏ@&/ޙb0 C]N(u~OS@BǞ/b%Oߏ|@ +E5>RNY&+t eCyT b:@nB1 +0!7 r/r%e!2dh0 9>ŸVz&)^Yx8}jFpTKZa!:oWz)ۖҔDiYJoV\xJ++| _#h jq$$@Izo+׊F0#Ciu @;.NwܓfϪWwoJ Rz\RUjS` U~!SHimUL,C83WG#CcGPs\B?NJ $2R<kvܡBUiK\-v69 ~Ii[5Oʹ,`jOSz וRG{`Pv;}[bA\At$FsѼY<8=*4ںq8kڎW[y:ZRt9L.A3ހjV镊Hu ߗ)* B; v"sv_3R=ڽjpg|?ni4iU{dd4S PّWV?W,I.΅U4,NޫӺ^uOH`?g}>œN mEq^uTc0 R̛["\0v:} ####ho**DuA}裚pGZkd12]bG4X7 6ݦ#:mZ YX5ME殛*h?qsc wK^uHm0;_ݯӘH骊n&@.Ո衑7,Mk  <=Ն.SØ|nrWz> 3%C"iNSrrPκ{)})bJ6l.Ⱦv4t2yOT# ]M %ϪݥvGL|m(ڲw(E:{jH冲gPtݛ}/l R ͻǼi g ~]5/6R֤:uSSqڑ!|#gtO@lR7{h W_JPP"/OY| Sc)sN>==e:ׯ:ojgJ&!].5yK p(O]u.ԑ6(_h|z@ѥʚئ/C."TeɍwDR?rޣ Sje$?EGc$5tw괏8y94}{$#t{Ǖ_N59 Nir,:fu)qтoT_Pw.{/h_vM hꧏbCU?}7kqry7^:Px(r!LhDw.ӻuI24$o_1Ǒږn ` t.am%5\=A<_?+F9k}Sw? [u=W#:nDS?GKu<\b׆>cq\mJEa3 ?|FX)z*FgHwv?k~(]kH3' l%$Q+ڱ{^j ^I#glj@<"dU],%T˓A +@VBZ@<"dU],%T˓A +@VBZ, |gZ :%YI/J)H@n&'V_M~ȽUDZ" b@+C @0W>E@@ `-| 6Z\m-&):0ZLhqSt`ʧhh1 ŕO! b@+C @0W>E@@ `-| 6Z\m-&):0ZLhqSt`ʧhh1 ŕO! b@+C @0W>E@@ `-| 6Z\m-&):0ZLhqSt`ʧhh1 ŕO! b-C!3);<3-&0v1Z C gSjw*X?3-&`Z}S/̰onL`yuj;2+/L!,r3钮\,r `ܵ +:cSMH@& NHXܕ@ , `Q̠hEqǍ  k6[ԴKZ#cLʧ) l7q@@,酱Xb h>Ek6k-5R4X(ȕ/ech0+oۘ4XNz0?PQ h.kZ BEh^<|_^45jZ0Oe E\s34i^=6;]p&;HlY?4iZ[k8 T=0o0⇚yV5k  `S(W, ; {֢5٩S鮴jגw:bu{*P AsClO(6 ~FEQ4?{$@`n\Za[??p z @y "@7[+H> GhvbgS^v}T3tG@b0Oź zA)#p6K~#7r$W^ 4L 6/MY8Y P!;o)|W+x0f,^FeK;*P jX+|#6/u_4z|#żag+Hܪ_T:} _댤A{!i, 3]+<.L/_T~/v;/Mj~{B؋4e6SpZ $LAbBU>}G#nQ؝c!rosÝKw A ܭW*,;>pi瀟!d꣩(Xou>݀+pMk+QRw^' 86WNtC 0,{f60>w7t?e)?.v>^7LF`XKa3Q,PfM)l">]pR: "`#E§)),j&-#zį#GrOML i¢ιE] MahvBށr%|h&_MŦC#Z6b,M[Bv$ S h}m0}L tj8``y@ˢG<1MĩdZm3 M$F< }-~GӈCmGYBٝۊbvĠĩ!|C eG gxA{[3Rxgb{Z6z44諑ۏL!D!|[0O-8{+N1Ol7zf.Av=-zgX"4;n,'A !TO#B!8NL۩,$?IENDB`ic13PNG  IHDR\rfsRGB pHYs%%IR$iTXtXML:com.adobe.xmp Michael Sweet Copyright 2017 Michael Sweet New Icon yP~cIDATx -U}ʪ@"J )4Ĕ -,$"!E!F!e*!((A)P (""Yþ/73.3wzgt߾}}}2) @ @ @ @4 jQAbzc$JYccq*~*Ń9KseUT/S 6/7*.S\I1i6 *١1 (U<5\x(R AG_Zq JEVwST0 L X;PI&o{6UnmAr@qX+`.mŦUlm@#߃UDOj䋙Yu& y-~ƒ*H@uh[cv k{w')H@ Xl\ \# =~$@Uk6 ܵ +;  k6Nv gY]C`_[t}/.rh2kڍ^@z>3/kl~BF>@&`ZalW:8NV` x֮5l-w{iM0" Ȏ= Fi. ` XE{{~ ȏk ;зfGT`I@~b`RNv$@ ?nRGD^,V8Dߙ}3 ȏ@&/ޙb0 C]N(u~OS@BǞ/b%Oߏ|@ +E5>RNY&+t eCyT b:@nB1 +0!7 r/r%e!2dh0 9>ŸVz&)^Yx8}jFpTKZa!:oWz)ۖҔDiYJoV\xJ++| _#h jq$$@Izo+׊F0#Ciu @;.NwܓfϪWwoJ Rz\RUjS` U~!SHimUL,C83WG#CcGPs\B?NJ $2R<kvܡBUiK\-v69 ~Ii[5Oʹ,`jOSz וRG{`Pv;}[bA\At$FsѼY<8=*4ںq8kڎW[y:ZRt9L.A3ހjV镊Hu ߗ)* B; v"sv_3R=ڽjpg|?ni4iU{dd4S PّWV?W,I.΅U4,NޫӺ^uOH`?g}>œN mEq^uTc0 R̛["\0v:} ####ho**DuA}裚pGZkd12]bG4X7 6ݦ#:mZ YX5ME殛*h?qsc wK^uHm0;_ݯӘH骊n&@.Ո衑7,Mk  <=Ն.SØ|nrWz> 3%C"iNSrrPκ{)})bJ6l.Ⱦv4t2yOT# ]M %ϪݥvGL|m(ڲw(E:{jH冲gPtݛ}/l R ͻǼi g ~]5/6R֤:uSSqڑ!|#gtO@lR7{h W_JPP"/OY| Sc)sN>==e:ׯ:ojgJ&!].5yK p(O]u.ԑ6(_h|z@ѥʚئ/C."TeɍwDR?rޣ Sje$?EGc$5tw괏8y94}{$#t{Ǖ_N59 Nir,:fu)qтoT_Pw.{/h_vM hꧏbCU?}7kqry7^:Px(r!LhDw.ӻuI24$o_1Ǒږn ` t.am%5\=A<_?+F9k}Sw? [u=W#:nDS?GKu<\b׆>cq\mJEa3 ?|FX)z*FgHwv?k~(]kH3' l%$Q+ڱ{^j ^I#glj@<"dU],%T˓A +@VBZ@<"dU],%T˓A +@VBZ, |gZ :%YI/J)H@n&'V_M~ȽUDZ" b@+C @0W>E@@ `-| 6Z\m-&):0ZLhqSt`ʧhh1 ŕO! b@+C @0W>E@@ `-| 6Z\m-&):0ZLhqSt`ʧhh1 ŕO! b@+C @0W>E@@ `-| 6Z\m-&):0ZLhqSt`ʧhh1 ŕO! b-C!3);<3-&0v1Z C gSjw*X?3-&`Z}S/̰onL`yuj;2+/L!,r3钮\,r `ܵ +:cSMH@& NHXܕ@ , `Q̠hEqǍ  k6[ԴKZ#cLʧ) l7q@@,酱Xb h>Ek6k-5R4X(ȕ/ech0+oۘ4XNz0?PQ h.kZ BEh^<|_^45jZ0Oe E\s34i^=6;]p&;HlY?4iZ[k8 T=0o0⇚yV5k  `S(W, ; {֢5٩S鮴jגw:bu{*P AsClO(6 ~FEQ4?{$@`n\Za[??p z @y "@7[+H> GhvbgS^v}T3tG@b0Oź zA)#p6K~#7r$W^ 4L 6/MY8Y P!;o)|W+x0f,^FeK;*P jX+|#6/u_4z|#żag+Hܪ_T:} _댤A{!i, 3]+<.L/_T~/v;/Mj~{B؋4e6SpZ $LAbBU>}G#nQ؝c!rosÝKw A ܭW*,;>pi瀟!d꣩(Xou>݀+pMk+QRw^' 86WNtC 0,{f60>w7t?e)?.v>^7LF`XKa3Q,PfM)l">]pR: "`#E§)),j&-#zį#GrOML i¢ιE] MahvBށr%|h&_MŦC#Z6b,M[Bv$ S h}m0}L tj8``y@ˢG<1MĩdZm3 M$F< }-~GӈCmGYBٝۊbvĠĩ!|C eG gxA{[3Rxgb{Z6z44諑ۏL!D!|[0O-8{+N1Ol7zf.Av=-zgX"4;n,'A !TO#B!8NL۩,$?IENDB`ic09KOPNG  IHDRxsRGB pHYs  iTXtXML:com.adobe.xmp Michael Sweet Copyright 2017 Michael Sweet New Icon yP~@IDATx 5UYDPQK볲,Scj$䡲jH,MSUji'xߗUwgϞ=kߺ{5kϬ=kT @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ :,8XɎذ _v']en'#@@*-.jU+e[e[6싊/O<~X d˜G !pvΒy+V>e?aQ@+KVgdݰ(E2aUG~Qv@).<:`a2;7_쩲e@8_ oUK ,s/usey 0-O0|앲/ll4@~}2_'@"/}<X33SvEFB@U wD(";8_,5~{>@AtȖLDQ`Q!+C 0WAB'|R:D!}k>!@3knoġϮ:4{d3P/0Bw= @5\koXZ8 6{=qlD @@'q 49kFL\pv[ +@ &ko3 iok;dX  X{C6ȺF9Q 0G M:qjF Ee/!@脀7kqsT;6œ8 9 '  Nd r6bdgl-@@YZuza;8 am-> @芀wgئa@}].K& y;}:Ƨ7 {@Z%` >6V;$!Xh2&u @O ~N^-axG!rGm ̃ T,L@JZ'04{dAF^#+K@B t8bWC[ϩ}sX= : tG`&G^nv8hȋ byɀ @`ZbnRk8n4X68D-[=mv _÷TOMUuUKc9sKe5~ > ]WUoUA`Fh{;?tQU=Xf,Pr?3אٺ˫(]z׫Bp.`Da{3~֕*>@>@ .Ԅg]YU^KtWUՕZ.!qik5G;j88B=k% _][>} U#p\SU~&nN@L@c;YU~6%dG=~_`Ձ4|#@ ;U?SӜݙ9{kvhTU[7J2|.WYL@ TGkحUVM\6#}gг>B9%L>@@\@k̉WO4%v% :H>0 n\Km҈D=CeG8P&`HXk @$pԁ bxmz5z0ƎojGpɵ6γc`37lŻa)>KFzoOP}Yzue] ;oXb|8|KsT8JTud~zUӠ5ļLǗy(0L/I?A ?W6^MGA?B4U?[?RIE:m2v$J@u;rWU2(+$7osBp =aa>0ķxϭUz%* N |E~Oѓ7@zAϥ=?X5#7g`$"\zGIO[ %'"o\ĥzwFp2ҥ s|oԟ:_%Z|?Oeߖ#pc|%pr>o⾟i"'h-UuĿE@49ZU%{X/ X4pH=ƹCpv@2]Fi?>@X-;zEU`{5!;ovz !G K :G|FvoC?~9ϋ#c:! (Q}h]x^?ԗ+ƉyE9g#c?*<`fUªzU^>4T&@?;\{4xA1U?t 'Ev*@!?hx ,_(1[/4&-;`jdn?X?@yH'jayUu%=Cۂ0֓?#@3+$'x'p-N@jm8="h}]#u ΁=(i 0g{IMwU}XUUǫ9xνCuK.ܫ@]uUuO ˽L(e4V5"{ۗ5}˛}@]~o{ '$]o.FZ]a/}uw hh4goh$_].SuWzTI f%KclXtOX8яk{q ^y@UU|W{`z]@weQY\77sxUf-aGKI?hxߓ_~{R$0AG|Rw`⡺hvFNۥܟۣ^)X<}t*DiT ~IOI5j<2`lixgV":~+͚/ׯ<*:S&st[ d'ߩuÙO?Fwy>QXvKPN4kL$c8c:¯>I'؞i*<f5úx^TUSlf"߯Qͼ'ً';쩺X) =Oz&`]^:B'./7psfEVu.԰}zQfARi6z/5O:nލI7zl#{[1:BI]so%/^UكY@Oi/"  Ӹ_%V1&(]V}*9``|4\z [dSl@k.ZN:@uo]O{.ו,5r}/)n8ooe3[p~U#SK t+_y?mG?&YY{Ɖ:ۿ-:9Y,?٬٬%+ N?RC/هo%MJ 9P%ggoY_'?vkUܥΟ 8s;8T/0]KzL>|hU}w,ptc\="I(ۙWg[U[jHK]=?`?Tڍ0Jy~uu۪.jXV%7,ң4AwJ]&Cua͵Hg\6%ixWtNtTgjG? vws/zJ ~Loj,<]߬*M @?G]N`IFcz? ~~(TZ V}Ec'^>\҂ ˃"ɞ+pzNg?*󎨪h/EctY׬?2Ŀ?K_2u½$on o>g;= &˾]fbM; ~ I', ?a)+j:aSZʞ/>OXC?Wقr2%?\t'F oe=o͓Y!]m|yK\/G9*^  8zׯ?7 StY#:+Q98, 5 Ioۺ7|_MZ~z(_OخCxtx ~(ү CtۓΔZpnwo{j~˟;\|WitίH3߶{^Orά74Mnfܗk}t4wE wiR5koפYѬ/IOx oӵ`:^^ۗ}̓.kx8@_ :{uSN]Mr_@!i 5i~-G`0s?!W5L\wZ;@AnhiMD/I~%}g~-]UU5w.OYg 0=tx~? O%C,p ;IZ7h[-qg@`GsE^O{F y玌9,s7kk8}{ҳեV|kx}߾kxG!Qtkɺ,p H\ӻٽU&pV֪y-a}q =}Op˯KCB=w:I1]yGpfF<l[t=/Oϰ'Gp=_+Q=?%~x%:,_Rݦ{& @Ԛ56i(+*8Wj]#ve@ Z8 6BsRC#>_y!@5Z:HcM\yCghC  LNi jm=}vGަx zn\ |@к:qjNF9rPsѐܰ*( ,5ϱ<h|;!;gBӱm͜-ˆ< @dֵɶ`t!+k0%(=Dˑ$;r.e@@>bgAq,@Tdvp9/s>׷=O~Sv6 "XYAY,,!ۅg`jW9kCKZIb;ÂΗ#C N |̣Aoo "Uf9C,8:"rVy 8G +2 <[8ϱr@]NV.2,xʏ㻼./#mC'聒@ X-W,!? `/o-dur<("ϱ/ xH >2 @`o?Ao <Bcֳkbq#\u^?@3ev @]~[,}[;bp#?g~p\PHG\>/:A:R'e(CI @`n,ʟ]Eq#1PC[+Ƕbzzڇ+lo@s#N٧de!!!,:z]:3%BFܢ,y9s=eoP' #p' ?Β5YC;.9!vB#nQ]˃ZA:oN#%ewqǀ  @`j$|[z~CCC#&}>ʊ:wNgZ,9#IDATuжVMި2w#Ic`w 0Zg~;> 1qn" X?Mb嶂n>3v30??yb(儹z{m @A'_ذmCx#$qnG^xp*G9Vv{"9Ex' ?8/@8s8ˇʎ#;PU@+@z\WeʲF: 8cw8q,e䲣Z)|QA#wAq^g' ꮷk7c02?ry@X~d˶,Ϋ-;3up,mr.eG&/bRq;; !'qy!dG sGlו-ڐcr|'''Cy6mE  XCH-vҶkdW;-?1!C#΂yhB , j Ю;kQ62|rze娣-8M9yNGv@3Ѫ;+3!G1 tK.ZD:A:5%%{vr٢(?hKNs]:串qu"6Lj'guBGZMi/GD1 GQrwqhNhJCW"8z:֋m^E=-j;hv#Y cXg@q"@G3A@Dg6ܖA:!:r#R7HSB[,N ub[ǡ[96MZ"w8蜀3(:o,/bX9ϡ @]l^v:ӱ\X8reFv:BNG^o4hDCr[#xՅ Michael Sweet Copyright 2017 Michael Sweet New Icon yP~@IDATx 5UYDPQK볲,Scj$䡲jH,MSUji'xߗUwgϞ=kߺ{5kϬ=kT @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ :,8XɎذ _v']en'#@@*-.jU+e[e[6싊/O<~X d˜G !pvΒy+V>e?aQ@+KVgdݰ(E2aUG~Qv@).<:`a2;7_쩲e@8_ oUK ,s/usey 0-O0|앲/ll4@~}2_'@"/}<X33SvEFB@U wD(";8_,5~{>@AtȖLDQ`Q!+C 0WAB'|R:D!}k>!@3knoġϮ:4{d3P/0Bw= @5\koXZ8 6{=qlD @@'q 49kFL\pv[ +@ &ko3 iok;dX  X{C6ȺF9Q 0G M:qjF Ee/!@脀7kqsT;6œ8 9 '  Nd r6bdgl-@@YZuza;8 am-> @芀wgئa@}].K& y;}:Ƨ7 {@Z%` >6V;$!Xh2&u @O ~N^-axG!rGm ̃ T,L@JZ'04{dAF^#+K@B t8bWC[ϩ}sX= : tG`&G^nv8hȋ byɀ @`ZbnRk8n4X68D-[=mv _÷TOMUuUKc9sKe5~ > ]WUoUA`Fh{;?tQU=Xf,Pr?3אٺ˫(]z׫Bp.`Da{3~֕*>@>@ .Ԅg]YU^KtWUՕZ.!qik5G;j88B=k% _][>} U#p\SU~&nN@L@c;YU~6%dG=~_`Ձ4|#@ ;U?SӜݙ9{kvhTU[7J2|.WYL@ TGkحUVM\6#}gг>B9%L>@@\@k̉WO4%v% :H>0 n\Km҈D=CeG8P&`HXk @$pԁ bxmz5z0ƎojGpɵ6γc`37lŻa)>KFzoOP}Yzue] ;oXb|8|KsT8JTud~zUӠ5ļLǗy(0L/I?A ?W6^MGA?B4U?[?RIE:m2v$J@u;rWU2(+$7osBp =aa>0ķxϭUz%* N |E~Oѓ7@zAϥ=?X5#7g`$"\zGIO[ %'"o\ĥzwFp2ҥ s|oԟ:_%Z|?Oeߖ#pc|%pr>o⾟i"'h-UuĿE@49ZU%{X/ X4pH=ƹCpv@2]Fi?>@X-;zEU`{5!;ovz !G K :G|FvoC?~9ϋ#c:! (Q}h]x^?ԗ+ƉyE9g#c?*<`fUªzU^>4T&@?;\{4xA1U?t 'Ev*@!?hx ,_(1[/4&-;`jdn?X?@yH'jayUu%=Cۂ0֓?#@3+$'x'p-N@jm8="h}]#u ΁=(i 0g{IMwU}XUUǫ9xνCuK.ܫ@]uUuO ˽L(e4V5"{ۗ5}˛}@]~o{ '$]o.FZ]a/}uw hh4goh$_].SuWzTI f%KclXtOX8яk{q ^y@UU|W{`z]@weQY\77sxUf-aGKI?hxߓ_~{R$0AG|Rw`⡺hvFNۥܟۣ^)X<}t*DiT ~IOI5j<2`lixgV":~+͚/ׯ<*:S&st[ d'ߩuÙO?Fwy>QXvKPN4kL$c8c:¯>I'؞i*<f5úx^TUSlf"߯Qͼ'ً';쩺X) =Oz&`]^:B'./7psfEVu.԰}zQfARi6z/5O:nލI7zl#{[1:BI]so%/^UكY@Oi/"  Ӹ_%V1&(]V}*9``|4\z [dSl@k.ZN:@uo]O{.ו,5r}/)n8ooe3[p~U#SK t+_y?mG?&YY{Ɖ:ۿ-:9Y,?٬٬%+ N?RC/هo%MJ 9P%ggoY_'?vkUܥΟ 8s;8T/0]KzL>|hU}w,ptc\="I(ۙWg[U[jHK]=?`?Tڍ0Jy~uu۪.jXV%7,ң4AwJ]&Cua͵Hg\6%ixWtNtTgjG? vws/zJ ~Loj,<]߬*M @?G]N`IFcz? ~~(TZ V}Ec'^>\҂ ˃"ɞ+pzNg?*󎨪h/EctY׬?2Ŀ?K_2u½$on o>g;= &˾]fbM; ~ I', ?a)+j:aSZʞ/>OXC?Wقr2%?\t'F oe=o͓Y!]m|yK\/G9*^  8zׯ?7 StY#:+Q98, 5 Ioۺ7|_MZ~z(_OخCxtx ~(ү CtۓΔZpnwo{j~˟;\|WitίH3߶{^Orά74Mnfܗk}t4wE wiR5koפYѬ/IOx oӵ`:^^ۗ}̓.kx8@_ :{uSN]Mr_@!i 5i~-G`0s?!W5L\wZ;@AnhiMD/I~%}g~-]UU5w.OYg 0=tx~? O%C,p ;IZ7h[-qg@`GsE^O{F y玌9,s7kk8}{ҳեV|kx}߾kxG!Qtkɺ,p H\ӻٽU&pV֪y-a}q =}Op˯KCB=w:I1]yGpfF<l[t=/Oϰ'Gp=_+Q=?%~x%:,_Rݦ{& @Ԛ56i(+*8Wj]#ve@ Z8 6BsRC#>_y!@5Z:HcM\yCghC  LNi jm=}vGަx zn\ |@к:qjNF9rPsѐܰ*( ,5ϱ<h|;!;gBӱm͜-ˆ< @dֵɶ`t!+k0%(=Dˑ$;r.e@@>bgAq,@Tdvp9/s>׷=O~Sv6 "XYAY,,!ۅg`jW9kCKZIb;ÂΗ#C N |̣Aoo "Uf9C,8:"rVy 8G +2 <[8ϱr@]NV.2,xʏ㻼./#mC'聒@ X-W,!? `/o-dur<("ϱ/ xH >2 @`o?Ao <Bcֳkbq#\u^?@3ev @]~[,}[;bp#?g~p\PHG\>/:A:R'e(CI @`n,ʟ]Eq#1PC[+Ƕbzzڇ+lo@s#N٧de!!!,:z]:3%BFܢ,y9s=eoP' #p' ?Β5YC;.9!vB#nQ]˃ZA:oN#%ewqǀ  @`j$|[z~CCC#&}>ʊ:wNgZ,9#IDATuжVMި2w#Ic`w 0Zg~;> 1qn" X?Mb嶂n>3v30??yb(儹z{m @A'_ذmCx#$qnG^xp*G9Vv{"9Ex' ?8/@8s8ˇʎ#;PU@+@z\WeʲF: 8cw8q,e䲣Z)|QA#wAq^g' ꮷk7c02?ry@X~d˶,Ϋ-;3up,mr.eG&/bRq;; !'qy!dG sGlו-ڐcr|'''Cy6mE  XCH-vҶkdW;-?1!C#΂yhB , j Ю;kQ62|rze娣-8M9yNGv@3Ѫ;+3!G1 tK.ZD:A:5%%{vr٢(?hKNs]:串qu"6Lj'guBGZMi/GD1 GQrwqhNhJCW"8z:֋m^E=-j;hv#Y cXg@q"@G3A@Dg6ܖA:!:r#R7HSB[,N ub[ǡ[96MZ"w8蜀3(:o,/bX9ϡ @]l^v:ӱ\X8reFv:BNG^o4hDCr[#xՅ Michael Sweet Copyright 2017 Michael Sweet New Icon yP~@IDATx mGY H2ɔޛAQdADmlEۿwVp[  bDAAmT `̐@0SIu> {X{[SY^꭛sN}VR$ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @lO:;Y \7| m#"7uf}|"_osY׏m @@/_~6g6s]*/u>;9?Y"+]uw?]7 [$#$P%Fl;#/jMC#Pt @,KࢸG~Q isعSz.ˤv ?9?!D @e |*n @\ନ_~fF'[sUvDw~4ɶs0já @8$_6=&u'Tf%0Du{$v}%s_"@ @h0&O|vL8N~ѯg}7G~kdcI @>Rϔ}L/iG{8Lkg @ @]OФIX&p̴o)0);6>'-"K @ 6OXֹA<6O؎r;p{n @إs 88p=8f+`Vc;v{wG @>U5wcW S6d?'/G>>D @{ȾշE>!_Fm,vJ>[o@j0&NiF~eM] @ w%5Wms;Ӥ}G:oۙm~D>OA @8?.#Eێ~ۛ{a#?;_uIq"W%K @O ^9bjl^㹯d vWs3Gd~  @ @`Aȹ|=)uЎ uKk}(qqڏY#@ @ <0wjGBg'm.S%@TzA,M"@ @ Eo t(z-}/kv+:u="6:v @ @r>}d$v2KԮO}]Jn\I @8'gG듶sڧ^vku=wꉖ @ 0:e-pm]r֕Mo7\=][; @ @`M.z<*?n֧muvZ@׆oOu% @/}e.Ӱ7θˊܬذv]eE0_Y"@ @x9xOᯣuٗc{쿵f:::u=,# @+,<4FյLu=OoY"@ @(gE>P;߬G`X=iyb|<;= @ D4mqu{-3i*1WݞY|-Ok>o @GQE4_k=ܮWvP;Qqq_,  @ ~˾_' ugno]eTaIwFGO} @ V6"qSI}z)P6Vݞ}όz% @]~KSI}%P6Rn^cɖ @ ЍDMύO5ܬuy5J.ZJ Pe~#_o+ @ go#rٮ5۹Z֎_ewD5WB @= \o#׎ZV[jǾC]?6N|Ed*fI @~o}+}v=uvgno]C.+&H @9!վduYOn^b`]'-s_oQ @ @25oF^+4B זOZ7, @ @^ω\eiءUvӵ]os.K#D @ۑ|ON{N:FV}^s @ @XN|>&9v]G\Ys9\9#8 @8@o#vߨkyTfXƺ.s7wD>ep- @ @`+}"*0P;e^_G\WjG?zl;uGJZa @ @`n̯|m[6C*յiWesFjUZ[#@ @e |1n3Hper}TvGU´e\֜"M;E @ @nD΀@ks=So7c}v+Qݮ_29cD @ plv::V&},TԼ-W]o>w}9 @ثgDnhuĿ.}>4kG?zvs;ˑuA"@ @d3myú=\&a})=h @ @&}sN돶}֬{RS[$n>,Kp=k"K @ @`_&s4n-l}LN~V\os <=s~H"@ @sfvs޹Rۇ꼥[͛2ׇ9oY"@ @".|E>#58'H?s"+?$ @ @9 䄀$vy Жr\#Y"@ @| P@]e]텦H/3N~eݗۓO~T @ @`;>jWˑۙr~"dj_s9-'= @ Ї@/DͱyҞXfv׎,OF^fk,  @ @/OZuJrv[rY7n[e9s;w|v,$ @ P`DOe;_G,lݗ I١Sj;xz8I @ @`'}Wa27H23ywGF1$ @T Q{D>9G':?\G@vǒjǿ.\u. Ŕ @ d4Z)R2-=ea$'E~_F @ @|EK#'СK} `O @b u;Y @B W>kۇLuv]_j7nU+pYrzV% @ 0DA'ͱzɀ?E?0P>Nj&@ @e d_5:\˗3M2>inA @v#}yIr򜹧$jQ3i2W\y_lks_,$ @ 0*|ω\_|:@<.7h;N>⃋(|  @ @vϚ}ףoIcsMsAޣ] ۙs׍Dud @UQE\:_9> pg=T;Q;yc:#@ @1 d5~mβ=Ly|niZZu}2zK @ 0rf_vZ?j s\Sp^v]l'5G~E @ @>S"!r}NXSg=4pϻu\ @f%}f?m}޺羹yR{Vv]~ @ 0RN}ع=-mulg.6 Rs9 9 "K @ @`U>ȟku=vu;3KٞgGuYH @ Jٗ}pڿmYܮk̗OڮlY"K @ @`Oq۾o-i< ma֋X @ @>mm׳*i;tpuVsvV4ˑ۹sD @ @* d6m_gvה4nx}ZRu_=i" @ @`Eo;˪ \4+0YLmz4@pXкV]{ϴv.F @'}>oY\op=Y&VZxgY<_u,  @ @`;֫>r{<9;ڞUtZBc"xD @A gnOJO:f @Xf_wRݗU۹)gfTu}2_=gZ3#@ @ȾnrR߸Ҷ]SSʛ*M*LW+2" @X'<udžw=v@ϩ;n> @ @ lh}#йo&iO 6,T=˭rNpö  @ @ d_h}筪[ꜩT/G'97$@ @k"}_Udžw=@޴VW 5<' B @ n_ʾo/}㶮v=g d!jw @ @`2p~qOe:{vK.}*  @ @ 싺d߸'g0}u9<~].\u]n'@ @+.pbV^e$*P Lrޞ[sB @&:q]vuU-@.S-d]NڗǎyP"@ @k(}q۹.7fjArXwmݖ#>* @ @Q d7}a@t}x粮 vn< @ @l@V'*}xݿ,ÂdT r/>v=_?7u@{IiuK Z'@ @k(}./S=ߺ^ Sm=0TM @&0| v[ڧnz}ZIh v|>H @+"0 ƹ_fTZzn˛ԃ @ @`MnjuVw]l@u]yu{,  @ @ ʾqX]ϯ۹Qi6on7-Z5 @ /޹ަv=/iċ4;kaj!2Ot,]U @ _]eMu}ұzή Bjp_n j  @ @`@7κN7vߎg,D]evWRE"@ @u @ַzl}NvyZzl@$@ @u>:׾t=ky-wh/8u-p^# Z @ @`},c/x]6Mߞ3u}ﶠyv{ZS  @X3a+U'_u}'ܠ=.0u]N @ @k zVejn-mCI`M'l/i׵ @~>sǏ=@ޤ-H]esr["@ @ l]ٓ^m!PzNk @@Y\s&}}{ luX]˶ǭ @ @u2ڮձṇm40F}u;z޸ c @@eV73Mڷqsv=r}zZŧko+N @Q`R?x'j2:n.6yݮK @(0okuf8ZAsgVzAK @ 0biI}WcI۹l+ @ @`ھqgn^m_{|&x 3yo['@ @(0\v <.hz~e]꺎 @ @uhq=m}W&{ niypu @ N>pݮuv={ Lv ~ @ j omurnϷN @]`/}亜Kw8ZO7( @/=< @ضO_  Г@@O+ 0޶Q2k+p7\j8Brcs3 p@#'pW2$s@ ,I@`InK'Z[]  @`'#@ `'j%@`9*;FJ\@ O`A v= GzǿWWأ@}-qܷ߉s  @m p8-v- k:$@ Ԏcr?bI._@=]@ P{Ȏ= (؆Pr G8!v;GA% 0/Y%Ї@f"pf_&.Bv%9veCzՙjo9Q 9G@]ICydy&@ |p)su%& n->f vX)O@ "+PI`oFu! @`>5_=1G@|]  q@IDATZ)/9Ԏ_;:svI $ 9G@m H@`D(-?wu-~ @`v7ck(9 {.M%P<ՀqXb݅(E(Xn5GRM ,C@`I`x_nGF,ߊ9FHF`3t)cȎŵWF󳹌E@ (@X5iH yǿOrsJ9_ssvaxGKօ4@B݄Ff/?{ӣ]S_,yr٥<#G ]Zʾ99!?gw·s@kG$06؅Gpɑ*G.)<#SPl_xiK KyU3w/ ' E@`,-v!7X[cr?]#9#P9ʑ)'|:7~s\{|=75#vz~̚;Fr鴃#P9% @r|e){+y)_y "0wb7 0W8 s;WˑTqʑ'%).to|+=5jOI)D @#)"AʑQʑ7}ztػ1]ֳ>Vʥ{G=2*1G@Q&04"&7;gT4n$划D'pIti8sWU+q dzۓ@O+#v;so!ʑų8ws7 @"''\T{vξoS] ͇G@>Ӯ#B92#D9R#F@~S}ƫ]y]ծ7r>s lW@`R#0G6#s1#B92#D!?8=A/0׆@c|"@ `.N`[brd/;:1nzf/G^刐D} 3[#|'Jo?8m lʉf'vNR::9y]|Du|Ts.-^4sY ̅E l[@`TN$wn 9#:w>Xcc'Gz$ 0MGc^KJcbӨfo0S!(9(9n h;> -GhHsc&Gn$ 0+Bc^)Oʮ3I@ `}f' 0;KW"Pt1#29{sxBsqD^{Rr<346) g极nN.L>Y-$w2r\6GX^w=gcLaە  @`3?kh?\| j< @t%rDY'{9" @ \@/~_=5 Wsk<07[C@vV ($FPr$%GT#+9" @ \O08`)sxu~ېJp* ` >^ʕrK3 ̅EH@`SU.wã]!G>^HcD$GF$ ЋY+/xY+R4} |@^hj f)y߈q7/#9#(&F*pIti87N9~#+jRH ;g;owug:LlGN#9! @WēqϏ{OC `..+hw5;+Hӣß#9‘# 0Y ]G+rod=#uYJ|ǀ/-/D)~쏬qַ8\l.9r_.3Nj,s=s~H]zcszavR`##xht?ז83F*sY)'>=֧ԤnbGoVnTqW4stơ0@vzR4٨uRt~)=+ @@q§|gG=F?cLՀ_:sŷÜ5XFURڎ" V?#R# @ \h̯r Q6/0SXhBAf!? ׸p> Зx"`.4ѻ,3GRvZ9# 'C<D,W g\^ʝ-yW.EI1_)~ϴj 5?#`.6_Oy|uy|.miv=_9fgJQ ;yGs$ GN'{9R  @)pYv|Ͼx2,g3t9 ץw/vCNdF!#9"p Jv @2{a pǃ<.{UYeJ `Y]J9o!:cHF?#ϊKc$@"@o}UssKy)E@@/+Y@`τ.0 G4~F3g_"@T7}:D0 z'K*͞x8:{ ؓ|xxjgD?#HD&ĠEAO N~[ yk͈}F3K @xm? E ߖ[88C#`p5#/H}>柑K @\gD87l@{5`6-m19i_MG1:񔏔?^O|\ę@:zϋ9NL."F&3"~烥|˅dd]"@E*c>K|s8X@`Ơ.G 2dl̷a @4~zv|#ҾӖ^؍n|X?#"~ZD"e7 @` >Q+WM>^v. s3 p@F3RgE:# @_&R~~)obI6K /ڈPg:# @l\Wb]"@`wc>E@ *r"& @ \'_R\wAxVy R^tR.U{y)UKo @ >:>A)DD x`un%QB]Q32O @`ODg(cGF@GPؖ]_~~fpެnWMJ*;9cFϚ @Z <8^+|U<ޟ>+?W-/y~c5gk_Z1x-9/5SBA]zInYZCcbO%bxx5EW|c pۯZVރɹ_?} x29R[@R | 5^1Wk>eqU1S-.]Qi9пEzijKhxE)ϋo5g%]Z G%s^_48\ͷƓ/;/챲#@#~Gt &oZz^cƈb_"0ovk.pQgW]sngܼJymKyDH @/rˍɂ_zk=Pgw?RLX]dSf+/ψtf~<=^x 1ylyc=3߈<(˷$ @`eo9IZ{b|==x [iG3^[HK}L?btSJ*FF"@VK '9)?BK=11rۤ #/@c;9>~2<1F ~r)9n'4&nN_ L_w΁x<Vds?vE&K?~b|/ 8h;211poJF+GhFOS=5.fO-|Vu &I3 fpCXs;kx:K+aޥ'b@WbZ" V0OG5uuu|ZfvÈ_ 5CsߌyΈ o 7$@%/ypMO4Rt~)'cMmw߻ ]aD#?f {b  |q=U1S]TFQX-/vRR^߰V'-Wc,&>'ߓrg* 0SNg"b҈-"Y__)xu쓖+pBx=KJ*FqwXWqrωN_xLDI\ xhZT}xs|'k;ƻO(}~)\sG>+& @: ArRƓqx<?=fCoh<$ Pѹ|ťQ$:h[?lەMJp 0 Cp:qU+`)_^>"XR \?Q_㩀{~vubd|^g~3~)/{n>F'-nx>E_'.J8O,ڝF&_Orss?/xktR[r)H@(E! @`k1W/y=~wDŽ~Igń:w1 x`L,KbRb?8M+px*J朘ED䎟8$ 0M{T<ϯ'ڤq|1v^?/˘J"@ i ~䒍ymkqv0e<x&PZr=U DasR41P.G(X1*OFqK֘F@~ÓoRʻ*572Q t x-" sښ4CmP q4RJ+j@>i?#9a`>KwW;'^ xQm$ 0KG~'fI;k3(f9$ x`#xW]1ýx*>Vʥf?g7038Kyc<J\f7C+Z,uӮ9q n)=/& O(ɨ,|aKbf؎@VOh}} vz'b&&⩿s~_'֣b sJ|n~hPbګc4{S/w=/?1 8JB4}Z<1_I|kIxtS>AE9wцy;GpZ֎9%_/^-@K{W|Dq' y|che @:WvsR{eKeꋥ'7&;I"@`⡋v7\Q1Oq :B?_%xցR<2gWB"~zƕ_wF֥?TOj9bX~eD3?F+kRMe[|SIbDoGhq$X@>5DJP"J h%B*5*B!%'-6 Ђ 6 !~m~W:;kkҸxsKy^{~䞑 "`{ |`Ocslo=ɧ7MJv9ݳmsrQN7~玤үȝC|b|\p7:'\}@ {/n>-c=/| 3rA @{$/xlʷK#Xnc?QAl㋃~ַ{o @xb|﷎/}ب }o.WN >'$P>V3_3>.ҥ @;.?;~n t6xwBgF  @ |l|G~/^p[ po o|n1 @#Eo_E *`r#@L|v/y|K۽|B\MMw_8~>QW!@C t8 }O/ %}||Ol7>G^1~)ש\< Ӌſ9~zN?xGGO}_ ɿ7Gp$X%@)w_[?|/>ExߣScGg7NQ xT^@+7t| ( @`C7@;;FBG!; @i?3q?csvgے|܄n߄$@\rrJhwOz /O( @ c|_[/Ɵ{CBp @ w'vnq w}?c[!@Sy G/?Rp|O_O~2 @F>16_:tO'nYxq ~c2>F1Q(O੸v_9~}M=A 8'8 /REJEJ6 _X-E#>:|DC s07!PNQ˪_OI7q5^" 1Uܴ$@N zn^eKeK__d{cQcg?<ύ/ jTDm&@6-<wo {n]-\U+=ޟ_Hiv ~Iowǯ ( @P7/}o_@ #m SwoFk>c{m @όc?D!@]OT~4Osc4~*/񩱗JVp6#``3ڍ s>珍_ZMAM {l1_77浾7f7M`63 ~'>Ovq|Oot ׍D޺ͱN9f = |@$@`{ӹ?c{{nGln lY?s;ow}O+ p{>4~Wa~sU}kpmND]xrǷ@xW}{tBG}|k}7/}CޗBlx# @`AP_h` X2Dxbׯyn# <(;#@^5QU=_?'9e @ |bl}3>>Q'nSs܈c:>Vӥo+}svy{ 8* |po/zcW/z/: @1_-E#۹ ~>TD_/}i/{n3k{lIc?>[qJkp͠NG6^kߵ7W&pE?f?? ={# ÏlQ@ŧ 88 @ @pBå @ @c 8 @ @pBå @ @c 8 @ @pBå @ @c 8 @ @pBå @ @c 8 @ @pBå @ @c 8 @ @pBå @ @c 8 @ @pBå @ @c 8 @ @pBå @ @c 8 @ @pBå @ @c 8 @ @pBå @ @c 8 @ @pBå @ @c 8 @ @pBå @ @c 8 @ @pBå @ @c 8 @ @pBå @ @c 8 @ @pBå @ @c 8 @ @pBå @ @c 8 @ @pBå @ @c 8 @ @pBå @ @c 8 @ @pBå @ @c |ҁ'us̓~J?;B @_7Q?z?V׏W]Zv^*qW @ @;.`?`G @J @؀ _7 @70G @'!``<ģp @ @x7'<_g&@ @'!p)l$ @ @3 @ @71<  @Is_8ғuZ @ |``h @ @(p)|wɺ' @ n< ?n6 @ @NT[ooڽ>6"# @ @kr߹yR<s7(ġj @I׽p݊ @"p՜95]0XB @nOf:w"r  @Ax+p j: @N] 9or޵Qmo>T  @!u's[sGpȍ՚ǎzNN @c%͋zu8.8 ;9 @xu^҇۵~u?X @Bl$׭[?kvf /_|]k3W1>( @ @ TNĨr]#>KC7.BY?~54_c>Х  @ @6 TN|;i\28ϯZe^d~+s5n :" @6Ɂ'^~nkkG[⡯c @Ie+ܺ5Veil{]MKNbJڙY  @ @["Pl~u_[ۿ@.tE\?R @ @-u}<4q1}nԋeK_<4W/O @NTrߦdƖڥ5nY˺y]f2  @ @rٞ&Mo!kkfN/ڽ_#k27>@N/"\hg}YWc]_w @ @ܵrؔvkJAױ/8Yjױ폏+j@!@ @',qm.u_&eil^ C^vu!vjN!@ @&PkrdށM{-k8?h4.*/WӞchtD @ pbV2|ozuUglŁ@Nυ~|R~& @ @*gM>[J>ۙO^U6`e>1/_'y2'  @ @TZ9Uroƪs?}*Nx ĚObcڥ5?U  @8!U+gl;9n-ssW.ױP//.e?'pN. @ @rY[^*Kcg3gͺ>vumsѹĚ_c?8ʼH @nXrU/g>V*5Veil!{ \L||b}ȚuB @nPrQ^R]SkS*س/ sEvƲ.5XsT'Q @ @ TnZ9jY{{_nuuKUx{z?{U7M3~.mq @ @Q TN\6Ӯ=^@.<si+. @ @0I+7ECrz~+>t ^_>6C?>jE @^/B @<@嘕kV:砗a/:.sX<aa6N/$튗I1ϧޱta @ @%*3f=7M{iҮ˫u)+ȅ2 L?k*Vbڽ>k>27B @.-P9g喕c&L|ǬI\W;$gҚt Eqxuy[+/- @ p&P9e=MYqCn.Kc pEd!틵>؟cw @ p%_2j˞sM3v\_j5rcw0|/p^~Oc1emhZc  @8DrVnjhYcK{[s+֩v5>~Q6&vLĬ{ @ @`?4jOc>严D?ee4?lYH;2mױ6H|{  @'Pc'kuRx{*ױ0_@~iŠf>8:n^[-`B @*gq'K{9uMv_k xnh-vY\>_>WsT @, TXO^o9iel-RY_Z{u|@^~J~wy.kz|icz;5F* @ @ ?3U{|2 f}U\c?t9@]XOOs՞sQxϮB @<G$sv?'^Køڕ(_wY&:^>6G}rT @-PG\q-sC9WCXR^kOԅ/]hOs\O15>2z͏qZ @N\~z}֯Kg/QqR>w7ꢒ{'?$ G  @ p'~g&9:{2?{?sv^b1t)P*}l6꒓|cծc+@_Z]u{gքB @^;o$'s{Nc|zyeQ˱6+Z;d}mu|ht~}?3քB @VwǕϣp'!>g9GOk,8ꯕ}sk\8(6"OR49f59S Qk  @ @V xwO'1O2ݓױT$sK7Үxr Jκ>jzK8[F P  @n@%ouNDdi^JUjZ7vAj.&gMsތ'^4u9'Ԩ~d @@}G/{B??O)+{.> vik.vsڹ]QoD/  @NX>QWb;IR\Jgs-^^7q\T{ڣGP7QuJޯv2Һ>kJ~/՟  @NP_%ФNxډ1dq%\ţGP7QIu9% O̱'f<{{s9O_wv6G~usggR$@ @?WvOv~?'K:6T?I!q,ZZ@LOoU!@ @x˸¿d?q)IcI{(~j'xcƫ$GPﷸoM\syx^#}lL&g" @nL5p휄Wbd|s_X>ukU}_sKem|inb.6IuO36x9ZWe>l쿙Q폟M/ @}ͥ-gډ9%x{}u;I~kKZy*f<1cW|˨O'FC* @ p|Jlԟ5v9M:>~zucRkSz;cG7P7;78's?$v)._'%4 F}֨  @O}ۨړx'Vݓ{⾔g~\ΗKj:jW+zn4Rsigf2XbU~*ߙQ;/  @ qο7j}O|-̉}_[;os=O;q +_l$7Ǫk|c9Wcz?ymΗs%fGF/|U!@ @ǩ~d$Ib%_ϥ{PűruI{z~og>UƫeނY[7ɱ8jF=OU!@ @ T@%= yo)|sv %c5Om`&ļsڥ~U\=QW>& @㈿7jJ&N"3V1}I6~&$xjͼr|_>6j/FU @ @`]Z߱{vJ>1ĚR~ըiQ @{~p_cA* vOӮ<{~_m}οq])GOmn'M?&u}l^7ʄH @ TBQΨs]JXc=Ob~bWk36>^)P=N;q km>}v߷?ԬKk[G}ݨ3g @ @`Ko7[?Q{"]Rj+\%'~žq9Z5q9h9 B sډKHk^4_fn/~lz;k,/kn_8 @@G}٨;R]IwOXNk}QsC81=H9 H\1펔>W'}MEuڥ{,u訟7)=q9  @Z# ?=ꏎQ+ғl]qXk}f{[N&Zٓ{vjG\˚WL5Y[v_3ب$u߹ƴB @\գַI|ծ?xQ?c52V1c}sK6vju=M;q "SڬK~yv_WFQ?wԵcJ!@ @I T[yZTI"=ǞX{nIĿs?>XcKqnWF)nHO|N\7ĵs̯׭{;w^Wo?2u^? @@5lmz<{bv+IO? {_K3s}:.6lu&vĥ[k]s1:!_ԗbԷbGe5 @ prWFQ4'NbK69o^\ZRUz'S((<־s?r|s}Ț>ǪfX:E{~5۸< @ ԗO~y|X%ٽ~ONRI9g^+_[sCROz"{vjǝjyncG`FPCSx  @@%?7j%o>_%IrogJOҽ'uixQҟ9~5XKx7 'i'hM+|-=.s/]zZyר ٣zX @ @R$jԟQ+7X%s;cs2^z=~j\b]gsKqL?pկRkOܶ L5}si?^Z4v׮y2jz@}_էB @O_5ꏍVRq>=V{&sMrܮΟiϯ~]{ƫl{&ni+UC{v R=׬~XtTs׵|_:5̀ @ p)hͣV\eNz{jtϱ^zKk2c{k~{LbJ?R m)ZvZw8'8Xsjel~߯onp~iO6Ĩ:B @%Dq67ZSv_s5 uݓvOk> }ogl-iX^8ު]Rz;c'+M_N\+᮱$|-q_K>kz2~Ӟ:K{)fQ x)* @l[+WD6Ǫ=J3t'Kr_si6ޏϚk]c{u'{vK팝d~i/5 uI{\H_Ҟ<~UL~s{r~i/>VS Ѯ{Q @m$)=M{)j9^Jg.\sk~UI&O?P޶2_sKz]J{v%^5Oq}Mr}{3G}FT @c'F}~~ʟfǹ]:'sԟ$6b͵zgL'5W%~O2V2y|8_uN%KI|[J:z9ss瘱ŚRRPQ B @D~k;G}v%%_}k5 uͧ]Z}qn_ԟ3.U[U6]|8_9&^s_>ԯ9wM~:[jX:JYu9j6>~! @k~oGL_cIdG2''+kg~pR\KƓ|9^ƗXroMUSߊxqnWj%ݽd=i9FOU?~i/q}|RisFQ?}?|~ԮuuB @`ITַWF?0~gZzIoYjgj/3iW$3!~]=$w7KbXZ{Hǹ]I{;IRLº/ޮטk[%ֳ|s~I[+֎1N @`kk{?v{]J3VZky]ﯽf]w{;cc|>]R ](s~bcoy~XҞcxk1k_=/r;/z  @Ux/3ܮZBz\%skc}.;/GutiX*ṷ.weœxуZZwľکΥ~c}|e2q2[K @. uX/3Vu)XǗIuk%}vk[署2dzѧӿ.mae5Kseo,5Yvd}Y8~kΑ-9  @lM#/z?튇J&d2X컖qjZ<}j>[@=9O}hyS+v9Ǽf[:_q[:~>G_zL;Xc7  @lA/z?CcߗX/%Y$\^Vvi-lou@?̯Ŭ_7|8uL{;s},k2Vk,gMsye42׏f|Y @nҿu3~b/X利XkҞc%},!1Ixb~>9GO+cǹ=wR*u̝*'bՓbױmFykM՚ks%c6j=~Ե_1ĺ:oŹ\<7ק/u{k&s}^:n^O @.\[jgl)jc+X_5O_kױ}.Zk>c|櫬ų٧ӿnéړ/zl\u|k_c׺ޟկuX״xb]cuRcs;z^rv?~mq @7-pk^:~vz_|"s[5q)c]~|W?yb[@=z=y++ƪsTvjJZ7oXQԥUkXg<95םSsYSJi}Ur|kD!@ p[Һy\{-Xogn)XOK c2vӞ:KbZs}7e利\Үc{7T\*W/md.K}k.Z5s},}U|sYTuK#@ pJoCykϧQ!kҮ8Y25ZO\RK^~-lԃO{agJrZj_Tk\10~#cvb3~`>:6%X_̯ws8 @eU5~ډuNyi|uZ%>X*9ܾ79g,1 @]`,v*k/W~>vs{_cQr3cJ{)XJ zy=ᬱgZ Y|uJ+Z{~v>=~u|:>^*u\Ĺ_q @yN,jRXձ|R;c=X+ @ P\O{)]jYRcNc{Rƪd3~o5is}N^ pJYOǬ[&t~̀]:. }%9ӮKULqǧ/jWיؼF @]e>WCk$}m=ks>v'k_ןvs{_c([\oVJ}o`r:&ZKzs'x3$gn_s>kXΛ56N @m߯ybO\KcuK3̱x1UOsL[7@OLk,A2Ǫ]o:jIvԮ똚K;~3Xs}>C8ܮ~zccX @#P?VY:w[jgl)jZ+kܞu[|!_םvs{_c+i/>Vf v|ל3/ROT;wQ9dE0O @Q TzQYZ>$֚.bOuyv~~KUJ xmPotRci?xaz#9R\:&vo-\G֤K_wWɺ>W픜+u @NY`_4\qN{?ˬu/&v1}[ab:'ϱz;.~>V2vO{)ԯk* @n!I缦qnW?N\Jb:Ks_^}U$ @OK{)XO)&Y\利Xk^}^EhJss2kc  @[2 luIDATv}|$YKͱ7tͱSK)jʂjeahvve<~vu^'~=vܯ~6 @ c'}^ؾ=kzu~Vnj~Ԛޮu}o%>Xsiϱ'|u}Ue~_*9ܾ7׵aM @R`_Rzn4}U;5ǧ?ǵ|ޮ]_Zӯc3/jԹ $[-Lfk85Z4~X?>7_^2/snk  @\Vಉ>R>~uO?'-_5kbU2$ @.v*~֭9y-s{OTJ/5F @%x}H5}]s,(Iq=3i]sU\%$\ZXǖ5#!PZ}nkJ޾rc @ Cҥ5}lRge~ZAK?Ҿc.XfNSV;h}ܮ~J-} @]H;[_jgl_>Xv|y,\W=2&( :eKXuڴ+ksYsH\;f}Mu}sk'@ py>$5^_4XK5VRƪcF.dtK?^"튽>5kck\bKKk/ @KlgvƖbK7Wמ5},~4-cWl]ÖlO{)j?dM|}c5WlxEY' @8ey~ˣ}U%sdǹ_q!$ZwKX}Hk繹_RckKX{6rߌglg⾹N @mHRtZcoTksse~_sծ9wik?!.yvv=:U>voA[Қ>}M?GFȴ6PIENDB`htmldoc-1.9.7/desktop/htmldoc.ico000066400000000000000000011163231354715574200170050ustar00rootroot00000000000000(6h^ h .   $$f($$X v,$$ 6@@h VL@@(V@@ (Blh((Lv (# +>Lt +( fD3"( f3f3̙f3ff̙fff3ff33,3f3/333,,f(3("f"3""f3̙̀f̀3fffff3ff3̀3̀3f3333 fw3̷̷ef3̙̙̙f̙3̙̙T̙˙f'3fff{ff3fef33(3f3333{{f3fffff3fff{ffff3f)ff̙ffff3fffffffffff3ffff3f3f3ff3f33f3ffffff3ff3 33f333333 3f333 33̙33 f3333f3 f3f3ff33f3f3333333f33333333I33f3G33h3f3f3̙f3fffff3ff333f3333̙f3wUD"wUD"ffffwUfD"f333wwwUUU3DDD"""33߳ޏݏ۳Gkߏݏk(  b*0I F e \ l) 0$H \ ~) h  < D \ () k$ W g(( @fD3"( @f3f3̙f3ff̙fff3ff33,3f3/333,,f(3("f"3""f3̙̀f̀3fffff3ff3̀3̀3f3333 fw3̷̷ef3̙̙̙f̙3̙̙T̙˙f'3fff{ff3fef33(3f3333{{f3fffff3fff{ffff3f)ff̙ffff3fffffffffff3ffff3f3f3ff3f33f3ffffff3ff3 33f333333 3f333 33̙33 f3333f3 f3f3ff33f3f3333333f33333333I33f3G33h3f3f3̙f3fffff3ff333f3333̙f3wUD"wUD"ffffwUfD"f333wwwUUU3DDD"""33####G###k###kG#G########k##k###k#k##( @ OjqrrrrrrrrrrrrrrrrrrrrqjO{h~  ^ [ 5 L ^ [ b$   P h ^ [  <  n { s [+  X  V [3+ 4 [ Y Y  [0  ! 3 d ^ [  ! 3 Q ^ [ h!  V R GGFF($HfD3"񙙙<8>($Hf3f3̙f3ff̙fff3ff33,3f3/333,,f(3("f"3""f3̙̀f̀3fffff3ff3̀3̀3f3333 fw3̷̷ef3̙̙̙f̙3̙̙T̙˙f'3fff{ff3fef33(3f3333{{f3fffff3fff{ffff3f)ff̙ffff3fffffffffff3ffff3f3f3ff3f33f3ffffff3ff3 33f333333 3f333 33̙33 f3333f3 f3f3ff33f3f3333333f33333333I33f3G33h3f3f3̙f3fffff3ff333f3333̙f3wUD"wUD"ffffwUfD"f333wwwUUU3DDD"""33##G##G##G#؏###Gk#G##kkk#G#k#G#######Gk###G׏k###G#׏ߏ##G##G<8>($H >aorrrrrrrrrrrrrrrrrrrrrrrroa>Z`DJ  S : B S : H !  S :  d 8 y S :4    L  S    j   J S m Z    \  S L  m    S :  m   _ S :  m  S :     <8>(@fD3"񙙑񙙑񙙑?(@f3f3̙f3ff̙fff3ff33,3f3/333,,f(3("f"3""f3̙̀f̀3fffff3ff3̀3̀3f3333 fw3̷̷ef3̙̙̙f̙3̙̙T̙˙f'3fff{ff3fef33(3f3333{{f3fffff3fff{ffff3f)ff̙ffff3fffffffffff3ffff3f3f3ff3f33f3ffffff3ff3 33f333333 3f333 33̙33 f3333f3 f3f3ff33f3f3333333f33333333I33f3G33h3f3f3̙f3fffff3ff333f3333̙f3wUD"wUD"ffffwUfD"f333wwwUUU3DDD"""33#####G#####G#####G######G#k########G#######k#####G####؏k####؏#####G##########޳##GG####ڳ################Gk###k###G#############G######؏###GGGGGGG###G###k########Gk####k########G####k########G###k######G#k#####G#####GGGGGG?(@  -@MUXYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYXUM@-  #?XhqvxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxvqhX?"  #EccE# ?fh? -[]- ??j##%%&&&&&&&&&&&&&&&&&&&&&&&&&&&&& && &&) "&&B%  X,&&  ^%  X F&& } ' b&&/  k #  && F  A ? : : : : : :  W+&& }.&&  T  n o&&7 f  !&&7 y %  !&&6   !&&6%  X !&&6%  X  &&6 * && &&  &&&&&&&&&&&&&&&&&&&&&%%## RR LL?(fD3"񙙙񙙙񙙙񙙙񙙙񙙙񙙙񙙙񙙙񙙙񙙙񙙙񙙙񙙙񙙙????(f3f3̙f3ff̙fff3ff33,3f3/333,,f(3("f"3""f3̙̀f̀3fffff3ff3̀3̀3f3333 fw3̷̷ef3̙̙̙f̙3̙̙T̙˙f'3fff{ff3fef33(3f3333{{f3fffff3fff{ffff3f)ff̙ffff3fffffffffff3ffff3f3f3ff3f33f3ffffff3ff3 33f333333 3f333 33̙33 f3333f3 f3f3ff33f3f3333333f33333333I33f3G33h3f3f3̙f3fffff3ff333f3333̙f3wUD"wUD"ffffwUfD"f333wwwUUU3DDD"""33#################################################################k############################G#G#################G####k###################G######k######################G########؏####################################################################ڳ#################################G#################################؏G##########G################################k#############G##########G########؏############################k#########G##################################k#######G#######؏#########################################################################################k############################G#################ڳ############################################################G##############################؏#############k##################׳#############k##############################G##########################G######################G##################G##############G####################################################kkkkkkkkkkkkk????(  !'*-........................................................................................-*'! ".8AGLOPQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQPOLGA8." "1@MW_ehkllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllkhe_WM@1"  +=O]hotwyzz{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{zzywtoh]O=+ 1FYhq~~qhYF1 3J_nn_J3  1JassaJ1 +F__F+"=YY="1OzzO1"@aa@".MM. 8kk8  !@@! 'OO'**,,........................................................... l  .. l  .. l  .. l  .. l  ..( L l  ] .. A P l   |..  ] P l  /.. | P l  I... P l   e..HD l   .. d } l   E 4..  O  l     O ..4( l    R m..  O ] l  *#.. `3 l                _ .. j l 5  P..J l   P.. m l 2 P.. :  l B ..> % l   T ..>4 l  e ..>D l   y ..= U  l   ..= g l  - ..=5 l    ..= P l   .. < P l   .. < P l   .. < P l   .. < P l   ..  l  .. l  .. l  .. l  ..G  z n...............................................,,**'' !!   ee)) "",,!! VV ????PNG  IHDR\rfiCCPkCGColorSpaceGenericRGB8U]hU>sg#$Sl4t? % V46nI6"dΘ83OEP|1Ŀ (>/ % (>P苦;3ie|{g蹪X-2s=+WQ+]L6O w[C{_F qb Uvz?Zb1@/zcs>~if,ӈUSjF 1_Mjbuݠpamhmçϙ>a\+5%QKFkm}ۖ?ޚD\!~6,-7SثŜvķ5Z;[rmS5{yDyH}r9|-ăFAJjI.[/]mK 7KRDrYQO-Q||6 (0 MXd(@h2_f<:”_δ*d>e\c?~,7?& ك^2Iq2"y@g|U\ wIDATx{U<$JX+yZ.U"(bFE]ZTcZK#Ѕ,XLR`x l%2{g}wO;}s~uNID@D@D@D@D@D@D@D@D@D@D@D@D@D@D ]9؆@,E,Fx5bTIB%0 y2c$׈G@Z-8 5>rD7BI:(*_ ښisP!ZD b3G|jB4@@}a v!A% qb PdC 1gl}JEʵ.Pwg#~;Yz&,K݄xM+:D@ g"AXOj|L̤WHebPȎ>Aܗjgj&|@@ w#@L :BIDW,DAh< _AIH`w5LcL6@eE@R`Oc?M9Ix" Pd9$#ЎCF lC$2$Go? (@P$I6}`oJ" !@MRfM@3ǎ/o@(؜"^Bv:S9e_l6Qjnbzi}|%)>3kDu{z f$~@PFU]1>Vz\WvBID Uj֮ Z`a?%VY3sŖ2f2t@8Y; Z \F) E(CXl**Xw Њ!"g,kmeopi@ PԮ LKY-1#,j4OD ]jZ?fQID 8ԮA|T@g kD@#@R j=:b%P~p!4c.BID <ԮZEW¼@ID <v#{&zyLf@8jU(7_\V4S\/P;0R>/!]-ݪB~Ͻ+0Oa?x>+fuc4ܙOΙ{ Mʘ1TFWuB0?hQw:xIi];yxHI.ao+A|#)yL3BY ]_92⾏u6;N{@ޟwbOFp~1+Ylqi?ߊ#1wPnʅHgoNso#>cx!h3pFǸNc?8,ijQƖ2#꧱ηfvg/nƍDft#Qjԍ@̀{+~Gu\atZf)G`.E} #h.,_ {{o$o;F{ZAqxwq4l aX:7G6=#ϯ ^[_gh7@C/Ex~D[RX]=l.xfN}ՕO0;^@] |X^#Kt..]ߎy|: 񕐦bUp?U%WR3|N+n o8QQ\l~| ˮX7w vͅ1n g08|j>'kb*T׽ٞ$X n1z[s~yNͷ,^x㸣/4Va`+qG&k}),C^=㶎㹒7W~Ft^אZ6)`ϧxḣ|G/y?67Bp X 4-'7ڔ򺯯D@ :/q_xz/e*ZfVu=)bMxcRi܉]^$2{N||wH,~ a_ؗpu0_Ӄ_f$ߦa7ϭ3JNhKOC}ݷ}W ᆑp 3y;}56+?ڳ6|G$(]񧛰}3@3p ^Yp $`t.%nŋF뽫q)Sqp@.av䱫 ]mihzh=0vy[.WQ#-G7X*N=H|5إx~d^wxpY>!췷)_t P]ǻށ'pL6=1n8NzU\G83p1C#h>{3yYʬPA6 0n8R2qD,?yNvfs WW&_֭X0|*8=ۍрh | CJU#Ma)~ D R=_9@0Gp\=yۧR88;oG kў+UT2ß ;x9.i/| Jt31TO@PRy\Z8X5Ne]n~ N/4/ǒ&Kan7SkkC} vڻD7|,<+'J'(rp܅_KwZe <cM>|1?~^`+wc>t8a#I> rtK#JɗkMάn u^(-(G E n2WduhM@wv"P .- n_Nţ"7@ډ@]48?^wPD ?@+D֠$! HBKyE 22T$dIh)DF@Y:" -"kPUG$"@d @2$W"# AUHB@@dd5#IR^ UuD @Z+D֠$! HBKyE 22T$dIh)DF@Y:" -"kPUG$"@d @2$W"# AUHB@@dd5#IR^ UuD @Z+D֠$! HBKyE 22T$dIh)DF@Y:" -"kPUG$"@d @2$W"# AUHB@@dd5#IR^ UuD @Z+D֠$! HBKyE 2@1::")jxSh"mvGEN!P ` ^ZDFڥkjP^ٚ@D m\]52yTD (['ִ\ p4CD ԮmeȂ'(B׮@Ŧޟr asEI38< |~Q$"jk50W ZF+h[[*"Ԭצ)@~fZ&*M3nF(fl"5kM'eo+Y>:l֦UM7Sf6{;J" %@R[x |dx_̤$"[(J͚~LSX+wL<6Q+pSʆ[J" #@mRԪ6Ԩ`Z<ϏM[m$i:5 )UR~AQ}"5YSS1g EG!J" C¾ ?.5MPPfϘy#D@f?AP>&@E/̔P{/M%oCHo`ⷣ?Oqze=S^4 u%x_Q.~G@T,M3{7B=#Oj^wjz\fMi_pLD@2$@}݅#|]rSQ`*#> PՌ "A!D@!@q߈~8џvOӨz=.-gN- }!^<7 xpm$~.M#xj`r<3r܎BID ^j>Nk_k{Z3s `ݕ:-%h@bow.0s9nṿQ[k)_q7x} D@]7!x?j&~~=M"DEmjMs} ȻE@N?˘ 0^8A@v%Ep܌&G#O?P&s~7[pmMLF@؆-fBDFtR]IrE:љGrxAQS7様} SRǏ6SEoƍc)f 0qZ@Q ioM3&|_77s&~aR*/ۗrZ^ O4<f&zbK4S_/v)r3=YecH%~K`&*VBX3fL7[&@ J0Ni\&|غ3J/p>7X/QOFyb@6et©#?MbM<3n |Lfb6rUίU(?6ة@df_IHDm3pj0S 7Mu߃ɓ 7y\38 NPL'@M ;0`yb@4nS ؂F`B/2N- ƓTHm3rj)EmGtNel6♥V ˩/j~[^)cg% S ێ_Ou5TIENDB`(@fD3"񙙙񙙙񙙙񙙙񙙙񙙙񙙙񙙙񙙟񙙙񙙙񙙙񙙙񙙙񙙙񙙙񙙙񙙙񙙙񙙙񙙙񙙙񙙙񙙙񙙙񙙙񙙙񙙙񙙙񙙙񙙙񙙙񙙙񙙙񙙙񙙙񙙙񙙙񙙙񙙙񙙙񙙙񙙙񙙙񙙙񙙙񙙙񙙙񙙙񙙙񙙙񙙙񙙙񙙙񙙙񙙙񙙙񙙙񙙙񙙙񙙙񙙙񙙙񙙙񙙟񙙙񙙙񙙙񙙙񙙙񙙙񙙙񙙙????????(@f3f3̙f3ff̙fff3ff33,3f3/333,,f(3("f"3""f3̙̀f̀3fffff3ff3̀3̀3f3333 fw3̷̷ef3̙̙̙f̙3̙̙T̙˙f'3fff{ff3fef33(3f3333{{f3fffff3fff{ffff3f)ff̙ffff3fffffffffff3ffff3f3f3ff3f33f3ffffff3ff3 33f333333 3f333 33̙33 f3333f3 f3f3ff33f3f3333333f33333333I33f3G33h3f3f3̙f3fffff3ff333f3333̙f3wUD"wUD"ffffwUfD"f333wwwUUU3DDD"""33###################################################################################################################################################G##########################k################################################################؏#######################################G############################################ڳ##############k##################G##############Gk##############؏##################k#############؏################################G#############G###############################k##############ڳ############################################Gk#########################################################G###############################k############k#########################################################؏######################################################ٳ########################################################G###############################################G##########################################################kG###########׏####################################k############kG###########################################################kG############k##############################kG############ڳ##################G############kG##########################################kG############G##############################kG############؏###############################kG##########################################kG######################################kG##################################k##############################k##########################k######################k##################k##########################################################################################????????(@  $),/1222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222221/,)$  &.6<BFIJLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLJIFB<6.&  (3=FNUZ]`bccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccb`]ZUNF=3( %1>JT]diloqrssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssrqolid]TJ>1% *9GT_hnsvxyz{{||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||{{zyxvsnh_TG9*  ->N\gouzzuog\N>- .@R`lttl`R@.-@Sbn~~nbS@- *>RboobR>*  $9N`oo`N9$ 1G\oo\G1 (>ThhT>( 3J__J3&=UU=& .FffF. 6NN6$<dd<$)BB) ,GG,  /mm/  11  11  22  22  22  22  22  22  22  22  22  22  22  22  22  22  22  22  22  22  22  22  22  22  22  22  22  22  22  22  22  22  22  22  22  22  22  2 N1!2  2 N1!2  2 N1!2  2 N1!2  2 N1!2  2 N1!2  2  N1!,] 2  24 N1!> |2  2  N N1!>.2  2 k N1!>H2  2"  N1!> d2  2 :  N1!> 2  2  U N1!> 42  2 s  N1!! O 2  2( m N1!, l2  2 AB N1! b#2  2  ] | N1!8  :2  2 { O  N1! p W 2  2. ( N1!D t2  2 \ N! 2  2>3 N!  Q2  2> i N!)2  2> : N!  ]2  2= J N! o2  2B \  N!  !2  2 A n N!&  !2  2 A  N!5  !2  2 A % N%G! E !2  2 A4 N1!  W !2  2 AD N1! i !2  2 A V  N1! |  2  2 A g N1!   2  2 A N1!>  2  2 @ N1!>  2  2 @ N1!>  2  2 @ N1!> 2  2 @ N1!> 2  2 ? N1!> 2  2 ? N1! <2  2 N1!2  2 N1!2  2 N1!2  2 N1!2  2 N1!2  2-                   2  22  22  22  22  22  22  22  22  22  22  22  22  22  22  22  22  22  22  22  22  22  22  22  22  22  22  22  22  11  11  //  ,, ))$$   FF  ""SS OO5ww4????????htmldoc-1.9.7/desktop/htmldoc.info000066400000000000000000000000111354715574200171470ustar00rootroot00000000000000HTDChtdc htmldoc-1.9.7/desktop/htmldoc.opacity000066400000000000000000000432631354715574200177040ustar00rootroot00000000000000bplist0056X$versionX$objectsY$archiverT$topgbnopqrvw~VI $'*-45<=IJKLMNVZ^bcipz /5678adgltw}6FGHIJKLPTX\]^_cfghijkpv  %&8HIJKLMNRVZ^_`dghixy   (89:;<=>BFLMNRSTX[\]stuvwxyz{@}~M:9!&*.U$null0  !"#$%&'()*+,-./0123456789:;9<=>>@AB::CDEFGH:IJKLMN>PQRSIMUVWXYB[\>^>BY@9WpolySidWpixDTypSbmPUresUnTsecCUcolSpUoBgImSparVnPaStrWactLaysUsnShsWpenTTypSmodTzoomTallRVsavStDTmetaVspiDecVgenNamUorTypVpixRadTfrasUimSizUbgColVnPaFilV$classVactTraVsavPrDTtarsVcurFraSenVVlineThVautoBTUshLayXrectCRadUresiMTcurRWspiSegsTtrasWfilSensUmainCVtraTrgVcurObjVguiLinTvarsVlasModWpolyStaUbgTyp lc,#@@ #@T #? f< #@ - ,#@I}b,cd"eimWNS.keysZNS.objectsfghjkl \kMDItemTitle^kMDItemAuthors_kMDItemCopyrightXNew Icond"sut ]Michael Sweetxyz{Z$classnameX$classesWNSArray|}WNSArrayXNSObject_Copyright 2017 Michael Sweetxy_NSMutableDictionary}\NSDictionaryd"uX  "SresSdel#?xy\PCResolution}\PCResolutionXPCObject"#?"#?"#?"I"#@"#@"V"#?d"uR "ATlaysUanimTUlAcLs#?cd"mfghjl d"ut d"u>Z "@:R:@MTisShUblendSnamWmaskTypTopacSfilWmaskLayUedMskSvis=.#@Y/ ">BUalConTobjs,-cd"m !"#$    %'()*+ #?#?"V&xy_PCBitmapContext}_PCBitmapContextZPCDrawableXPCObject"#?&"&""#?&"I&"&d"+u xy./]PCNormalLayer0123}]PCNormalLayerWPCLayerZPCDrawableXPCObject]Shadow Effect"678:;TfilNTatts<01_PCShadowEffectFiltercd">Cm?@AB2345DEFD67;6 [inputOffsetZinputColorZinputAngleYinputBlur#@OPQ"RSTUUNSRGB\NSColorSpace_NSCustomColorSpaceJ0 0 0 0.58:W"XYTNSID9xy[\\NSColorSpace]}\NSColorSpacexy_`WNSColora}WNSColor#VxydeXPCFilterfgh}XPCFilterZPCDrawableXPCObjectxyjk]PCFilterLayerlmno}]PCFilterLayerWPCLayerZPCDrawableXPCObject"::@rsMuw@RB? C-E">}B>@,-cd"mA "sV?&Scd"mD "V>&d"uF " @@MM@M@TrectTstrYSisIXstrTBndsTstrXSshXTantiSflVVattStrSshYUalPixSangSflHG # YH> X_5{{4.0850515463917532, 33.996134020618555}, {120, 80}}"XNSString\NSAttributesIWJScd"ŤKLMNĀOPRUVVNSKern_NSParagraphStyleVNSFontWNSColor">ZNSTabStops[NSAlignmentQxy_NSMutableParagraphStyle}_NSParagraphStyle"[VNSSizeXNSfFlagsVNSNameST]OpenSans-BoldxyVNSFont}VNSFontOP"SUF1 0 0:xy}xy_NSAttributedString}_NSAttributedStringP"9UWNSWhiteD1 0:xy\PCTextVector}\PCTextVector_PCRectBasedVectorXPCVectorZPCDrawableXPCObject"::@M@R^[ _-a">BZ\,-cd"m ] "V[&ZBackgroundcd"m` "VZ&d"ub  "!"#@M&M@))*+M@UdimLKWfilPropVcornRXVcornRYUstroscf g #@0{Z cd"02m1d3e ]cornerRadiusX]cornerRadiusY_{{4, 4}, {120, 120}}9:;<=>"?@ABCDEFGHIJKLMN@PQ:RS:TUVW>Y[\:]^S_MVrelLP2SblHWgradAngUradGCTfilTWrelRadCVfilPosSaEqStypXrelLinP1VfilColVrelLP1UfilImVothColXrelLinP2SgEqUfilGrSrEqXgradStopUpgNumSbEqt#@Vpqzyshribuwvjx OP"bSUF0 0 0:OP"eSUL0.6 0.6 0.6:d"hkijknomno">&<sValtColSlocScolglmP"u9UB1:xyxy^PCGradientStopz{|}^PCGradientStopZPCDrawableXPCObjectmno">&Ysgimxy^NSMutableArray}WNSArrayV{0, 0}V{0, 0}V{0, 0}V{0, 0}V{0, 0}V{0, 0}Q0QtW100 - tS100xy_PCDrawVectorProperties}_PCDrawVectorPropertiesZPCDrawableXPCObjectd"k|o9:<;=>"?@ABEDFGHIoJKLM@P::T>:M\I:\]S_TcapSSposUinvisSwidUdashSy~b w}vxP"9UB0:OP"SUL0.4 0.4 0.4:d"komno">\s|}mmno">s|~mV{0, 0}V{0, 0}V{0, 0}V{0, 0}V{0, 0}V{0, 0}d"uO xy_PCStrokeVectorProperties}_PCStrokeVectorProperties_PCDrawVectorPropertiesZPCDrawableXPCObjectxy\PCRectVector}\PCRectVector\PCPathVector_PCRectBasedVectorXPCVectorZPCDrawableXPCObjectd"u> xyWPCFrame}WPCFrame_PCMetadataObjectZPCDrawableXPCObjectd"uˀ߀ "A @M>>: >M@@BYauSizCropVnewFacUapIn1TpathTapIDUcropRUapIn2UisRelUisColTcropVvarVal ,_{{0, 0}, {0, 0}}\htmldoc.icns"A !"#$MR'()*>,-.M0134UcodeSUprColVprShTiSfraVcodePlVcodeFrUcodeFTsnShVexPropTpropUgenCHUgrTypVanLooCVprLinCUcodeL   cd"7>m89:;<=?@<BCDl V{JFIF}U{GIF}_"kCGImageDestinationBackgroundColorU{PNG}V{TIFF}_*kCGImageDestinationLossyCompressionQualitycd"MNm cd"QRm cd"UVm cd"YZm #?^com.apple.icns]public.foldercd"`am OP"dSUL0.5 0 0 0.5:SiosUcocoaUtouchVMyViewVUIViewxylm_PCBitmapPropertiesno}_PCBitmapPropertiesXPCObjectxyqrYPCFactorystu}YPCFactoryZPCDrawableXPCObject"A @@>z>: >M@@B ,_htmldoc-128.png"A !"$MR'(*>M014  cd"m<l V{JFIF}U{GIF}_"kCGImageDestinationBackgroundColorU{PNG}V{TIFF}_*kCGImageDestinationLossyCompressionQualitycd"m cd"m cd"m cd"m #?Zpublic.pngcd"m OP"SUL0.5 0 0 0.5:VMyViewVUIView"A @@>>:>M@MB  ,_{{8, 8}, {113, 113}}^htmldoc-32.png"A !"$MR(*>M01( ɀǀ Ȁcd"m<€ÀlĀŀƀ cd"m cd"m cd"m cd"  m #?cd"m OP"SUL0.5 0 0 0.5:SmacVNSView"A @M>>: >M@@#B ̀ ̀,[htmldoc.ico"A !"'$MR'(,*>/01M0154 ݀ۀ΀ ˀ܀cd"9@m:;<=>?πЀрҀӀԦAB<DEFՀրl׀؀ـ V{JFIF}U{GIF}_"kCGImageDestinationBackgroundColorU{PNG}V{TIFF}_*kCGImageDestinationLossyCompressionQualitycd"OPm cd"STm cd"WXm cd"[\m #?_com.microsoft.icocd"abm OP"eSUL0.5 0 0 0.5:VMyViewVUIView"A @@>m>: >M@@vB ,_htmldoc-160.png"A !"z$MR'(*>M014 ‸ ߀cd"m<l V{JFIF}U{GIF}_"kCGImageDestinationBackgroundColorU{PNG}V{TIFF}_*kCGImageDestinationLossyCompressionQualitycd"m cd"m cd"m cd"m #?cd"m OP"SUL0.5 0 0 0.5:VMyViewVUIView"A @@>>: >M@@B󀨀 ,_htmldoc-256.png"A !"$MR'(*>M14  cd"m<l V{JFIF}U{GIF}_"kCGImageDestinationBackgroundColorU{PNG}V{TIFF}_*kCGImageDestinationLossyCompressionQualitycd"m cd"m cd"m cd"m #?]public.foldercd"m OP" SUL0.5 0 0 0.5:VMyViewVUIViewd"koZ{128, 128}P"9UE0.75:_CICheckerboardGenerator"A !">$MR*> !M01% Ɂ  cd")0m*+,-./  <23456l _"kCGImageDestinationBackgroundColorV{JFIF}U{GIF}V{TIFF}U{PNG}_*kCGImageDestinationLossyCompressionQualitycd"?@m cd"CDm cd"GImHJ [Compressioncd"OPm #?_com.likethought.opacity.opacitycd"UVm OP"YSUJ1 0 0 0.5:Vquartz_MyDrawingFunctioncd"^hm_`abcdefg !"#$%&'iiklinoii(()*(+,(( _framePickerVisibleZhideRulers[windowFrame_layerViewDimension]hideVariablesZexpansionsYprintInfo]toolbarHidden_editFrameMetadata_{{4, 254}, {626, 523}}#@i`cd"m "\NSAttributes;-cd"m./012345677896:: _NSHorizontallyCentered]NSRightMargin\NSLeftMargin_NSHorizonalPagination_NSVerticalPagination_NSVerticallyCentered[NSTopMargin^NSBottomMargin "B"Bxy[NSPrintInfo}[NSPrintInfocd"m=>?@ABCDJNS=W _"com.likethought.opacity.preview.ui_(com.likethought.opacity.preview.elementsWfactory_#com.likethought.opacity.preview.web_&com.likethought.opacity.preview.cursorTtype_&com.likethought.opacity.preview.iphonecd"mǁEBF<ˀl9G Ucolor[resolutionsd"kHI#$o#?#?cd"m܁KLMii((6 VstatusWtoolbarTdockcd"mOPQR WaddressUimage_#http://likethought.com/opacity/web/_,http://likethought.com/opacity/web/image.pngcd"mŁTBUEELRY`gnu| &/8AKT]gqz !-8COZfr~ -;HUcq~ +:IXgw'7HYj{+=Oat 2FZn  % : O d y  ' = T j " 9 Q i  * C \ u & @ Z t .Id %A^z &Ca~1Om&Ed#Cc'Ij4Vx&IlAe@e Ek*Qw;c*R{Gp@j>i  A l !!H!u!!!"'"U"""# #8#f###$$M$|$$% %8%h%%%&'&W&&&''I'z''( (?(q(())8)k))**5*h**++6+i++,,9,n,,- -A-v--..L.../$/Z///050l0011J1112*2c223 3F3334+4e4455M555676r667$7`7788P8899B999:6:t::;-;k;;<' >`>>?!?a??@#@d@@A)AjAAB0BrBBC:C}CDDGDDEEUEEF"FgFFG5G{GHHKHHIIcIIJ7J}JK KSKKL*LrLMMJMMN%NnNOOIOOP'PqPQQPQQR1R|RSS_SSTBTTU(UuUVV\VVWDWWX/X}XYYiYZZVZZ[E[[\5\\]']x]^^l^__a_``W``aOaabIbbcCccd@dde=eef=ffg=ggh?hhiCiijHjjkOkklWlmm`mnnknooxop+ppq:qqrKrss]sttptu(uuv>vvwVwxxnxy*yyzFz{{c{|!||}A}~~b~#G k͂0WGrׇ;iΉ3dʋ0cʍ1fΏ6n֑?zM _ɖ4 uL$h՛BdҞ@iءG&vVǥ8nRĩ7u\ЭD-u`ֲK³8%yhYѹJº;.! zpg_XQKFAǿ=ȼ:ɹ8ʷ6˶5̵5͵6ζ7ϸ9к<Ѿ?DINU\dlvۀ܊ݖޢ)߯6DScs 2F[p(@Xr4Pm8Ww)Kmexy+,]NSMutableData+-}VNSDataxy/0WPCImage1234}WPCImage_PCMetadataObjectZPCDrawableXPCObject_NSKeyedArchiver7Troot"+5:? &*/4;@GNT[`flsz  (*-/8;DFILMPRUWY[\_hjlnpy{}  +4<AIRqz&/@BKMO`bkmo&)+-FKQWY[]fhjw~         ! * , . / 0 E K P R T V X Z g t v x z | ~    " / 1 3 @ B K M Z \ ^ k m o x y {   % ' ) + - 6 8 : < > @ L W b l u    ) 2 ; D O X a o z         ) + - 1 > A C F H J W Y [ d g i k    FS\ikmos!4ELU\^`bpy '4HQ\e  !#,/13zfmqy   !(*7DFOTVXZovz~ '.5<CJLNVZc|5:>DHNPQSUWY[]_acdfhjlnpr !&(*,5P[v !#,4?GZenw  "$%'()+-@M   !#0=?ACEGIVXZ\^`bdkq,:GHIKXegkqw~ABCEGIKMOPRSTVXj !'LRY  XYZ\^`bdfgijkmo "$&(*79;=?ACERSTVcdegtuvx     ,{}~    H U V W Y f g h j w x y { !#!$!%!'!)!+!-!/!1!2!4!5!6!8!:!L!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"" "."4";"h"u"v"w"y""""""""""""""""""""""#/#0#1#3#5#7#9#;#=#>#@#A#B#D#F#X###########################$$$$$ $ $$$$@$F$M$z$$$$$$$$$$$$$$$$$$$$$$$%%% %%%%%'%4%:%<%V%%%%%%%%%%%%%%%%%%%%%%%%%%&&& & &&&&&=&D&J&Q&W&&&&&&&&&&&&&&&&&&&&&&' ''''')'4'6'='Q'^'q't'w'z'}''''''''''''''''''''( (( (.(B(C(\(e(r(s(t(v(((((((((((((((((((((((() ))')?)V)m)y))))))))))))))))))))**** * **4*_*g********+++ + ++++$+-+6+9+<+>+@+B+K+T+a+h+k+n+q+x+{+~++++++++++++++++,,,,5,8,;,>,A,J,L,O,Q,S,U,^,g,t,,,,,,,,,,,,,,,,,,,,,,,,,,,-------"-(-*---/-8-@9999999999999:::9:htmldoc-1.9.7/desktop/htmldoc.plist.in000066400000000000000000000027521354715574200177720ustar00rootroot00000000000000 CFBundleInfoDictionaryVersion 6.0 CFBundleExecutable htmldoc CFBundleIdentifier org.msweet.htmldoc CFBundleVersion @SVERSION@ CFBundleDevelopmentRegion English NSHumanReadableCopyright Copyright 1997-2019 by Michael R Sweet CFAppleHelpAnchor help CFBundleName HTMLDOC CFBundlePackageType APPL CFBundleSignature HTDC CFBundleIconFile htmldoc.icns CFBundleShortVersionString @SVERSION@ CFBundleGetInfoString @SVERSION@, Copyright Michael R Sweet 1997-2019 CFBundleDocumentTypes CFBundleTypeExtensions book CFBundleTypeIconFile htmldoc.icns CFBundleTypeName HTMLDOC Book File CFBundleTypeOSTypes htdc CFBundleTypeRole Editor htmldoc-1.9.7/desktop/htmldoc.xbm000066400000000000000000000015761354715574200170230ustar00rootroot00000000000000#define htmldoc_width 32 #define htmldoc_height 32 static unsigned char htmldoc_bits[] = { 0xf0, 0xff, 0xff, 0x0f, 0xf8, 0xff, 0xff, 0x1f, 0xfc, 0xff, 0xff, 0x3f, 0xfe, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7, 0xe3, 0xff, 0xff, 0xc4, 0x23, 0xff, 0x3f, 0xc4, 0x23, 0xfc, 0x0f, 0xc7, 0xe3, 0xf0, 0xc7, 0x07, 0xe0, 0xe3, 0xc7, 0x07, 0xe0, 0xe3, 0x0f, 0x07, 0xe0, 0xf0, 0x3f, 0xc4, 0x23, 0xfc, 0xff, 0xc4, 0x23, 0xff, 0xff, 0xc7, 0xe3, 0xff, 0xff, 0xc7, 0xe3, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0x7f, 0xfc, 0xff, 0xff, 0x3f, 0xf8, 0xff, 0xff, 0x1f, 0xf0, 0xff, 0xff, 0x0f }; htmldoc-1.9.7/desktop/htmldoc.xcf000066400000000000000000000025211354715574200170040ustar00rootroot00000000000000gimp xcf file BBBgimp-image-grid(style solid) (fgcolor (color-rgba 0.000000 0.000000 0.000000 1.000000)) (bgcolor (color-rgba 1.000000 1.000000 1.000000 1.000000)) (xspacing 10.000000) (yspacing 10.000000) (spacing-unit inches) (xoffset 0.000000) (yoffset 0.000000) (offset-unit inches) gamma0.45455000000000001 htmldoc-32.png     h | Uq  " " = 1  U&&&&&&&&&&& &&&5&&&&&&;  UK4p;  htmldoc-1.9.7/desktop/htmldoc.xml000066400000000000000000000005631354715574200170300ustar00rootroot00000000000000 HTMLDOC Book File htmldoc-1.9.7/desktop/htmldoc.xpm000066400000000000000000000027011354715574200170300ustar00rootroot00000000000000/* XPM */ static const char * const htmldoc_xpm[] = { "32 32 17 1", " c None", ". c #000000", "+ c #0F0F0F", "@ c #FF0000", "# c #FF2600", "$ c #221A18", "% c #110200", "& c #040000", "* c #010000", "= c #030000", "- c #0D0200", "; c #220400", "> c #0D0100", ", c #3D3534", "' c #1C0300", ") c #030303", "! c #070707", " ........................ ", " ................+......... ", " ............................ ", " .............................. ", "................................", "................................", ".......................+........", "................................", "................................", "................................", "...........@@@....@@@...........", "........@@.@##....##@.@@........", "......@@@@.@##....##@.@@@@......", "....@@@@...@##....##@...@@@@....", "...@@@..$..@##@@@@##@.....@@@...", "...@@@%&*..@#####@##@...=-@@@...", "....@@@@;>.@##@@@@##@.,'@@@@.*..", "......@@@@.@##....##@.@@@@..*...", "........@@.@##....@#@.@@........", "...........@##....@#@...........", ".........+.@@@....@@@...........", "................................", ".......++..............)........", "....+++.................).......", "..++.....................++)....", "++..........................+!..", "..............................+.", "................................", " .............................. ", " ............................ ", " .......................... ", " ........................ "}; htmldoc-1.9.7/dmgbuild.png000066400000000000000000000257321354715574200155050ustar00rootroot00000000000000PNG  IHDR09iCCPkCGColorSpaceGenericRGB8U]hU>sg#$Sl4t? % V46nI6"dΘ83OEP|1Ŀ (>/ % (>P苦;3ie|{g蹪X-2s=+WQ+]L6O w[C{_F qb Uvz?Zb1@/zcs>~if,ӈUSjF 1_Mjbuݠpamhmçϙ>a\+5%QKFkm}ۖ?ޚD\!~6,-7SثŜvķ5Z;[rmS5{yDyH}r9|-ăFAJjI.[/]mK 7KRDrYQO-Q||6 (0 MXd(@h2_f<:”_δ*d>e\c?~,7?& ك^2Iq2"y@g|U\ pHYs%%IR$iTXtXML:com.adobe.xmp Michael Sweet Copyright 2018 Michael Sweet New Image ;Q$IDATxydU'[, PUʦ 32 `Ȯa ؂3 Ҋ PȀ-"l*"% 4Vl˨|q^^թ'T],9WY( [elUJ@VY( [elUJ@VY( [elUJ@VY( [elUJ@VY( [elUJ@VY( [elUJ@VY( [elUJ@VY( [elUJ@VY( [elUJ@VY( [elUJ@VY( [elUJ@VY( [elUJ@VY(F% /ȘBFD dL#2QSˆ()`D@Ɣ/"J@ c% 1ȘED dL"2hQS()XD@Ɣ+"J@ c% 1ȘBED dL"2HQS()PD@Ɣ'"J@ c% 1H,GHG`B L EH,&o.DG6HO&P_~it3&7摔x+?],Z]D4]US'-S*} R^vJL;eȄ57Sk/~}̪T-Zs~*_H˿Smk+AF_J.IQ*^+ڹ`a6H)84% 0F]PgɔBCS8λH%mk w,ޚyھW:릿/g]MRԮ5J<zV5iX&etܮ)L`'xoϸ(vJwQq#LDxS“Nc^3#JGߗdnnUgF,pc]F^?3ZP0mbSFAFC](;ca?7\W,qF:nq.ns??yv[k[7.2y4q(Hd+VFʗ\X/PO6602.~2%V*~o`{am*V~6{vUYCxz>MO46Lzj䴹+>od 8+Z՗k%;Ewz5zܙ žR]*)TpŹKqzt>b)*QJFɵ%0,toOyFs72+ZFT+~.O/(Py" Q]_;.>EqCr1뼆gZ?k%ʖsv]Z++s>Q Ϡk^}IŴjvoq*۹?{X y@C +֯_ҽYrI909fU>hXF&l.7S0Z֭dM:nL7jE!ig *ŋ<];GvhlV](;6b2rD]60FMToRceeёDZq/#^FeQyZu[Cvw~oTk4DJyzM_Cxzyly=xx/q/,c ,6JFiT$ųc𢡊:V?j8lm_{L;v_/p1]s;aAv~h FP ԸB'b@vcZ c^Ϊ W>ϝzimࣵgP]{[{<ھ7;vnn)՗5 6@~sk=Jj^; FXףzDZO8 @ظnZ樆k8yҢxG:˳m8_}j}>aqic okh , }]FU;8VT1n`6ʌXtaQLsj]J5S%TLxϧ9aquHp/Jy>W,Em]K}sq~#CFk RV}ݾ@U+ls9 K*E/AW su|G};Ẏ)/>KyYF;Of ~XF&Tca`s£=vZ)(aZq\WOϳ{!9OsWVZVaTB#QFλ{:gR/{6| k1e}?>WptK~6s9&ݶnñj8V,Xu8TbpAKv9g]> XkR [XZٵ|#=zb\׼./tG4>od @0Ƶ"2Qd@CA7훦sTG54,+Q mg1! =z(]Ϯ#,&e*vq,~#QPciL Uuʕ8#8J15c$)1ȃ %P& }\51uڵb;y'm֎*F}:"h^q==i[ȼDZLD?XH ryn1Zj~ʰs*PJ_K.-)U.+']6FMUS3F4ebјS:s 8H9`P!UϢ[Ǿȳ0$_Lh(L/V]T$?`P%ӴSSwsQGRnL]F},PRTH~PQ()ND@Ɣ'"? c 1%Ș"EDdL"2PQS()VD@Ɣ+"? c 1%ȘEDdL"2pQS()^D@Ɣ/"? c 1%Ș"FDdL#2QR@Ɣ1dLS@Ɣ1dLS@Ɣ1dLS@Ɣ1dLS@Ɣ1dLS@Ɣ1dLS@Ɣ1dLS@Ɣ1dLS@Ɣ1dLS@Ɣ1dLS@Ɣ1dLS@Ɣ1dLS@Nr (EDBA " @Ș@D1%( cJQ@Ɣ")DDS2 dL " @Ș@D1%( cJQ@Ɣ")DDS2 dL " @Ș@D1%( cJY3eʔrmm-oy{" @P>lЇ>䞈*[nQPqV^yr-ho.l~x;,L#8 +0mf{]s1G?qz>뮻5E&O<<[n>l7߼zNZnvaV|V[mU.úw&M*Yg=8ꨣ=أ\s5{[U|>qڴi̙3*w |q/x[_O~.7ؿ/ (|(.Vu駗;':& Yfu/Bkz]wݵnnh{iulk:ε:s\>Q+oA;3K/'EY}iʇz\s5]kjRC%#x=4{mC}?>?y{:_#!' Ѧ{~vPAZꫯo1LJUSwq^=J!w{9 A :k}o& hxN]8Ds6>:s_5bSN)/VYc{k{;;h Q^UG|Y-;.m><bkg̘Q]tQ;F([lq{g_joz;lͰ_\_Zx̌ǽاSOmK/?x58?Wu]kߖsxlE9.b>O?t{G sۗ_~~wkQ E+SO=z=4նx\ѰF\O}%]Vqq1Z>FYK.gA/c߱>y\~ַ9/ulcz׾V#3{V}=s,m)@81"O:;g\pAǶ?Obuy䑍Eڦn:Z7Eo혢Ӛ=:^xb^$J{5:|*# ,c=Q] 4_LK)qE («:Csw󶷽m`>88F٦ckVǾw[WGJ1/nbytl+#w}w>mQ(#F|́}bX1ŶH~?O;{{я~beܱ=W g5hQp qJlULSr[/#'tR㊻aٍUledL%y3xJ+4px>awe]>^΍E:±\}~|;cg>rkln#HE Ol*V,Ƣ,7s̎cT)S_h?w~ܺv7woxGZ sJ{J;qlaCӔǺ};_qX=7p"#)])@8MEXȽ(#EV}[W]u~pE[J+ ŢsT⪭zjUV86{Ǣx;4W {H&QodM)@>sX`#FUGvmM_}y~g}q?_|fX ]Ģ 1"Hu~ 1=w]wm-K-K @P.Wsz?輳fSjۢj6O&M8_L~3gN{ z8gLp K.7~v h "/Vg=í{[7|e-/袎 H{5w^ǹ->E 1bjnVtڢ裏nrZV4BkeOӃ;[+X7h~quZyꫯ.󟷦>)natd{vYfntx8iFUzꩃ+ћQBFٴ(@w}r-7묳Π}o!1p9Fם}]W%wܱ52o(M`H[.=ЎVXay =\>{oa| ,})@Ql,b'\]1oۃ9#Ҫga뮻Yy1vƌƊ1*.Vƭk<]c5Z TŴ=3}b?ov=W,L ?C(g HTMLDOC Users Manual

Chapter 1 - Introduction

This document describes how to use the HTMLDOC software. HTMLDOC reads HTML and Markdown source files or web pages and generates corresponding EPUB, HTML, PostScript, or PDF files with an optional table of contents. HTMLDOC can be used as a standalone application, in a batch document processing environment, or as a web-based report generation application.

HTMLDOC is open source software under the terms of version 2 of the GNU General Public License. No restrictions are placed upon the output produced by HTMLDOC.

History

Like many programs, I developed HTMLDOC in response to a need my company had for generating high-quality documentation in printed and electronic forms. For a while I used FrameMaker® and a package from sgi that generated "compiled" Standard Generalized Markup Language ("SGML") files that could be used by the Electronic Book Technologies ("EBT") documentation products; EBT was bought by INSO who was bought by StellentTM who apparently has dropped the whole product line. When sgi stopped supporting these tools I turned to INSO, but the cost of their tools was prohibitive to my small business.

In the end I decided to write my own program to generate the documentation. HTML seemed to be the source format of choice since WYSIWYG HTML editors are widely (and freely) available and at worst you can use a plain text editor. I needed HTML output for documentation on my web server, PDF for customers to read and/or print from their computers, and PostScript for printing needs.

The result of my efforts is the HTMLDOC software which runs on Linux®, macOS®, Microsoft® Windows®, and most UNIX® operating systems. Among other things, this software users manual is produced using HTMLDOC.

HTMLDOC used to be available under a commercial end-user license agreement from my former company, Easy Software Products. While that company is no longer in business, I continue to maintain HTMLDOC in my spare time.

Organization of This Manual

This manual is organized into tutorial and reference chapters and appendices:

Encryption Support

HTMLDOC includes code to encrypt PDF document files using the RC4 algorithm with up to a 128-bit key. While this software and code may be freely used and exported under current US laws, other countries may restrict your use and possession of this code and software.

Legal Stuff

HTMLDOC is copyright © 1997-2019 by Michael R Sweet. See Appendix A - License Agreement for the terms of use. This software is based in part on the work of the Independent JPEG Group and FLTK project.

htmldoc-1.9.7/doc/2-using.html000066400000000000000000000514571354715574200161320ustar00rootroot00000000000000

Chapter 2 - Using HTMLDOC

This chapter describes the basics of how to use HTMLDOC to convert HTML and Markdown files into PostScript and PDF files.

Note: HTMLDOC currently does not support HTML 4.0 features such as stylesheets or the STYLE element. For more information, please consult Chapter 4 - HTML Reference.

Using the HTMLDOC GUI

After opening the HTMLDOC application, the HTMLDOC window will appear with the Input tab selected. Click on the Web Page radio button to specify that you will be converting a web page file. Then choose a file for conversion by clicking on the Add Files... button.

Now that you've chosen a file to be converted, click on the Output tab to set the output file and format. Finally, click on the Generate button at the bottom of the HTMLDOC window to convert the HTML file.

Generating Books

While HTMLDOC can convert web pages into PostScript and PDF files, its real strength is generating EPUB, indexed HTML, PostScript, or PDF books. HTMLDOC uses heading elements to delineate chapters and headings in a book. The H1 element is used for chapters:

<HTML>
<HEAD>
    <TITLE>The Little Computer that Could</TITLE>
</HEAD>
<BODY>
<H1>Chapter 1 - The Little Computer is Born</H1>
...
<H1>Chapter 2 - Little Computer's First Task</H1>
...
</BODY>
</HTML>

Sub-headings are marked using the H2 through H6 elements.

Note: When using book mode, HTMLDOC starts rendering with the first H1 element. Any text, images, tables, and other viewable elements that precede the first H1 element are silently ignored. Because of this, make sure you have an H1 element in your HTML file, otherwise HTMLDOC will not convert anything.

Start by clicking on the Book radio button to specify you'll be converting one or more files into a book. Then add one or more HTML or Markdown files by clicking on the Add Files... button.

HTMLDOC will automatically create a title page for you unless you specify a Title File/Image. When the title file is HTML or Markdown, the contents are formatted to produce title page(s). When the title file is an image, the image is centered on the title page with automatically generate content based on the title and other metadata.

After providing all of the input files, click on the Output tab to select the output format and file. Finally, click on the Generate button to generate the book.

Using the HTMLDOC Command

To convert a single web page type:

htmldoc --webpage -f output.pdf filename.html ENTER

htmldoc is the name of the software.

The --webpage option specifies unstructured files with page breaks between each file.

The -f option specifies the output file name (output.pdf). In this example it is a PDF file.

Filename.html is the name of the file that you want to be converted.

To convert more than one web page with page breaks between each file, list each of the files on the end:

htmldoc --webpage -f output.pdf file1.html file2.html ENTER

We've been using HTML files, but you can also use URLs. For example:

htmldoc --webpage -f output.pdf http://slashdot.org/ ENTER

Generating Books

Type one of the following commands to generate a book from one or more files:

htmldoc --book -f output.html file1.html file2.html ENTER
htmldoc --book -f output.pdf file1.html file2.html ENTER
htmldoc --book -f output.ps file1.html file2.html ENTER

The --book option specifies that the input files are structured with headings.

The -f option specifies the output filename.

File1.html and file2.html are the files you want to convert.

HTMLDOC will build a table of contents for the book using the heading elements (H1, H2, etc.) in your input files. It will also add a title page using the document TITLE text and other META information you supply in your files. See Chapter 4 - HTML Reference for more information on the META variables that are supported.

Note: When using book mode, HTMLDOC starts rendering with the first H1 element. Any text, images, tables, and other viewable elements that precede the first H1 element are silently ignored. Because of this, make sure you have an H1 element in your HTML file, otherwise HTMLDOC will not convert anything.

Setting the Title File

The --titlefile option sets the HTML, Markdown, or image file to use on the title page:

htmldoc --titlefile filename.bmp ... ENTER
htmldoc --titlefile filename.gif ... ENTER
htmldoc --titlefile filename.jpg ... ENTER
htmldoc --titlefile filename.png ... ENTER
htmldoc --titlefile filename.html ... ENTER

HTMLDOC supports BMP, GIF, JPEG, and PNG images, as well as generic HTML or Markdown text you supply for the title page(s).

Using HTMLDOC on a Web Server

HTMLDOC can be used in a variety of ways to generate formatted reports on a web server. The most common way is to use HTMLDOC as a CGI program with your web server to provide PDF-formatted output of a web page. Examples are provided for Microsoft IIS and the Apache web servers.

HTMLDOC can also be called from your own server-side scripts and programs. Examples are provided for PHP and Java.

Warning: Passing information directly from the web browser to HTMLDOC can potentially expose your system to security risks. Always be sure to "sanitize" any input from the web browser so that filenames, URLs, and options passed to HTMLDOC are not acted on by the shell program or other processes. Filenames with spaces must usually be enclosed with quotes.

CGI Mode

HTMLDOC supports operation as a CGI program. You can copy or symlink the htmldoc (all but Windows) or htmldoc.exe (Windows) executable to your web server's cgi-bin directory and then use it to produce PDF versions of your web pages.

The CGI converts a page on your local server to PDF and sends it to the client's web browser. For example, to convert a page called superproducts.html at the following URL:

http://servername/superproducts.html

and if you installed HTMLDOC in your server's cgi-bin directory, you would direct your clients to the following URL:

http://servername/cgi-bin/htmldoc/superproducts.html

The boldface portion represents the location of the HTMLDOC executable on the web server. You simply place that path before the page you want to convert.

Form data using the GET method can be passed at the end of the URL, for example:

http://servername/cgi-bin/htmldoc/superproducts.html?name=value

Server-Side Preferences

When run as a CGI program, HTMLDOC will try to read a book file to set any preferences for the conversion to PDF. For the superproducts.html file described previously, HTMLDOC will look at the following URLs for a book file:

http://servername/superproducts.html.book
http://servername/.book
http://servername/cgi-bin/.book

The first book file that is found will be used.

Configuring HTMLDOC with Apache

The Apache web server is easily configured to use HTMLDOC. The simplest way is to copy or symlink the htmldoc executable to the configured cgi-bin directory. For example, if your Apache installation is configured to look for CGI programs in the /var/www/cgi-bin directory, the default for Apache on Red Hat Linux, then the command to install HTMLDOC on your web server would be:

ln -s /usr/bin/htmldoc /var/www/cgi-bin ENTER

If you are using Apache 2.0.30 or higher, you will also need to enable PATH_INFO support by adding the following line to your httpd.conf file:

AcceptPathInfo On

Apache also allows you to associate CGI programs with a specific extension. If you add the following line to your httpd.conf file:

AddHandler cgi-script .cgi

and enable CGI execution with the Options directive for a directory:

Options +ExecCGI

then you can copy or symlink the htmldoc executable to an alternate location. For example, if you have a web directory called /var/www/htdocs/products, you can install HTMLDOC in this directory with the following command:

ln -s /usr/bin/htmldoc /var/www/htdocs/products/htmldoc.cgi ENTER

Configuring HTMLDOC with Microsoft IIS

The IIS web server is configured to run CGI programs by either modifying the permissions of an existing directory or by creating a new virtual directory that allows for execution of programs. Start by running the Internet Services Manager program:

  1. Click on Start
  2. Click on Settings
  3. Click on Control Panel
  4. Double-click on Administrative Tools
  5. Double-click on Internet Services Manager

After the Internet Services Manager window appears, perform the following steps to add a virtual folder for HTMLDOC:

  1. Click on your server in the list to show the default web site service in the list
  2. Choose New->Virtual Directory from the Action menu
  3. Click Next when the Virtual Directory Creation Wizard window appears
  4. Enter the name htmldoc in the Alias field and click Next
  5. Enter the HTMLDOC program folder in the Directory field and click Next
  6. Check the Execute (such as ISAPI applications or CGI) box and click Next
  7. Click Finish to dismiss the wizard
  8. Click on Web Service Extensions
  9. Click Add a new Web Service Extension
  10. Enter the name "HTMLDOC" when the Web Service Extension window appears
  11. Click Add... and choose the htmldoc.exe file from the program folder, typically C:\Program Files\msweet.org\HTMLDOC
  12. Check the Set extension status to Allowed box
  13. Click OK to add the extension and dismiss the window

Finally, double-click the My Computer icon on the desktop or start the Windows Explorer. When the explorer window appears, perform the following steps to provide write access to the Windows temporary folder:

  1. Open the windows temporary file folder, typically C:\WINDOWS\TEMP
  2. Choose Properties from the File menu
  3. Click on the Security tab
  4. Click Add..., enter the username for the web server, typically "SERVER\IUSR_SERVER" where "SERVER" is the name you gave your server, and click OK
  5. Click on the username you just added in the list
  6. Check the Read and Write permissions
  7. Click OK to save the changes

Once configured, the htmldoc.exe program will be available in the web server directory. For example, for a virtual directory called cgi-bin, the PDF converted URL for the superproducts.html page would be as follows:

http://servername/cgi-bin/htmldoc.exe/superproducts.html

The boldface portion represents the location of the HTMLDOC program on the web server.

Using HTMLDOC From Server-Side Scripts and Programs

To make this work the CGI script or program must send the appropriate HTTP attributes, the required empty line to signify the beginning of the document, and then execute the HTMLDOC program to generate the HTML, PostScript, or PDF file as needed. Since HTMLDOC looks for CGI environment variables when it is run, you must also set the HTMLDOC_NOCGI environment variable to a value of 1 before running HTMLDOC from your CGI script or program.

Another way to generate PDF files from your reports is to use HTMLDOC as a "portal" application. When used as a portal, HTMLDOC automatically retrieves the named document or report from your server and passes a PDF version to the web browser. See the next sections for more information.

Calling HTMLDOC from a Shell Script

Shell scripts are probably the easiest to work with, but are normally limited to GET type requests. Here is a script called topdf that acts as a portal, converting the named file to PDF:

#!/bin/sh
#
# Sample "portal" script to convert the named HTML file to PDF on-the-fly.
#
# Usage: http://www.example.com/path/topdf/path/filename.html
#

#
# Tell HTMLDOC not to run in CGI mode...
#

HTMLDOC_NOCGI=1; export HTMLDOC_NOCGI

#
# The "options" variable contains any options you want to pass to HTMLDOC.
#

options='-t pdf --webpage --header ... --footer ..."

#
# Tell the browser to expect a PDF file...
#

echo "Content-Type: application/pdf"
echo ""

#
# Run HTMLDOC to generate the PDF file...
#

htmldoc $options http://${SERVER_NAME}:${SERVER_PORT}$PATH_INFO

Users of this CGI would reference the URL "http://www.example.com/topdf.cgi/index.html" to generate a PDF file of the site's home page.

The options variable in the script can be set to use any supported command-line option for HTMLDOC; for a complete list see Chapter 3 - Command-Line Reference.

Calling HTMLDOC from Perl

Perl scripts offer the ability to generate more complex reports, pull data from databases, etc. The easiest way to interface Perl scripts with HTMLDOC is to write a report to a temporary file and then execute HTMLDOC to generate the PDF file.

Here is a simple Perl subroutine that can be used to write a PDF report to the HTTP client:

sub topdf {
    # Get the filename argument...
    my $filename = shift;

    # Make stdout unbuffered...
    select(STDOUT); $| = 1;

    # Tell HTMLDOC not to run in CGI mode...
    $ENV{HTMLDOC_NOCGI} = 1;

    # Write the content type to the client...
    print "Content-Type: application/pdf\n\n";

    # Run HTMLDOC to provide the PDF file to the user...
    system "htmldoc -t pdf --quiet --webpage $filename";
}

Calling HTMLDOC from PHP

PHP provides a passthru() function that can be used to run HTMLDOC. This combined with the header() function can be used to provide on-the-fly reports in PDF format.

Here is a simple PHP function that can be used to convert a HTML report to PDF and send it to the HTTP client:

function topdf($filename, $options = "") {
    # Tell HTMLDOC not to run in CGI mode...
    putenv("HTMLDOC_NOCGI=1");

    # Write the content type to the client...
    header("Content-Type: application/pdf");
    flush();

    # Run HTMLDOC to provide the PDF file to the user...
    passthru("htmldoc -t pdf --quiet --jpeg --webpage $options " . escapeshellarg($filename));
}

The function accepts a filename and an optional "options" string for specifying the header, footer, fonts, etc.

To make a "portal" script, add the following code to complete the example:

global $SERVER_NAME;
global $SERVER_PORT;
global $PATH_INFO;
global $QUERY_STRING;

if ($QUERY_STRING != "") {
    $url = "http://${SERVER_NAME}:${SERVER_PORT}${PATH_INFO}?${QUERY_STRING}";
} else {
    $url = "http://${SERVER_NAME}:${SERVER_PORT}$PATH_INFO";
}

topdf($url);

Calling HTMLDOC from C

C programs offer the best flexibility and easily supports on-the-fly report generation without the need for temporary files.

Here are some simple C functions that can be used to generate a PDF report to the HTTP client from a temporary file or pipe:

#include <stdio.h>
#include <stdlib.h>


/* topdf() - convert a HTML file to PDF */
FILE *topdf(const char *filename)       /* I - HTML file to convert */
{
  char	command[1024];			/* Command to execute */


 /*
  * Tell HTMLDOC not to run in CGI mode...
  */

  putenv("HTMLDOC_NOCGI=1");

 /*
  * Write the content type to the client...
  */

  puts("Content-Type: application/pdf\n");

 /*
  * Run HTMLDOC to provide the PDF file to the user...
  */

  sprintf(command, "htmldoc --quiet -t pdf --webpage %s", filename);

  return (popen(command, "w"));
}


/* topdf2() - pipe HTML output to HTMLDOC for conversion to PDF */
FILE *topdf2(void)
{
 /*
  * Tell HTMLDOC not to run in CGI mode...
  */

  putenv("HTMLDOC_NOCGI=1");

 /*
  * Write the content type to the client...
  */

  puts("Content-Type: application/pdf\n");

 /*
  * Open a pipe to HTMLDOC...
  */

  return (popen("htmldoc --quiet -t pdf --webpage -", "w"));
}

Calling HTMLDOC from Java

Java programs are a portable way to add PDF support to your web server. Here is a class called htmldoc that acts as a portal, converting the named file to PDF. It can also be called by your Java servlets to process an HTML file and send the result to the client in PDF format:

class htmldoc
{
  // Convert named file to PDF on stdout...
  public static int topdf(String filename)// I - Name of file to convert
  {
    String              command;          // Command string
    Process             process;          // Process for HTMLDOC
    Runtime             runtime;          // Local runtime object
    java.io.InputStream input;            // Output from HTMLDOC
    byte                buffer [];        // Buffer for output data
    int                 bytes;            // Number of bytes


    // First tell the client that we will be sending PDF...
    System.out.print("Content-type: application/pdf\n\n");

    // Construct the command string
    command = "htmldoc --quiet --jpeg --webpage -t pdf --left 36 " +
              "--header .t. --footer .1. " + filename;

    // Run the process and wait for it to complete...
    runtime = Runtime.getRuntime();

    try
    {
      // Create a new HTMLDOC process...
      process = runtime.exec(command);

      // Get stdout from the process and a buffer for the data...
      input  = process.getInputStream();
      buffer = new byte[8192];

      // Read output from HTMLDOC until we have it all...
      while ((bytes = input.read(buffer)) > 0)
        System.out.write(buffer, 0, bytes);

      // Return the exit status from HTMLDOC...
      return (process.waitFor());
    }
    catch (Exception e)
    {
      // An error occurred - send it to stderr for the web server...
      System.err.print(e.toString() + " caught while running:\n\n");
      System.err.print("    " + command + "\n");
      return (1);
    }
  }

  // Main entry for htmldoc class
  public static void main(String[] args)// I - Command-line args
  {
    String server_name,                 // SERVER_NAME env var
           server_port,                 // SERVER_PORT env var
           path_info,                   // PATH_INFO env var
           query_string,                // QUERY_STRING env var
           filename;                    // File to convert


    if ((server_name = System.getProperty("SERVER_NAME")) != null &&
        (server_port = System.getProperty("SERVER_PORT")) != null &&
        (path_info = System.getProperty("PATH_INFO")) != null)
    {
      // Construct a URL for the resource specified...
      filename = "http://" + server_name + ":" + server_port + path_info;

      if ((query_string = System.getProperty("QUERY_STRING")) != null)
      {
        filename = filename + "?" + query_string;
      }
    }
    else if (args.length == 1)
    {
      // Pull the filename from the command-line...
      filename = args[0];
    }
    else
    {
      // Error - no args or env variables!
      System.err.print("Usage: htmldoc.class filename\n");
      return;
    }

    // Convert the file to PDF and send to the web client...
    topdf(filename);
  }
}
htmldoc-1.9.7/doc/3-cmdref.html000066400000000000000000001106121354715574200162330ustar00rootroot00000000000000

Chapter 3 - Command-Line Reference

This chapter describes all of the command-line options supported by HTMLDOC.

Basic Usage

The basic command-line usage for HTMLDOC is:

% htmldoc options filename1.html ... filenameN.md ENTER
% htmldoc options filename.book ENTER

The first form converts the named HTML or Markdown files to the specified output format immediately. The second form loads the specified .book file and displays the HTMLDOC window, allowing a user to make changes and/or generate the document interactively.

If no output file or directory is specified, then all output is sent to the standard output file.

On return, HTMLDOC returns an exit code of 0 if it was successful and non-zero if there were errors.

Options

The following command-line options are recognized by HTMLDOC.

-d directory

The -d option specifies an output directory for the document files.

This option is not compatible with the EPUB or PDF output formats.

-f filename

The -f option specifies an output file for the document.

-t format

The -t option specifies the output format for the document and can be one of the following:

FormatDescription
epubGenerate an EPUB file.
htmlGenerate one or more indexed HTML files.
htmlsepGenerate separate HTML files for each heading in the table-of-contents.
pdfGenerate a PDF file (default version - 1.4).
pdf11Generate a PDF 1.1 file for Acrobat Reader 2.0 and later.
pdf12Generate a PDF 1.2 file for Acrobat Reader 3.0 and later.
pdf13Generate a PDF 1.3 file for Acrobat Reader 4.0 and later.
pdf14Generate a PDF 1.4 file for Acrobat Reader 5.0 and later.
psGenerate one or more PostScript files (default level - 2).
ps1Generate one or more Level 1 PostScript files.
ps2Generate one or more Level 2 PostScript files.
ps3Generate one or more Level 3 PostScript files.

-v

The -v option specifies that progress information should be sent/displayed to the standard error file.

--batch filename.book

The --batch option specifies a book file that you would like to generate without the GUI popping up. This option can be combined with other options to generate the same book in different formats and sizes:

% htmldoc --batch filename.book -f filename.ps ENTER
% htmldoc --batch filename.book -f filename.pdf ENTER

--bodycolor color

The --bodycolor option specifies the background color for all pages in the document. The color can be specified by a standard HTML color name or as a 6-digit hexadecimal number of the form #RRGGBB.

--bodyfont typeface

The --bodyfont option specifies the default text font used for text in the document body. The typeface parameter can be one of the following:

typefaceActual Font
ArialHelvetica
CourierCourier
HelveticaHelvetica
MonospaceDejaVu Sans Mono
SansDevaVu Sans
SerifDejaVu Serif
TimesTimes

--bodyimage filename

The --bodyimage option specifies the background image for all pages in the document. The supported formats are BMP, GIF, JPEG, and PNG.

--book

The --book option specifies that the input files comprise a book with chapters and headings.

--bottom margin

The --bottom option specifies the bottom margin. The default units are points (1 point = 1/72nd inch); the suffixes "in", "cm", and "mm" specify inches, centimeters, and millimeters, respectively.

This option is only available when generating PostScript or PDF files.

--browserwidth pixels

The --browserwidth option specifies the browser width in pixels. The browser width is used to scale images and pixel measurements when generating PostScript and PDF files. It does not affect the font size of text.

The default browser width is 680 pixels which corresponds roughly to a 96 DPI display. Please note that your images and table sizes are equal to or smaller than the browser width, or your output will overlap or truncate in places.

--charset charset

The --charset option specifies the 8-bit character set encoding to use for the entire document. HTMLDOC comes with the following character set files:

charsetCharacter Set
cp-874Windows code page 874
cp-1250Windows code page 1250
cp-1251Windows code page 1251
cp-1252Windows code page 1252
cp-1253Windows code page 1253
cp-1254Windows code page 1254
cp-1255Windows code page 1255
cp-1256Windows code page 1256
cp-1257Windows code page 1257
cp-1258Windows code page 1258
iso-8859-1ISO-8859-1
iso-8859-2ISO-8859-2
iso-8859-3ISO-8859-3
iso-8859-4ISO-8859-4
iso-8859-5ISO-8859-5
iso-8859-6ISO-8859-6
iso-8859-7ISO-8859-7
iso-8859-8ISO-8859-8
iso-8859-9ISO-8859-9
iso-8859-14ISO-8859-14
iso-8859-15ISO-8859-15
koi8-rKOI8-R
utf-8UTF-8
Note: UTF-8 support is limited to the first 128 Unicode characters found in the input.

--color

The --color option specifies that color output is desired.

This option is only available when generating PostScript or PDF files.

--compression[=level]

The --compression option specifies that Flate compression should be performed on the output file(s). The optional level parameter is a number from 1 (fastest and least amount of compression) to 9 (slowest and most amount of compression).

This option is only available when generating PDF or Level 3 PostScript files.

--continuous

The --continuous option specifies that the input files comprise a web page (or site) and that no title page or table-of-contents should be generated. Unlike the --webpage option described later in this chapter, page breaks are not inserted between each input file.

This option is only available when generating PostScript or PDF files.

--cookies 'name=\"value with space\"; name=value'

The --cookies option specifies one or more HTTP cookies that should be sent when converting remote URLs. Each cookie must be separated from the others by a semicolon and a space, and values containing whitespace or the semicolon must be placed inside double-quotes. When specifying multiple cookies, the entire cookie string must be surrounded by single quotes in order for the string to be processed correctly.

--datadir directory

The --datadir option specifies the location of data files used by HTMLDOC.

--duplex

The --duplex option specifies that the output should be formatted for two sided printing.

This option is only available when generating PostScript or PDF files. Use the --pscommands option to generate PostScript duplex mode commands.

--effectduration seconds

The --effectduration option specifies the duration of a page transition effect in seconds.

This option is only available when generating PDF files.

--embedfonts

The --embedfonts option specifies that fonts should be embedded in PostScript and PDF output. This is especially useful when generating documents in character sets other than ISO-8859-1.

--encryption

The --encryption option enables encryption and security features for PDF output.

This option is only available when generating PDF files.

--firstpage page

The --firstpage option specifies the first page that will be displayed in a PDF file. The page parameter can be one of the following:

pageDescription
p1The first page of the document.
tocThe first page of the table-of-contents.
c1The first page of chapter 1.

This option is only available when generating PDF files.

--fontsize size

The --fontsize option specifies the base font size for the entire document in points (1 point = 1/72nd inch).

--fontspacing spacing

The --fontspacing option specifies the line spacing for the entire document as a multiplier of the base font size. A spacing value of 1 makes each line of text the same height as the font.

--footer lcr

The --footer option specifies the contents of the page footer. The lcr parameter is a three-character string representing the left, center, and right footer fields. Each character can be one of the following:

lcrDescription
.A period indicates that the field should be blank.
:A colon indicates that the field should contain the current and total number of pages in the chapter (n/N).
/A slash indicates that the field should contain the current and total number of pages (n/N).
1The number 1 indicates that the field should contain the current page number in decimal format (1, 2, 3, ...)
aA lowercase "a" indicates that the field should contain the current page number using lowercase letters.
AAn uppercase "A" indicates that the field should contain the current page number using UPPERCASE letters.
cA lowercase "c" indicates that the field should contain the current chapter title.
CAn uppercase "C" indicates that the field should contain the current chapter page number.
dA lowercase "d" indicates that the field should contain the current date.
DAn uppercase "D" indicates that the field should contain the current date and time.
hAn "h" indicates that the field should contain the current heading.
iA lowercase "i" indicates that the field should contain the current page number in lowercase roman numerals (i, ii, iii, ...)
IAn uppercase "I" indicates that the field should contain the current page number in uppercase roman numerals (I, II, III, ...)
lA lowercase "l" indicates that the field should contain the logo image.
tA lowercase "t" indicates that the field should contain the document title.
TAn uppercase "T" indicates that the field should contain the current time.
uA lowercase "u" indicates that the field should contain the current filename or URL.

Setting the footer to "..." disables the footer entirely.

--format format

The --format option specifies the output format for the document and can be one of the following:

FormatDescription
epubGenerate an EPUB file.
htmlGenerate one or more indexed HTML files.
htmlsepGenerate separate HTML files for each heading in the table-of-contents.
pdfGenerate a PDF file (default version - 1.4).
pdf11Generate a PDF 1.1 file for Acrobat Reader 2.0 and later.
pdf12Generate a PDF 1.2 file for Acrobat Reader 3.0 and later.
pdf13Generate a PDF 1.3 file for Acrobat Reader 4.0 and later.
pdf14Generate a PDF 1.4 file for Acrobat Reader 5.0 and later.
psGenerate one or more PostScript files (default level - 2).
ps1Generate one or more Level 1 PostScript files.
ps2Generate one or more Level 2 PostScript files.
ps3Generate one or more Level 3 PostScript files.

--gray

The --gray option specifies that grayscale output is desired.

This option is only available when generating PostScript or PDF files.

--header lcr

The --header option specifies the contents of the page header. The lcr parameter is a three-character string representing the left, center, and right header fields. See the --footer option for the list of formatting characters.

Setting the header to "..." disables the header entirely.

--header1 lcr

The --header1 option specifies the contents of the page header for the first body/chapter page. The lcr parameter is a three-character string representing the left, center, and right header fields. See the --footer option for the list of formatting characters.

Setting the header to "..." disables the first page header entirely.

--headfootfont font

The --headfootfont option specifies the font that is used for the header and footer text. The font parameter can be one of the following:

  • Courier
  • Courier-Bold
  • Courier-Oblique
  • Courier-BoldOblique
  • Helvetica
  • Helvetica-Bold
  • Helvetica-Oblique
  • Helvetica-BoldOblique
  • Monospace
  • Monospace-Bold
  • Monospace-Oblique
  • Monospace-BoldOblique
  • Sans
  • Sans-Bold
  • Sans-Oblique
  • Sans-BoldOblique
  • Serif
  • Serif-Roman
  • Serif-Bold
  • Serif-Italic
  • Serif-BoldItalic
  • Times
  • Times-Roman
  • Times-Bold
  • Times-Italic
  • Times-BoldItalic

This option is only available when generating PostScript or PDF files.

--headfootsize size

The --headfootsize option sets the size of the header and footer text in points (1 point = 1/72nd inch).

This option is only available when generating PostScript or PDF files.

--headingfont typeface

The --headingfont options sets the typeface that is used for headings in the document. The typeface parameter can be one of the following:

typefaceActual Font
ArialHelvetica
CourierCourier
HelveticaHelvetica
MonospaceDejaVu Sans Mono
SansDevaVu Sans
SerifDejaVu Serif
TimesTimes

--help

The --help option displays all of the available options to the standard output file.

--helpdir directory

The --helpdir option specifies the location of the on-line help files.

--hfimageN filename

The --hfimageN option specifies an image to use in the header and/or footer, where N is a number from 1 to 10. The supported formats are BMP, GIF, JPEG, and PNG.

--jpeg[=quality]

The --jpeg option enables JPEG compression of continuous-tone images. The optional quality parameter specifies the output quality from 0 (worst) to 100 (best).

This option is only available when generating PDF or Level 2 and Level 3 PostScript files.

--landscape

The --landscape option specifies that the output should be in landscape orientation (long edge on top).

This option is only available when generating PostScript or PDF files.

--left margin

The --left option specifies the left margin. The default units are points (1 point = 1/72nd inch); the suffixes "in", "cm", and "mm" specify inches, centimeters, and millimeters, respectively.

This option is only available when generating PostScript or PDF files.

--linkcolor color

The --linkcolor option specifies the color of links in EPUB, HTML. and PDF output. The color can be specified by name or as a 6-digit hexadecimal number of the form #RRGGBB.

--links

The --links option specifies that PDF output should contain hyperlinks.

--linkstyle style

The --linkstyle option specifies the style of links in EPUB, HTML, and PDF output. The style can be "plain" for no decoration or "underline" to underline links.

--logoimage filename

The --logoimage option specifies the logo image for the HTML navigation bar and page headers and footers for PostScript and PDF files. The supported formats are BMP, GIF, JPEG, and PNG.

Note: You need to use the --header and/or --footer options with the l parameter or use the corresponding HTML page comments to display the logo image in the header or footer.

--no-compression

The --no-compression option specifies that Flate compression should not be performed on the output files.

--no-duplex

The --no-duplex option specifies that the output should be formatted for one sided printing.

This option is only available when generating PostScript or PDF files. Use the --pscommands option to generate PostScript duplex mode commands.

--no-embedfonts

The --no-embedfonts option specifies that fonts should not be embedded in PostScript and PDF output.

--no-encryption

The --no-encryption option specifies that no encryption/security features should be enabled in PDF output.

This option is only available when generating PDF files.

--no-jpeg

The --no-jpeg option specifies that JPEG compression should not be performed on large images.

--no-links

The --no-links option specifies that PDF output should not contain hyperlinks.

--no-localfiles

The --no-localfiles option disables access to local files on the system. This option should be used when providing remote document conversion services.

--no-numbered

The --no-numbered option specifies that headings should not be numbered.

--no-pscommands

The --no-pscommands option specifies that PostScript device commands should not be written to the output files.

--no-strict

The --no-strict option turns off strict HTML conformance checking.

--no-title

The --no-title option specifies that the title page should not be generated.

--no-toc

The --no-toc option specifies that the table-of-contents pages should not be generated.

--no-xrxcomments

The --no-xrxcomments option specifies that Xerox PostScript job comments should not be written to the output files.

This option is only available when generating PostScript files.

--numbered

The --numbered option specifies that headings should be numbered.

--nup pages

The --nup option sets the number of pages that are placed on each output page. Valid values for the pages parameter are 1, 2, 4, 6, 9, and 16.

--outdir directory

The --outdir option specifies an output directory for the document files.

This option is not compatible with the PDF output format.

--outfile filename

The --outfile option specifies an output file for the document.

--owner-password password

The --owner-password option specifies the owner password for a PDF file. If not specified or the empty string (""), a random password is generated.

This option is only available when generating PDF files.

--pageduration seconds

The --pageduration option specifies the number of seconds that each page will be displayed in the document.

This option is only available when generating PDF files.

--pageeffect effect

The --pageeffect option specifies the page effect to use in PDF files. The effect parameter can be one of the following:

effectDescription
noneNo effect is generated.
biBox Inward
boBox Outward
dDissolve
gdGlitter Down
gdrGlitter Down and Right
grGlitter Right
hbHorizontal Blinds
hsiHorizontal Sweet Inward
hsoHorizontal Sweep Outward
vbVertical Blinds
vsiVertical Sweep Inward
vsoVertical Sweep Outward
wdWipe Down
wlWipe Left
wrWipe Right
wuWipe Up

This option is only available when generating PDF files.

--pagelayout layout

The --pagelayout option specifies the initial page layout in the PDF viewer. The layout parameter can be one of the following:

layoutDescription
singleA single page is displayed.
oneA single column is displayed.
twoleftTwo columns are displayed with the first page on the left.
tworightTwo columns are displayed with the first page on the right.

This option is only available when generating PDF files.

--pagemode mode

The --pagemode option specifies the initial viewing mode in the PDF viewer. The mode parameter can be one of the following:

modeDescription
documentThe document pages are displayed in a normal window.
outlineThe document outline and pages are displayed.
fullscreenThe document pages are displayed on the entire screen in "slideshow" mode.

This option is only available when generating PDF files.

--path dir1;dir2;dir3;...;dirN

The --path option specifies a search path for files that are loaded by HTMLDOC. It is usually used to get images that use absolute server paths to load.

Directories are separated by the semicolon (;) so that drive letters and URLs can be specified. Quotes around the directory parameter are optional. They are usually used when the directory string contains spaces.

--path "dir1;dir2;dir3;...;dirN"

--permissions permission[,permission,...]

The --permissions option specifies the document permissions. The available permission parameters are listed below:

PermissionDescription
allAll permissions
annotateUser can annotate document
copyUser can copy text and images from document
modifyUser can modify document
printUser can print document
no-annotateUser cannot annotate document
no-copyUser cannot copy text and images from document
no-modifyUser cannot modify document
no-printUser cannot print document
noneNo permissions

The --encryption option must be used in conjunction with the --permissions parameter.

--permissions no-print --encryption

Multiple options can be specified by separating them with commas:

--permissions no-print,no-copy --encryption

This option is only available when generating PDF files.

--portrait

The --portrait option specifies that the output should be in portrait orientation (short edge on top).

This option is only available when generating PostScript or PDF files.

--pscommands

The --pscommands option specifies that PostScript device commands should be written to the output files.

This option is only available when generating Level 2 and Level 3 PostScript files.

--quiet

The --quiet option prevents error messages from being sent to stderr.

--referer url

The --referer option sets the URL that is passed in the Referer: field of HTTP requests.

--right margin

The --right option specifies the right margin. The default units are points (1 point = 1/72nd inch); the suffixes "in", "cm", and "mm" specify inches, centimeters, and millimeters, respectively.

This option is only available when generating PostScript or PDF files.

--size size

The --size option specifies the page size. The size parameter can be one of the following standard sizes:

sizeDescription
Letter8.5x11in (216x279mm)
A48.27x11.69in (210x297mm)
Universal8.27x11in (210x279mm)

Custom sizes are specified by the page width and length separated by the letter "x" to select a custom page size. Append the letters "in" for inches, "mm" for millimeters, or "cm" for centimeters.

This option is only available when generating PostScript or PDF files. Use the --pscommands option to generate PostScript page size commands.

--strict

The --strict option turns on strict HTML conformance checking. When enabled, HTML elements that are improperly nested and dangling close elements will produce error messages.

--textcolor color

The --textcolor option specifies the default text color for all pages in the document. The color can be specified by a standard HTML color name or as a 6-digit hexadecimal number of the form #RRGGBB.

--textfont typeface

The --textfont options sets the typeface that is used for text in the document. The typeface parameter can be one of the following:

typefaceActual Font
ArialHelvetica
CourierCourier
HelveticaHelvetica
MonospaceDejaVu Sans Mono
SansDevaVu Sans
SerifDejaVu Serif
TimesTimes

--title

The --title option specifies that a title page should be generated.

--titlefile filename

The --titlefile option specifies a HTML or Markdown file to use for the title page.

--titleimage filename

The --titleimage option specifies the title image for the title page. The supported formats are BMP, GIF, JPEG, and PNG.

--tocfooter lcr

The --tocfooter option specifies the contents of the table-of-contents footer. The lcr parameter is a three-character string representing the left, center, and right footer fields. See the --footer option for the list of formatting characters.

Setting the TOC footer to "..." disables the TOC footer entirely.

--tocheader lcr

The --tocheader option specifies the contents of the table-of-contents header. The lcr parameter is a three-character string representing the left, center, and right header fields. See the --footer option for the list of formatting characters.

Setting the TOC header to "..." disables the TOC header entirely.

--toclevels levels

The --toclevels options specifies the number of heading levels to include in the table-of-contents pages. The levels parameter is a number from 1 to 6.

--toctitle string

The --toctitle options specifies the string to display at the top of the table-of-contents; the default string is "Table of Contents".

--top margin

The --top option specifies the top margin. The default units are points (1 point = 1/72nd inch); the suffixes "in", "cm", and "mm" specify inches, centimeters, and millimeters, respectively.

This option is only available when generating PostScript or PDF files.

--user-password password

The --user-password option specifies the user password for a PDF file. If not specified or the empty string (""), no password will be required to view the document.

This option is only available when generating PDF files.

--verbose

The --verbose option specifies that progress information should be sent/displayed to the standard error file.

--version

The --version option displays the HTMLDOC version number.

--webpage

The --webpage option specifies that the input files comprise a web page (or site) and that no title page or table-of-contents should be generated. HTMLDOC will insert a page break between each input file.

This option is only available when generating PostScript or PDF files.

--xrxcomments

The --xrxcomments option specifies that Xerox PostScript job comments should be written to the output files.

This option is only available when generating PostScript files.

Environment Variables

HTMLDOC looks for several environment variables which can override the default directories, display additional debugging information, and disable CGI mode.

HTMLDOC_DATA

This environment variable specifies the location of HTMLDOC's data and fonts directories, normally /usr/share/htmldoc or C:\Program Files\HTMLDOC.

HTMLDOC_DEBUG

This environment variable enables debugging information that is sent to stderr. The value is a list of keywords separated by spaces:

keywordInformation Shown
linksShows all of the links in a document
memoryShows memory usage statistics
remotebytesShows the number of bytes that were transferred via HTTP
tablePuts a box around each table, row, and cell
tempfilesShows the temporary files that were created, and preserves them for debugging
timingShows the load and render times
allAll of the above

HTMLDOC_HELP

This environment variable specifies the location of HTMLDOC's documentation directory, normally /usr/share/doc/htmldoc or C:\Program Files\HTMLDOC\doc.

HTMLDOC_NOCGI

This environment variable, when set (the value doesn't matter), disables CGI mode. It is most useful for using HTMLDOC on a web server from a scripting language or invocation from a program.

Messages

HTMLDOC sends error and status messages to stderr unless the --quiet option is provided on the command-line. Applications can capture these messages to relay errors or statistics to the user.

BYTES: Message

The BYTES: message specifies the number of bytes that were written to an output file. If the output is directed at a directory then multiple BYTES: messages will be sent.

DEBUG: Messages

The DEBUG: messages contain debugging information based on the value of the HTMLDOC_DEBUG environment variable. Normally, no DEBUG: messages are sent by HTMLDOC.

ERRnnn: Messages

The ERRnnn: messages specify an error condition. Error numbers 1 to 14 map to the following errors:

  1. No files were found or loadable.
  2. No pages were generated.
  3. The document contains too many files or chapters.
  4. HTMLDOC ran out of memory.
  5. The specified file could not be found.
  6. The comment contains a bad HTMLDOC formatting command.
  7. The image file is not in a known format.
  8. HTMLDOC was unable to remove a temporary file.
  9. HTMLDOC had an unspecified internal error.
  10. HTMLDOC encountered a networking error when retrieving a file via a URL.
  11. HTMLDOC was unable to read a file.
  12. HTMLDOC was unable to write a file.
  13. A HTML error was found in a source file.
  14. A table, image, or text fragment was too large to fit in the space provided.
  15. A hyperlink in the source files was unresolved.
  16. A header/footer string in the document contains a bad $ command.

Error numbers 100 to 505 correspond directly to a HTTP status code.

INFO: Messages

The INFO: messages contain general information that is logged when HTMLDOC is running in CGI mode or when you use the --verbose option.

PAGES: Message

The PAGES: message specifies the number of pages that were written to an output file. If the output is directed at a directory then multiple PAGES: messages will be sent. No PAGES: messages are sent when generating HTML or EPUB output.

REMOTEBYTES: Message

The REMOTEBYTES: message specifies the number of bytes that were transferred using HTTP. This message is only displayed if the HTMLDOC_DEBUG environment variable has the keyword remotebytes or all.

TIMING: Message

The TIMING: message specifies the load, render, and total time in seconds for the current command. This message is only displayed if the HTMLDOC_DEBUG environment variable has the keyword timing or all.

htmldoc-1.9.7/doc/4-htmlref.html000066400000000000000000000525661354715574200164520ustar00rootroot00000000000000

Chapter 4 - HTML Reference

This chapter defines all of the HTML elements and attributes that are recognized and supported by HTMLDOC.

General Usage

There are two types of HTML files - structured documents using headings (H1, H2, etc.) which HTMLDOC calls "books", and unstructured documents that do not use headings which HTMLDOC calls "web pages".

A very common mistake is to try converting a web page using:

htmldoc -f filename.pdf filename.html

which will likely produce a PDF file with no pages. To convert web page files you must use the --webpage option at the command-line or choose Web Page in the input tab of the GUI.

Note: HTMLDOC does not support HTML 4.0 elements, attributes, stylesheets, or scripting.

Elements

The following HTML elements are recognized by HTMLDOC:

ElementVersionSupported?Notes
!DOCTYPE3.0YesDTD is ignored
A1.0YesSee Below
ACRONYM2.0YesNo font change
ADDRESS2.0Yes 
AREA2.0No 
B1.0Yes 
BASE2.0No 
BASEFONT1.0No 
BIG2.0Yes 
BLINK2.0No 
BLOCKQUOTE2.0Yes 
BODY1.0Yes 
BR2.0Yes 
CAPTION2.0Yes 
CENTER2.0Yes 
CITE2.0YesItalic/Oblique
CODE2.0YesCourier
DD2.0Yes 
DEL2.0YesStrikethrough
DFN2.0YesHelvetica
DIR2.0Yes 
DIV3.2Yes 
DL2.0Yes 
DT2.0YesItalic/Oblique
EM2.0YesItalic/Oblique
EMBED2.0YesHTML Only
FONT2.0YesSee Below
FORM2.0No 
FRAME3.2No 
FRAMESET3.2No 
H11.0YesBoldface, See Below
H21.0YesBoldface, See Below
H31.0YesBoldface, See Below
H41.0YesBoldface, See Below
H51.0YesBoldface, See Below
H61.0YesBoldface, See Below
HEAD1.0Yes 
HR1.0Yes 
HTML1.0Yes 
I1.0Yes 
IMG1.0YesSee Below
INPUT2.0No 
INS2.0YesUnderline
ISINDEX2.0No 
KBD2.0YesCourier Bold
LI2.0Yes 
LINK2.0No 
MAP2.0No 
MENU2.0Yes 
META2.0YesSee Below
MULTICOLN3.0No 
NOBR1.0No 
NOFRAMES3.2No 
OL2.0Yes 
OPTION2.0No 
P1.0Yes 
PRE1.0Yes 
S2.0YesStrikethrough
SAMP2.0YesCourier
SCRIPT2.0No 
SELECT2.0No 
SMALL2.0Yes 
SPACERN3.0Yes 
STRIKE2.0Yes 
STRONG2.0YesBoldface Italic/Oblique
SUB2.0YesReduced Fontsize
SUP2.0YesReduced Fontsize
TABLE2.0YesSee Below
TD2.0Yes 
TEXTAREA2.0No 
TH2.0YesBoldface Center
TITLE2.0Yes 
TR2.0Yes 
TT2.0YesCourier
U1.0Yes 
UL2.0Yes 
VAR2.0YesHelvetica Oblique
WBR1.0No 

Comments

HTMLDOC supports many special HTML comments to initiate page breaks, set the header and footer text, and control the current media options:

<!-- FOOTER LEFT "foo" -->
Sets the left footer text; the test is applied to the current page if empty, or the next page otherwise.
<!-- FOOTER CENTER "foo" -->
Sets the center footer text; the test is applied to the current page if empty, or the next page otherwise.
<!-- FOOTER RIGHT "foo" -->
Sets the right footer text; the test is applied to the current page if empty, or the next page otherwise.
<!-- HALF PAGE -->
Break to the next half page.
<!-- HEADER LEFT "foo" -->
Sets the left header text; the test is applied to the current page if empty, or the next page otherwise.
<!-- HEADER CENTER "foo" -->
Sets the center header text; the test is applied to the current page if empty, or the next page otherwise.
<!-- HEADER RIGHT "foo" -->
Sets the right header text; the test is applied to the current page if empty, or the next page otherwise.
<!-- MEDIA BOTTOM nnn -->
Sets the bottom margin of the page. The "nnn" string can be any standard measurement value, e.g. 0.5in, 36, 12mm, etc. Breaks to a new page if the current page is already marked.
<!-- MEDIA COLOR "foo" -->
Sets the media color attribute for the page. The "foo" string is any color name that is supported by the printer, e.g. "Blue", "White", etc. Breaks to a new page or sheet if the current page is already marked.
<!-- MEDIA DUPLEX NO -->
Chooses single-sided printing for the page; breaks to a new page or sheet if the current page is already marked.
<!-- MEDIA DUPLEX YES -->
Chooses double-sided printing for the page; breaks to a new sheet if the current page is already marked.
<!-- MEDIA LANDSCAPE NO -->
Chooses portrait orientation for the page; breaks to a new page if the current page is already marked.
<!-- MEDIA LANDSCAPE YES -->
Chooses landscape orientation for the page; breaks to a new page if the current page is already marked.
<!-- MEDIA LEFT nnn -->
Sets the left margin of the page. The "nnn" string can be any standard measurement value, e.g. 0.5in, 36, 12mm, etc. Breaks to a new page if the current page is already marked.
<!-- MEDIA POSITION nnn -->
Sets the media position attribute (input tray) for the page. The "nnn" string is an integer that usually specifies the tray number. Breaks to a new page or sheet if the current page is already marked.
<!-- MEDIA RIGHT nnn -->
Sets the right margin of the page. The "nnn" string can be any standard measurement value, e.g. 0.5in, 36, 12mm, etc. Breaks to a new page if the current page is already marked.
<!-- MEDIA SIZE foo -->
Sets the media size to the specified size. The "foo" string can be "Letter", "Legal", "Universal", or "A4" for standard sizes or "WIDTHxHEIGHTunits" for custom sizes, e.g. "8.5x11in"; breaks to a new page or sheet if the current page is already marked.
<!-- MEDIA TOP nnn -->
Sets the top margin of the page. The "nnn" string can be any standard measurement value, e.g. 0.5in, 36, 12mm, etc. Breaks to a new page if the current page is already marked.
<!-- MEDIA TYPE "foo" -->
Sets the media type attribute for the page. The "foo" string is any type name that is supported by the printer, e.g. "Plain", "Glossy", etc. Breaks to a new page or sheet if the current page is already marked.
<!-- NEED length -->
Break if there is less than length units left on the current page. The length value defaults to lines of text but can be suffixed by in, mm, or cm to convert from the corresponding units.
<!-- NEW PAGE -->
Break to the next page.
<!-- NEW SHEET -->
Break to the next sheet.
<!-- NUMBER-UP nn -->
Sets the number of pages that are placed on each output page. Valid values are 1, 2, 4, 6, 9, and 16.
<!-- PAGE BREAK -->
Break to the next page.

Header/Footer Strings

The HEADER and FOOTER comments allow you to set an arbitrary string of text for the left, center, and right headers and footers. Each string consists of plain text; special values or strings can be inserted using the dollar sign ($):

$$
Inserts a single dollar sign in the header.
$CHAPTER
Inserts the current chapter heading.
$CHAPTERPAGE
$CHAPTERPAGE(format)
Inserts the current page number within a chapter or file. When a format is specified, uses that numeric format (1 = decimal, i = lowercase roman numerals, I = uppercase roman numerals, a = lowercase ascii, A = uppercase ascii) for the page numbers.
$CHAPTERPAGES
$CHAPTERPAGES(format)
Inserts the total page count within a chapter or file. When a format is specified, uses that numeric format (1 = decimal, i = lowercase roman numerals, I = uppercase roman numerals, a = lowercase ascii, A = uppercase ascii) for the page count.
$DATE
Inserts the current date.
$HEADING
Inserts the current heading.
$HFIMAGE1
$HFIMAGE2
$HFIMAGE3
$HFIMAGE4
$HFIMAGE5
$HFIMAGE6
$HFIMAGE7
$HFIMAGE8
$HFIMAGE9
$HFIMAGE10
Inserts the specified header/footer image; all other text in the string will be ignored.
$LOGOIMAGE
Inserts the logo image; all other text in the string will be ignored.
$PAGE
$PAGE(format)
Inserts the current page number. When a format is specified, uses that numeric format (1 = decimal, i = lowercase roman numerals, I = uppercase roman numerals, a = lowercase ascii, A = uppercase ascii) for the page numbers.
$PAGES
$PAGES(format)
Inserts the total page count. When a format is specified, uses that numeric format (1 = decimal, i = lowercase roman numerals, I = uppercase roman numerals, a = lowercase ascii, A = uppercase ascii) for the page count.
$TIME
Inserts the current time.
$TITLE
Inserts the document title.
$URL
Inserts the document filename or URL.

FONT Attributes

Limited typeface specification is currently supported to ensure portability across platforms and for older PostScript printers:

Requested FontActual Font
ArialHelvetica
CourierCourier
DingbatsDingbats
HelveticaHelvetica
MonospaceDejaVu Sans Mono
SansDejaVu Sans
SerifDejaVu Serif
SymbolSymbol
TimesTimes

All other unrecognized typefaces are silently ignored.

Headings

Currently HTMLDOC supports a maximum of 1000 chapters (H1 headings). This limit can be increased by changing the MAX_CHAPTERS constant in the config.h file included with the source code.

All chapters start with a top-level heading (H1) markup. Any headings within a chapter must be of a lower level (H2 to H15). Each chapter starts a new page or the next odd-numbered page if duplexing is selected.

Note: Heading levels 7 to 15 are not standard HTML and will not likely be recognized by most web browsers.

The headings you use within a chapter must start at level 2 (H2). If you skip levels the heading will be shown under the last level that was known. For example, if you use the following hierarchy of headings:

<H1>Chapter Heading</H1>
...
<H2>Section Heading 1</H2>
...
<H2>Section Heading 2</H2>
...
<H3>Sub-Section Heading 1</H3>
...
<H4>Sub-Sub-Section Heading 1</H4>
...
<H4>Sub-Sub-Section Heading 2</H4>
...
<H3>Sub-Section Heading 2</H3>
...
<H2>Section Heading 3</H2>
...
<H4>Sub-Sub-Section Heading 3</H4>
...
the table-of-contents that is generated will show:
  • Chapter Heading
    • Section Heading 1
    • Section Heading 2
      • Sub-Section Heading 1
        • Sub-Sub-Section Heading 1
        • Sub-Sub-Section Heading 2
      • Sub-Section Heading 2
        • Sub-Sub-Section Heading 3
    • Section Heading 3

Numbered Headings

When the numbered headings option is enabled, HTMLDOC recognizes the following additional attributes for all heading elements:
VALUE="#"
Specifies the starting value for this heading level (default is "1" for all new levels).
TYPE="1"
Specifies that decimal numbers should be generated for this heading level.
TYPE="a"
Specifies that lowercase letters should be generated for this heading level.
TYPE="A"
Specifies that uppercase letters should be generated for this heading level.
TYPE="i"
Specifies that lowercase roman numerals should be generated for this heading level.
TYPE="I"
Specifies that uppercase roman numerals should be generated for this heading level.

Images

HTMLDOC supports loading of BMP, GIF, JPEG, and PNG image files. EPS and other types of image files are not supported at this time.

Links

External URL and internal (#target and filename.html) links are fully supported for HTML and PDF output.

When generating PDF files, local PDF file links will be converted to external file links for the PDF viewer instead of URL links. That is, you can directly link to another local PDF file from your HTML document with:

<A HREF="filename.pdf">...</A>

META Attributes

HTMLDOC supports the following META attributes for the title page and document information:

<META NAME="AUTHOR" CONTENT="..."
Specifies the document author.
<META NAME="COPYRIGHT" CONTENT="..."
Specifies the document copyright.
<META NAME="DOCNUMBER" CONTENT="..."
Specifies the document number.
<META NAME="GENERATOR" CONTENT="..."
Specifies the application that generated the HTML file.
<META NAME="KEYWORDS" CONTENT="..."
Specifies document search keywords.
<META NAME="SUBJECT" CONTENT="..."
Specifies document subject.

Tables

Currently HTMLDOC supports a maximum of 200 columns within a single table. This limit can be increased by changing the MAX_COLUMNS constant in the config.h file included with the source code.

HTMLDOC does not support HTML 4.0 table elements or attributes, such as TBODY, THEAD, TFOOT, or RULES.

htmldoc-1.9.7/doc/5-mdref.html000066400000000000000000000133771354715574200161040ustar00rootroot00000000000000

Chapter 5 - Markdown Reference

This chapter describes the markdown syntax that is recognized and supported by HTMLDOC.

General Syntax

Markdown is a simple plain-text format that uses formatting conventions that are commonly used in email and other text-based communications. Markdown is used by most of the major blogging, web site, and project hosting platforms and is supported by many standalone text editors.

HTMLDOC supports the CommonMark version of markdown syntax with the following exceptions:

  • Metadata as used by Jekyll and other web markdown solutions can be placed at the beginning of the file;
  • "@" links can be used which resolve to headings within the file;
  • Tables can be embedded using the "|" separator;
  • Embedded HTML markup and entities are explicitly not supported or allowed;
  • Tabs are silently expanded to the markdown standard of four spaces since HTML uses eight spaces per tab; and
  • Some pathological nested link and inline style features supported by CommonMark (******Really Strong Text******) are not supported by mmd.
Note: HTMLDOC does not support embedded HTML in markdown documents because the version of HTML (or XHTML) cannot be reliably determined, making support of certain character entities and language elements problematic.

Metadata Syntax

Metadata is specified at the top of a markdown file between two lines containing three hyphens, for example:

---
title: My Great Novel
author: John Doe
copyright: Copyright © 2018 by John Doe
version: 1.0
language: en-US
subject: Fiction
---

# Preamble

...

HTMLDOC supports the "author", "copyright", "language", "subject", "title", and "version" metadata and silently ignores everything else.

Link Targets and @ Links

CommonMark defines no standard for how implementations generate anchors or identifiers for headings in a markdown file - this makes hyperlinking to a named section within a document basically impossible. Jekyll and other markdown implementations allow the special link "@" to be used, which HTMLDOC supports:

See [Screwing in a Light Bulb](@) for instructions on installing a
light bulb.

...

# Screwing in a Light Bulb

...

To reference a markdown heading from a HTML file, convert the heading to lowercase, replace spaces with the hyphen ("-"), and remove any special characters. Thus, a HTML file would reference the previous heading using the following HTML:

<a href="#screwing-in-a-light-bulb"> ... </a>

Table Syntax

CommonMark does not define a syntax for plain-text tables, instead relying on embedded HTML which HTMLDOC does not support. Both Github and Jekyll support a common markdown extension for plain text tables that uses the vertical pipe ("|") character to specify column separations. The first line contains the table header, the second line is a horizontal separator, and the remaining lines contain the table body. For example:

| Heading 1 | Heading 2 | Heading 3 |
| --------- | --------- | --------- |
| Cell 1,1  | Cell 1,2  | Cell 1,3  |
| Cell 2,1  | Cell 2,2  | Cell 2,3  |
| Cell 3,1  | Cell 3,2  | Cell 3,3  |

will produce:

Heading 1Heading 2Heading 3
Cell 1,1Cell 1,2Cell 1,3
Cell 2,1Cell 2,2Cell 2,3
Cell 3,1Cell 3,2Cell 3,3

The outer pipes can be omitted, for example:

Heading 1 | Heading 2 | Heading 3
--------- | --------- | ---------
Cell 1,1  | Cell 1,2  | Cell 1,3
Cell 2,1  | Cell 2,2  | Cell 2,3
Cell 3,1  | Cell 3,2  | Cell 3,3

While table headings are always centered, you can control the alignment of the body cells by using the colon (":") character in the separator line. Put a leading colon to specify left alignment (the default), a trailing colon for right alignment, or both to specify centering. For example:

Left Alignment | Center Alignment | Right Alignment
:------------- | :--------------: | --------------:
Cell 1,1       |     Cell 1,2     |               1
Cell 2,1       |     Cell 2,2     |              12
Cell 3,1       |     Cell 3,2     |             123

will produce:

Left AlignmentCenter AlignmentRight Alignment
Cell 1,1Cell 1,21
Cell 2,1Cell 2,212
Cell 3,1Cell 3,2123

Table columns do not need to be padded so that they line up - the following (less readable) example is perfectly valid:

Left Alignment|Center Alignment|Right Alignment
:--|:--:|--:
Cell 1,1|Cell 1,2|1
Cell 2,1|Cell 2,2|12
Cell 3,1|Cell 3,2|123
htmldoc-1.9.7/doc/Makefile000066400000000000000000000041121354715574200154020ustar00rootroot00000000000000# # Makefile for HTMLDOC documentation files. # # Copyright © 2011-2018 by Michael R Sweet. # Copyright © 1997-2010 by Easy Software Products. # # This program is free software. Distribution and use rights are outlined in # the file "COPYING". # # # Include common definitions... # include ../Makedefs # # Documentation files... # SOURCES = 1-intro.html \ 2-using.html \ 3-cmdref.html \ 4-htmlref.html \ 5-mdref.html \ a-license.html \ b-book.html DOCUMENTS = htmldoc.epub htmldoc.html htmldoc.pdf htmldoc.ps DOCFILES = help.html htmldoc.pdf HTMLDOC = ../htmldoc/htmldoc$(EXEEXT) --datadir .. --strict # # Make everything... # all: $(DOCUMENTS) # # Install everything... # install: $(DOCUMENTS) $(INSTALL_DIR) $(BUILDROOT)$(datadir)/doc/htmldoc; for file in $(DOCFILES); do \ $(INSTALL_DATA) $$file $(BUILDROOT)$(datadir)/doc/htmldoc; \ done $(INSTALL_DIR) $(BUILDROOT)$(mandir)/man1; $(INSTALL_MAN) htmldoc.man $(BUILDROOT)$(mandir)/man1/htmldoc.1 # # Clean out document files... # clean: $(RM) $(DOCUMENTS) # # htmldoc program (dummy rule) # ../htmldoc/htmldoc$(EXEEXT): echo Rebuilding documentation... # # htmldoc.d (directory) # .PHONY: htmldoc.d htmldoc.d: $(SOURCES) ../htmldoc/htmldoc$(EXEEXT) echo Formatting htmldoc.d... if test -d htmldoc.d; then \ $(RM) -r htmldoc.d; \ fi $(MKDIR) htmldoc.d $(VALGRIND) $(HTMLDOC) --batch htmldoc.book -t htmlsep -d htmldoc.d # # htmldoc.epub # htmldoc.epub: $(SOURCES) ../htmldoc/htmldoc$(EXEEXT) echo Formatting htmldoc.epub... $(VALGRIND) $(HTMLDOC) --batch htmldoc.book --titleimage htmldoc-cover.png -f htmldoc.epub # # htmldoc.html # htmldoc.html: $(SOURCES) ../htmldoc/htmldoc$(EXEEXT) echo Formatting htmldoc.html... $(VALGRIND) $(HTMLDOC) --batch htmldoc.book -f htmldoc.html # # htmldoc.pdf # htmldoc.pdf: $(SOURCES) ../htmldoc/htmldoc$(EXEEXT) echo Formatting htmldoc.pdf... $(VALGRIND) $(HTMLDOC) --batch htmldoc.book -f htmldoc.pdf # # htmldoc.ps # htmldoc.ps: $(SOURCES) ../htmldoc/htmldoc$(EXEEXT) echo Formatting htmldoc.ps... $(VALGRIND) $(HTMLDOC) --batch htmldoc.book -f htmldoc.ps htmldoc-1.9.7/doc/a-license.html000066400000000000000000000430701354715574200164760ustar00rootroot00000000000000

Appendix A - License Agreement

GNU GENERAL PUBLIC LICENSE

Version 2, June 1991

Copyright 1989, 1991 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.

Preamble

The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too.

When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things.

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

For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights.

We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software.

Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations.

Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all.

The precise terms and conditions for copying, distribution and modification follow.

GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION

  1. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you".

    Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does.

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

    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.

  3. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions:
    1. You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change.
    2. You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License.
    3. if the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.)

    These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, 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 Program, 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 Program.

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

  4. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following:
    1. 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; or,
    2. Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or,
    3. Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.)

    The source code for a work means the preferred form of the work for making modifications to it. For an executable work, 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 executable. However, as a special exception, the source code 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.

    If distribution of executable or 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 counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code.

  5. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program 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.
  6. 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 Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it.
  7. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program 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 to this License.
  8. 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 Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program 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 Program.

    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.

  9. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program 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.
  10. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns.

    Each version is given a distinguishing version number. If the Program specifies 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 Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation.

  11. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, 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

  1. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
  2. 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 PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.

END OF TERMS AND CONDITIONS

How to Apply These Terms to Your New Programs

If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms.

To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found.

one line to give the program's name and an idea of what it does.
Copyright (C) yyyy  name of author

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

Also add information on how to contact you by electronic and paper mail.

If the program is interactive, make it output a short notice like this when it starts in an interactive mode:

Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details
type `show w'.  This is free software, and you are welcome
to redistribute it under certain conditions; type `show c'
for details.

The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program.

You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names:

Yoyodyne, Inc., hereby disclaims all copyright
interest in the program `Gnomovision'
(which makes passes at compilers) written
by James Hacker.

signature of Ty Coon, 1 April 1989
Ty Coon, President of Vice
htmldoc-1.9.7/doc/b-book.html000066400000000000000000000037231354715574200160100ustar00rootroot00000000000000

Appendix B - Book File Format

This appendix describes the HTMLDOC .book file format.

Introduction

The HTMLDOC .book file format is a simple text format that provides the command-line options and files that are part of the document. These files can be used from the GUI interface or from the command-line using the --batch option:

htmldoc filename.book
htmldoc --batch filename.book

The first form will load the book and display the GUI interface, if configured. Windows users should use ghtmldoc.exe executable to show the GUI and htmldoc.exe for the batch mode:

ghtmldoc.exe filename.book
htmldoc.exe --batch filename.book

The Header

Each .book file starts with a line reading:

#HTMLDOC 1.9

The version number (1.9) is optional.

The Options

Following the header is a line containing the options for the book. You can use any valid command-line option on this line:

-f htmldoc.pdf --titleimage htmldoc.png --duplex --compression=9 --jpeg=90

Long option lines can be broken using a trailing backslash (\) on the end of each continuation line:

-f htmldoc.pdf --titleimage htmldoc.png --duplex \
--compression=9 --jpeg=90

The Files

Following the options are a list of files or URLs to include in the document:

1-intro.html
2-using.html
3-cmdref.html
4-htmlref.html
5-mdref.html
a-license.html
b-book.html

Putting It All Together

The following is the complete book file needed to generate this documentation:

#HTMLDOC 1.9
-f htmldoc.pdf --titleimage htmldoc.png --duplex --compression=9 --jpeg=90
1-intro.html
2-using.html
3-cmdref.html
4-htmlref.html
5-mdref.html
a-license.html
b-book.html
htmldoc-1.9.7/doc/help.html000066400000000000000000000467041354715574200155750ustar00rootroot00000000000000 HTMLDOC On-Line Help

HTMLDOC On-Line Help


Contents

Loading and Saving Books

HTMLDOC stores the HTML files, settings, and options you have chosen in .BOOK files. The buttons on the bottom of the HTMLDOC window allow you manage these files and generate formatted documents.
Button Description
Help Displays this on-line help.
New Creates a new .BOOK file.
Open... Opens an existing .BOOK file.
Save Saves the current .BOOK file to disk.
Save As... Saves the current .BOOK file to disk using the name you specify.
Generate Generates the current .BOOK file into a HTML, PDF, or PostScript file.
Close Exits HTMLDOC.

Contents | Loading and Saving Books

The Input Tab

The input tab lists all of the source files that are used to generate the document. You can also specify the type of document (book or web page) and the title and logo images.

Setting the Document Type

Normally HTMLDOC generates indexed documents from your structured source files. To convert a single unstructured document (or "web page") click on the Continuous or Web Page radio buttons. The Web Page type inserts page breaks between each file or URL, while the Continuous type does not.

Structured HTML files use heading elements (H1, H2, etc.) to delineate chapters and headings within a document.

Adding Input Files

Click on the Add File(s)... button to add one or more HTML or Markdown files to your .BOOK file.

Adding URLs

Click on the Add URL(s)... button to add one or more URLs to your .BOOK file.

Deleting Input Files

Highlight the file(s) in the input file list and then click on the Delete button to remove one or more source files from your document. The files are removed from your document but are not deleted from disk.

Editing Input Files

Highlight the file(s) in the input file list and then click on the Edit... button to edit one or more source files in your document. By default this starts the gedit editor under Linux, the bbedit editor under macOS, and the Notepad editor under Windows.

The editor can be changed in the Options Tab.

Reordering Input Files

Highlight the file(s) in the input file list and then click on the Move Up or Move Down buttons to change the order of the input files.

Selecting a Logo Image

The logo image can be shown in the header or footer of pages in the PostScript and PDF output files. Click on the Browse button to select a logo image file using the file chooser.

Selecting a Title File or Image

The title file or image is used for the title page. Click on the Browse button to select a title file using the file chooser.


Contents | Loading and Saving Books

The Output Tab

The output tab specifies where your document will be generated, the output format, and some of the output options.

Selecting File or Directory Generation

HTMLDOC can generate a single EPUB, HTML, PDF, or PostScript file, or a series of files to a directory when generating HTML or PostScript output.

Click on the File radio button to select single file output. Click on the Directory radio button to generate multiple files to a directory.

Selecting an Output File or Directory

The output file is the EPUB, HTML, PostScript, or PDF file you wish to generate from your source files. Click on the Browse button to select an output file using the file chooser.

Selecting the Output Format

Click on the corresponding Output Type radio button to select an output format. You can select the PostScript language level in the PS Tab and the PDF version in the PDF Tab.

Selecting Grayscale Output

When generating PostScript or PDF files you can choose to convert all images to grayscale. This is necessary for many Level 1 printers that do not support color images and can reduce the size of output files considerably.

Click in the Grayscale check box to enable or disable grayscale output.

Title Page

The title page is the first page in your generated file. Click in the Title Page check box to turn the title page on or off.

JPEG Big Images

JPEG compression is a great way to reduce the size of large photographic or continuous-tone images. It is supported when generating PDF, PostScript Level 2, and PostScript Level 3 output. HTMLDOC uses JPEG compression when the output image cannot be reduced to 256 colors or less.

Click in the JPEG Big Images check box to enable or disable JPEG compression.

JPEG Quality

Drag the JPEG Quality slider to change the JPEG quality setting. The JPEG quality setting determines the relative quality of the compressed image. Since JPEG is a lossy compression algorithm, higher compression generally yields lower quality. Typically a quality of 75 or higher provides excellent image quality with a high amount of compression.

Compression

PDF 1.2, PDF 1.3, PDF 1.4, and Level 3 PostScript files can be compressed using Flate (a.k.a. ZIP) compression to substantially reduce the size of files. Drag the Compression slider to set the amount of compression to use.

Unlike JPEG, the Flate algorithm is lossless and will not cause any loss of visual quality at any level of compression.


Contents | Loading and Saving Books

The Page Tab

The page tab defines the page header, footer, size, and margins for PostScript and PDF output.

Page Size

The page size option is only available for PostScript and PDF output. HTMLDOC supports the following standard page size names:

  • A3 - 11.69x16.54in (297x420mm)
  • A4 - 8.27x11.69in (210x297mm)
  • Legal - 8.5x14in (216x356mm)
  • Letter - 8.5x11in (216x279mm)
  • Tabloid - 11x17in (279x432mm)
  • Universal - 8.27x11in (210x279mm)

Click on the Page Size arrow button to select a standard page size. You can specify a custom page size by double-clicking on the page size text and entering the page width and length separated by the letter "x". Append the letters "in" for inches, "mm" for millimeters, or "cm" for centimeters.

Note: This option does not set the page size on the printer. It only generates pages using the specified size. See the PS Tab to enable printer commands for PostScript printers.

2-Sided

Click in the 2-Sided check box to select double-sided (duplexed) output.

Note: This option does not select duplexing on the printer. It only generates pages with the left/right margins swapped on even numbered pages and forces all chapters (and the table-of-contents) to start on an odd-numbered page. See the PS Tab to enable printer commands for PostScript printers.

Landscape

Click in the Landscape check box to select landscape output.

Page Margins

The left, right, top, and bottom margins can be changed by clicking in the appropriate text field and entering a new margin. Append the letters "in" for inches, "mm" for millimeters, or "cm" for centimeters.

Header and Footer

Select the desired text from each of the option buttons to customize the header and footer for the document/body pages. The left option buttons set the text that is left-justified, the middle buttons set the text that is centered, and the right buttons set the text that is right-justified.

The left and right header and footer are swapped automatically when generating duplexed output.

Number Up

The Number Up chooser selects the number of document pages that will appear on each output page. Click on the chooser to select a different number of pages.


Contents | Loading and Saving Books

The Table-Of-Contents Tab

The table-of-contents tab defines the number of levels in the table-of-contents and the page header and footer that are used when generating PostScript and PDF files.

Customizing the Table of Contents

To change the number of header levels listed in the table of contents, or to turn off table-of-contents generation entirely, click on Table of Contents chooser and select the number of levels desired.

Numbering Table of Contents Headings

To number the headings in your document, click on the Numbered Headings toggle button.

Customizing the Header and Footer

To customize the header and footer for the table-of-contents pages, select the desired text from each of the option buttons. The leftmost option buttons set the text that is left-justified, while the middle buttons set the text that is centered and the right buttons set the text that is right-justified.

Title

Enter the desired title for the table-of-contents in the Title field.

Contents | Loading and Saving Books

The Colors Tab

The colors tab specifies the colors and background image that should be used for the document.

Body Color

The Body Color field specifies the default background color. It can be a standard HTML color name or a hexadecimal RGB color of the form #RRGGBB. Click on the Lookup... button to pick the color graphically.

Body Image

The Body Image field specifies the default background image. Click on the Browse... button to pick the background image using the file chooser.

Text Color

The Text Color field specifies the default text color. It can be a standard HTML color name or a hexadecimal RGB color of the form #RRGGBB. Click on the Lookup... button to pick the color graphically.

Link Color

The Link Color field specifies the default link color. It can be a standard HTML color name or a hexadecimal RGB color of the form #RRGGBB. Click on the Lookup... button to pick the color graphically.

Link Style

The Link Style chooser specifies the default link decoration.

Contents | Loading and Saving Books

The Fonts Tab

The fonts tab contains all of the document font options. The default options roughly correspond to those used by most browsers.

Base Font Size

Click on the left arrow buttons to decrease the font size and the right arrow buttons to increase the font size.

The font size value is in points (there are 72 points per inch).

Line Spacing

Click on the left arrow buttons to decrease the line spacing and the right arrow buttons to increase the line spacing.

Body Typeface

The body typeface is the font used for paragraphs and most other text in a document. Click on the Body Typeface option button to change the body typeface.

Heading Typeface

The heading typeface is the font used for headings. Click on the Heading Typeface option button to change the typeface used for headings.

Header/Footer Size

Click on the left arrow buttons to decrease the heading and footer font size and the right arrow buttons to increase the font size. The font size value is in points (there are 72 points per inch).

Header/Footer Font

The header/footer font is the font used for headers at the top of the page and footers at the bottom of the page. Click on the Header/Footer Font option button to change the header/footer font.

Character Set

Click on the Character Set option button to change the encoding of text in the document.

Options

The Embed Fonts check box controls whether or not fonts are embedded in PostScript and PDF output.


Contents | Loading and Saving Books

The PS Tab

The PS tab contains settings specific to PostScript output.

Language Level

Select the appropriate language level by clicking on the corresponding radio button. Level 1 output is the most portable, however most PostScript printers manufactured in the last 6 years support Level 2. Level 3 output supports Flate compression, however very few printers support Level 3 PostScript at this time.

Send Printer Commands

Click in the Send Printer Commands check box to enable to disable printer commands in the PostScript output files. Printer commands are not supported for PostScript Level 1 output.

Include Xerox Job Comments

The Include Xerox Job Comments check box controls whether or not the output files contain Xerox job comments. Click in the check box to enable or disable the job comments.

Job comments are available with all levels of PostScript output.


Contents | Loading and Saving Books

The PDF Tab

The PDF tab contains settings specific to PDF output.

PDF Version

The PDF Version radio buttons control what version of PDF is generated. PDF 1.4 is the most commonly supported version. Click on the corresponding radio button to set the version.

Page Mode

The Page Mode option button controls the initial viewing mode for the document. Click on the option button to set the page mode.

The Document page mode displays only the document pages. The Outline page mode displays the table-of-contents outline as well as the document pages. The Full-Screen page mode displays the document pages on the whole screen; this mode is used primarily for presentations.

Page Layout

The Page Layout option button controls the initial layout of document pages on the screen. Click on the option button to set the page layout.

The Single page layout displays a single page at a time. The One Column page layout displays a single column of pages at a time. The Two Column Left and Two Column Right page layouts display two columns of pages at a time; the first page is displayed in the left or right column as selected.

First Page

The First Page option button controls the initial page that is displayed. Click on the option button to choose the first page.

Page Effect

The Page Effect option button controls the page effect that is displayed in Full-Screen mode. Click on the option button to select a page effect.

Page Duration

The Page Duration slider controls the number of seconds that each page will be visible in Full-Screen mode. Drag the slider to adjust the number of seconds.

Effect Duration

The Effect Duration slider controls the number of seconds that the page effect will last when changing pages. Drag the slider to adjust the number of seconds.

Options

The Include Links check box controls whether or not hyperlinks are included in PDF output.


Contents | Loading and Saving Books

The Security Tab

The security tab allows you to enable PDF document encryption and security features.

Encryption

The Encryption buttons control whether or not encryption is performed on the PDF file. Encrypted documents can be password protected and also provide user permissions.

Permissions

The Permissions buttons control what operations are allowed by the PDF viewer.

Owner Password

The Owner Password field contains the document owner password, a string that is used by Adobe Acrobat to control who can change document permissions, etc.

If this field is left blank, a random 32-character password is generated so that no one can change the document using the Adobe tools.

User Password

The User Password field contains the document user password, a string that is used by Adobe Acrobat to restrict viewing permissions on the file.

If this field is left blank, any user may view the document without entering a password.


Contents | Loading and Saving Books

The Options Tab

The options tab contains the current HTML editor and allows you to save the current settings as defaults.

HTML Editor

Type in the program name in the HTML Editor field or click on the Browse... button to change the HTML editor that is used. The "%s" is required and is replaced by the file to edit.

Browser Width

Drag the Browser Width slider to specify the width of the browser in pixels that is used to scale images and other pixel measurements to the printable page width. You can adjust this value to more closely match the formatting on the screen.

The default browser width is 680 pixels which corresponds roughly to a 96 DPI display. The browser width is only used when generating PostScript or PDF files.

Search Path

Enter a list of directories in the Search Path field to specify a search path for files that are loaded by HTMLDOC. This is usually used to get images that use absolute server paths to load.

Directories are separated by the semicolon (;) so that drive letters and URLs can be specified.

HTTP Proxy URL

Enter the URL for the HTTP proxy in the HTTP proxy URL field to specify a proxy host for all HTTP requests.

Tooltips

Check the Tooltips button to enable tooltips on GUI controls.

Strict HTML

Check the Strict HTML button to enable strict HTML conformance checking in HTMLDOC.

Save Options and Defaults

Click on the Save Options and Defaults button to save the current HTML editor, page, table-of-contents, color, font, PDF, and PostScript options. Default options are used for new documents and when generating documents from the command-line. htmldoc-1.9.7/doc/htmldoc-cover.opacity000066400000000000000000000372671354715574200201230ustar00rootroot00000000000000bplist00X$versionX$objectsY$archiverT$topbnopqrvw~ '-ABICDEFJNQUX\_bcjkwxyz{|"#)*6789V:@DKLPSUY]eou  !:=@EJOPQRSTUZajq{@!./347AGOPQUYZ`aeiv|}~>NOPQRSTX\`defgknopqrsx~:,M?12345678BCDKLMWXYZbcdefrst9uvU$null0  !"#$%&'()*+,-./0123456789:;9<=>>@AB::CDEFGH:IJKLMN>PQRSIMUVWXYB[\]B>B9@9WpolySidWpixDTypSbmPUresUnTsecCUcolSpUoBgImSparVnPaStrWactLaysUsnShsWpenTTypSmodTzoomTallRVsavStDTmetaVspiDecVgenNamUorTypVpixRadTfrasUimSizUbgColVnPaFilV$classVactTraVsavPrDTtarsVcurFraSenVVlineThVautoBTUshLayXrectCRadUresiMTcurRWspiSegsTtrasWfilSensUmainCVtraTrgVcurObjVguiLinTvarsVlasModWpolyStaUbgTyp/C "#@@ D#@T.#?,- b *#- "#@I+""cd"eimWNS.keysZNS.objectsfghjkl \kMDItemTitle^kMDItemAuthors_kMDItemCopyrightXNew Icond"sut ]Michael Sweetxyz{Z$classnameX$classesWNSArray|}WNSArrayXNSObject_Copyright 2017 Michael Sweetxy_NSMutableDictionary}\NSDictionaryd"uX  "SresSdel#?xy\PCResolution}\PCResolutionXPCObject"#?"I"#@"#@"#@#"#?d"uR "ATlaysUanimTUlAcLs#?  cd"mfghjl d"ut d"uրހ "M::@M@RSexpUblendWmaskTypUedMskSnamWmaskLaySvisTisShTopac $ %#@Y">BUalConTobjs"#cd"m! #@ia-#@#"#@ia- xy_PCBitmapContext}_PCBitmapContextZPCDrawableXPCObject" #@# d" u xy]PCNormalLayer}]PCNormalLayerWPCLayerZPCDrawableXPCObjectTLogod"u&Iv "@:":#$@MSfilH9:' ">*B&("#cd".7m/0123456)*+,-./089:;<=>?12345678 #@ia-#?#?#@##@ "$H'#@ia- "$L'#? "$I' "$S'#? "$' "$Z'#@# "$E' "$' ]Shadow Effect"defhiTfilNTattsG&;<_PCShadowEffectFiltercd"lqmmnop=>?@rstrABFA [inputOffsetZinputColorZinputAngleYinputBlur#@}~"=UNSRGB\NSColorSpace_NSCustomColorSpaceJ0 0 0 0.5CE"TNSIDDxy\NSColorSpace}\NSColorSpacexyWNSColor}WNSColor#VxyXPCFilter}XPCFilterZPCDrawableXPCObjectxy]PCFilterLayer}]PCFilterLayerWPCLayerZPCDrawableXPCObject"::@M@VJ W#a">BIK"#cd"m61350+L-M/NOPQRSTU #?#@##@ia-"J "IJ "J#? "J "J#@# "EJ "J#@ia- Scd"m316XY-Z+0[\]^_` #@##@ia-#?"I#@# "I#@ia- "I "I#? "II "I d"ub      " @@MVM@VM V@TrectTstrYSisIXstrTBndsTstrXSshXTantiSflVVattStrSshYUalPixSangSflHc udI t_{{10, 83}, {120, 80}}$"%&'(XNSString\NSAttributesesfScd"+05,-./ghij1234klnqrVNSKern_NSParagraphStyleVNSFontWNSColor;"<>>?ZNSTabStops[NSAlignmentmxyAB_NSMutableParagraphStyleAC}_NSParagraphStyleEFG"[HIJVNSSizeXNSfFlagsVNSNameop]OpenSans-BoldxyMNVNSFontO}VNSFont}~"QF1 0 0ExyT}xyVW_NSAttributedStringX}_NSAttributedStringZ~"[9WNSWhiteD1 0Exy^_\PCTextVector`abcd}\PCTextVector_PCRectBasedVectorXPCVectorZPCDrawableXPCObject"::@ghMjl@~w #">rBvx"#cd"vzmw5yy/z{|}{|} #@ia-#@#"hw#@ia- "hEw "hw#@# ZBackgroundcd"m #@ia-#@#"v#@ia- "v#@# d"u   "@MVM@VMV@UdimLKWfilPropVcornRXVcornRYUstros #@0v cd"m ]cornerRadiusX]cornerRadiusY_&{{10, 53.650000000000006}, {120, 120}}"@::?>:MVrelLP2SblHWgradAngUradGCTfilTWrelRadCVfilPosSaEqStypXrelLinP1VfilColVrelLP1UfilImVothColXrelLinP2SgEqUfilGrSrEqXgradStopUpgNumSbEq#@V }~"F0 0 0E}~"L0.6 0.6 0.6Ed"񀎀">V<ValtColSlocScolZ~"9B1Exy^PCGradientStop}^PCGradientStopZPCDrawableXPCObject">xy  ^NSMutableArray  }WNSArrayV{0, 0}V{0, 0}V{0, 0}V{0, 0}V{0, 0}V{0, 0}Q0QtW100 - tS100xy_PCDrawVectorProperties}_PCDrawVectorPropertiesZPCDrawableXPCObjectd"""#$%&?'@):*+:?->/0:M3I:\79TcapSSposUinvisSwidUdashS Z~";9B0E}~">L0.4 0.4 0.4Ed"ABC">V\">0V{0, 0}V{0, 0}V{0, 0}V{0, 0}V{0, 0}V{0, 0}d"Vu51/k xy[\_PCStrokeVectorProperties]^_`}_PCStrokeVectorProperties_PCDrawVectorPropertiesZPCDrawableXPCObjectxybc\PCRectVectordefghi}\PCRectVector\PCPathVector_PCRectBasedVectorXPCVectorZPCDrawableXPCObjectxykl]PCFolderLayermnop}]PCFolderLayerWPCLayerZPCDrawableXPCObject"M::@tuMw@R  ">~B"#cd"m #@#"u#@# WLayer 1d"uƀ "@::@MH ">B"#cd"m #@#"#@# _Inner Glow Effect"defG_PCInnerGlowEffectFiltercd"m€Āŀ ZinputColor_inputHideOriginalYinputSize}~"?F1 1 0ÀE"D#@"::@M@ˀ ̀#">BƀȀ"#cd"mۀɡ݀ʀ #@#"#@# TTextcd"m͡΀ #@#"#@# d"uЀـ      " @@MVM@VMV@ uҀ _{{0, 25}, {140, 30}}$"%'ӀsWHTMLDOCcd" 5,-./ghij1kՀր׀r;"<>>?mEFG"HIJ#@1op}~"F1 1 1EZ~"9D1 0E     " "@@MVM@)VM,V@ uۀ _{{0, 5}, {140, 30}}$"%0'܀s\Users ManualZ~"59D1 0E"::@9:M<>@R #">DBހ"#cd"HKmIJLM #@ia-#@#":S#@ia- ":W#@# ZBackgroundcd"[]m\^ #@#"c#@# d"fug   "jk@MnVM@VVrVMV@  cd"wymxz ]cornerRadiusX]cornerRadiusY_#{{0, 0}, {140, 187.30000000000001}}"@::>g:M }~"F0 0 1E}~"J0.5 0.5 1Ed"">nV4q">n}~"N1 0.67 0.6755E">n#@Uh'}~"M1 0.34 0.351EV{0, 0}V{0, 0}_{70, -93.649999999999991}_{50, -49.999999999999986}_+{2.8421709430404014e-14, 93.65000000000002}_,{2.0301221021717149e-14, 50.000000000000007}W100 - td"""#$%&?@:+:?>g:MI:\ҁ    }~"L0.4 0.4 0.4Ed"ف">V\">V{0, 0}V{0, 0}V{0, 0}V{0, 0}V{0, 0}V{0, 0}d"u51/k d"u xyWPCFrame}WPCFrame_PCMetadataObjectZPCDrawableXPCObjectd"u "  @@>>:>M@@BYauSizCropVnewFacUapIn1TpathTapIDUcropRUapIn2UisRelUisColTcropVvarVal) "_!{{6, 29.650000000000006}, {0, 0}}_htmldoc-cover.png !""#$%&'()*+,MR/012>456M89;<XUcodeSUprColVprShTiSfraVcodePlVcodeFrUcodeFTsnShVexPropTpropUgenCHUgrTypVanLooCVprLinCUcodeL' #$&(!  "%cd"?Fm@ABCDEGH<JKL V{JFIF}U{GIF}_"kCGImageDestinationBackgroundColorU{PNG}V{TIFF}_*kCGImageDestinationLossyCompressionQualitycd"UVm cd"YZm cd"]^m cd"abm #?Zpublic.png]public.foldercd"him }~"lL0.5 0 0 0.5ESiosUcocoaUtouchVMyViewVUIViewxytu_PCBitmapPropertiesvw}_PCBitmapPropertiesXPCObjectxyyzYPCFactory{|}}YPCFactoryZPCDrawableXPCObjectd"򠀒Yselection_{140, 187.30000000000001}Z~"9E0.75E_CICheckerboardGenerator !""#$%&'()*>,MR2>M89 ABC(?0>  @Bcd"m123456<789<= _"kCGImageDestinationBackgroundColorV{JFIF}U{GIF}V{TIFF}U{PNG}_*kCGImageDestinationLossyCompressionQualitycd"m cd"m cd"m:; [Compressioncd"m #?_com.likethought.opacity.opacitycd"m }~"J1 0 0 0.5ESmacVquartz_MyDrawingFunctioncd"mفEFGHIJKLMĀāNOāPTĀĀ _framePickerVisibleZhideRulers[windowFrame_layerViewDimension]hideVariablesZexpansionsYprintInfo]toolbarHidden_editFrameMetadata_{{35, 38}, {958, 839}}#@i`cd"mQRSS "\NSAttributesaUcd"mVWXYZ[\]   S^^_QS`` _NSHorizontallyCentered]NSRightMargin\NSLeftMargin_NSHorizonalPagination_NSVerticalPagination_NSVerticallyCentered[NSTopMargin^NSBottomMargin"B"Bxy[NSPrintInfo}[NSPrintInfocd" (m!"#$%&'cdefghi)*,-!/jptyc _"com.likethought.opacity.preview.ui_(com.likethought.opacity.preview.elementsWfactory_#com.likethought.opacity.preview.web_&com.likethought.opacity.preview.cursorTtype_&com.likethought.opacity.preview.iphonecd"9=m:&<khl<@Qm Ucolor[resolutionsd"EFG16no+0#?#?cd"NRmOPQqrsĀĀĀ VstatusWtoolbarTdockcd"[^m\]uv_`wx WaddressUimage_#http://likethought.com/opacity/web/_,http://likethought.com/opacity/web/image.pngcd"glmh&j:zh{kmno<|}~ XhotspotXXhotspotY#@#@=ffffhcd"wmx:z{|}~&kh<QQ UrectXUrectHUrectWUrectYTleftStop#@4#@F#@ixyWPCImage}WPCImage_PCMetadataObjectZPCDrawableXPCObject_NSKeyedArchiverTroot"+5:?Y_"*26<AGMQX`fnrw|#*18=DLRTVY[]_abegpruw &9BKNPR`it}   &*.09;=FSZgp#%'0357PU[acegpsv     % * + , . 0 1 3 5 6 ? A V \ a c e g i k x }       % & ( 1 ? J X ` k t y         - / 1 3 5 7 9 ; = ? H Q Z c l y {       & 7 < A C E G I ` m v x z | ~     " + 8 = J S [ ` h q z &')+,.0235JLNPRTaprtvxz|~,.0=?HJN[hjlnprt ')+479;'02468ACEGIKRelt  ',3@GIRW`uz =>@BCEGIJLacegikx   )68ACPR[]fikm &O "+1578ACEGIKMOQSUWY[]_`mtv(=?ACEN]dlsz  2468:AHOV]dmrtvx!.BKV_hv  "+8:CEMV[]_a !#=JQSUW^`bdfq!.1368:CPR[]bortwy{  !.024<IRTVXZcegikmz|~ 4ACEGTafh    ! # , . 9 F I K N P R [ h j s u ~ !!!9!!!!!!!!!!!!!!!!!!!!!!!!!!!""""""""!"#"8":"<">"@"M"\"^"s"u"w""""""""""##D#L#U#X#[#]####################$ $$$"$'$*$-$/$D$F$I$K$M$b$d$g$j$l$s$z$$$$$$$$$$$$$$$$$$$%%%%%%U%_%f%l%q%v%|%%%%%%%%%%%%%%%%%%%%%&<&B&H&O&S&Z&a&g&l&s&x&~&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&'' '''''''"'('M'S'Z''''''''''''''''''''''''( (((($(*(1(8(A(V(](r({(((((((((((((())e)g)h)j)m)p)s)v)x){)~)))))))))))))))))))))))*** ***G*T*U*V*X*e*f*g*i*v*y*|*******************+++%+8+;+>+A+D+G+J+M+P+S+f+h+j+m+p+r+u+x+z+|+~++++++++,,,&,3,8,;,>,C,F,I,K,L,U,b,e,h,u,,,,,,,,,,,,,,,,,,,,,,--,-C-O-^-c-h-q-}--------------------. .5.=.c...............// //////!/*/7/>/A/D/G/N/P/R/T/V/]/e/j/w/|///////////00 00000 0#0&0(0*030<0E0N0[0l0o0r0u0x0{0~000000000000000000000000111#1.171I1N1S1Uhtmldoc-1.9.7/doc/htmldoc-cover.png000066400000000000000000016267131354715574200172400ustar00rootroot00000000000000PNG  IHDRxQ"Ug iCCPICC Profile8U]hU>sg#$Sl4t? % V46nI6"dΘ83OEP|1Ŀ (>/ % (>P苦;3ie|{g蹪X-2s=+WQ+]L6O w[C{_F qb Uvz?Zb1@/zcs>~if,ӈUSjF 1_Mjbuݠpamhmçϙ>a\+5%QKFkm}ۖ?ޚD\!~6,-7SثŜvķ5Z;[rmS5{yDyH}r9|-ăFAJjI.[/]mK 7KRDrYQO-Q||6 (0 MXd(@h2_f<:”_δ*d>e\c?~,7?& ك^2Iq2"y@g|UP`oiTXtXML:com.adobe.xmp Michael Sweet Copyright 2017 Michael Sweet New Icon yP~&IDATx][b%7#da@UN\G% "22d!2 :???!>"3Ϩ~B= =Mڸߍ.x|捿>>n@ퟫ?3/ ʊ,4 ~TSK&.iϥ=0|wK.~ L^}GYHxO3Y۳}_}E^6{2 Ϳ5"M_œj-m[?zn^ZŧX 4@{>:<,jދۿ~,filx/O Nm7K7 g b%2 ymWs(Y?.ׯևq' MOCcr,;¾ociFޖhx"i/׏ g妝]߁?uI_O.Ƿk~s7?#{7sj~jOF18ՉٽLƀ?"nQ6~eֻsxbaN'_XlcdQu>P~Y bpG4S ~G?R\nܭ???7ςtgXri`P>G,|$&ߢQ~Bx[|9.3r'TL^ ;Ny%2'2VJ-ڟީQO5MxpRX2LmgfaOLqIHzsnm3`F9fvYgw{y273=O!Ԟ̤@sf7_+Tƀ>3TxMx_eέ~żq?V,͇tڞp3WJ \x#|HG>eL= _pE-aނG ۝9%e_z.(?q1~Wro-H̩ϑ@ &>u^!^w@3r?gJ"pQ,*j.F֞X~~R@Z;/Ry)= 1׀po`OK丗ma"1#<Ͷ@aڴ;???&:\)-N%6-"X=y} %[#@!_^TG(kI}~keWru*w3C+1~ONj50|x? CECT<ѥ/ װF7N:Aa։ŷa=\'z].o߮GDˑ-qwBۥNKyk]ʍCnk 1` e$zx3ڠڷJ#EJ }V0E( 5Csُ~Y'~hY2e3_YwT:Q\|ʊ,zhq\%!fUO/@f -xbaolT'ܝ倈Nw U|Jݞ|vR$D]m#|@^#wzU3Xo 5 y+ꍂ96QVfݲd~FgLsLv"I7Tʕ1ۓ{5bꤖ',/'f/z4kò%24ӎhvQR4SǮA;mhnNbn_*Ӯܣ/Q~uj ag$=v_}ǹ A%FY~m=ӄmu$O>+D|5vy~u:|Uf*m???Ŝlĉ]VE84u&#Zk YO;d枴-׈;0D|[hϰ[^x%7[YLixh~'LI+Ht977"I x(*0 yؿ` Jh狏gw1CEc Hg T6uRL;$f)lyp 2 z{dP3>391)=%h)T}~kK|c<VIg}Ż{ex| 3>bxT 4%!?k2'7aqBKe?4895)f`ų1Wov=4jێ>0w/#c'%34,u׻Zlz5޿_Mrڑ_~2dYKሥK4ҽ=䤨?{}岹Hj(???kB#5tEFV6ŇA3e?_iKd3P# 7nO<{$a H [%ab :8{S~,]="cNn0$1;>'??|Zj:(~PCktIatٶ:KO4b~1\h&et5@k{)%rL;;/~-;-`yK?' y&+A(%&al%"N״gkBFݸb^~T9}yT?Eۂ6? T~oFk]J%>??? SsauG*i"Sc4wߎAsPFYJ^qO&&frSCTؼ苅A2x٪V5So쩎@vUo_$F1b M "9*i"K2@M<Ӳrzt\W\ڎ/tvm烩: t90 Aaa~E!gV ҭ-n\[b֬_+K]4ۿ@U!zA#n׹=!s[~綋Bz´ߡqCemڟ2 8Ji9???>mbm``H].$1biF$n?D5|-Ip۟4)_LKcuL+Frm3be24i< ?y0}_ =w<0]7$Ó~rC>Hker$z&nXf/ ˃ˏg^L뭓}j?^5g~;X EC+e|a _ʦu.HGg%?>ߡc Za???#^%=d9N ^1Gk h`|= ow`x ΁!cgo_N;r6τ#:+\ Ooy+E!kЬ_zx76ٛ~BD3<^ rWfM`>m$e+tJE *.lLNSgo(J8ܺ~1(PDk00Sc?9P|~>kOWGk,c_o=Е:#x˛q5[|Kl>JB#v_؞px{߾ox<'K|e<@z4~ɇxh^`??ؓkxcOh ]4~\\=]`߅;p~4 s>=A_3PI(SEZT^A9I9?????􄊧 }N53r-). F =>GFc3!c 2f-2pAi{c3\(r&R@S ."]?# OibktBy! s7g1HOtiox޾m(`}Oo$ yi(_Ҍ(?_I^T+)|H#Cd L R'm0Q!2t90`=hs >{PЧk9Xt:.w {^bowrzyAE&\LsJw9?+QaO86t ]_ǼTItJ͓ʯ(7_j~O_*Xh"Yr BzbW^ ^V{:|hGWE|4|)5_ReX xsw!sܿ~_΃/tac Ai =\MQ ti֥AT|&[&PNO) &YO<A!,xQ4@o-zh% et zZP(D+)x2+(!7p }, 1̒lMҍ quĎ oJ%)4H_ .O/#>dP,@o6iCW)bhɏ{.|ҪVDpL;s[ykOb'9ԋ &%|_B);Q KVqQ/}jCLRx#Xo%”a"b~՘B%P\nK<d0H0x d v3:^v<#;jQ4~xS\BtO;eyO Mѵ&=T/ ##~ |{4i.Ǘro7/Z:n6q>7Gm> CozҸ~s`^Y=?!EIy9}"%>F%=6ahݏz7L4t#oi?%SSvF@VcGZǓ^IkWDglrh$???o}EV4ц4Wߞ. Htd =&{{` uUȕki1%p1H| 7\46c(F~%&Wl]rkڿIO)=@[p+Tz![ MtLN)Vp-(xdj,O뗤mg<[.ʈ~YCzBz 1=ErHˏ_bk)'ez~Waݏɱ$ҬڿVqYe#F}"LmQs0}'!獯 0cV!r3ؤJћ6QWI k&BڣOx @:pֈS!b "oh|{SVO>\6FVER?E!9b3Qc42z[F^0q7AQ `Myx~!ޣ^x.8 _0xia= x Tsrp']%e>T}a,޿l(,˙ώu3mx&8DĎNo \ɜ(2}({;~o1U k@ V~Wշ }Q$.iÛ2"n5&c5xx|RG[ !S(l_*S% sMJ_It_<9RAK0dcp{D0e8x$zkE Bʼn#ň-}|$e=>9lG:] ESLI~F)єU4ihY\l)k{%V5LEjI*|WNgpnJkh:*oK"?L"-NbųyC!j$|pX&R%T.kq0`6|DoRª \DXPWYu O v>n^kĸE%"z_ KEJ:j1RzrI2LX;2nI:}=1zz-wlOW4닚72~&?Ęa|#J|tNk]}gS/ nW9fev}, !-'?~fJY~*O3[F?~ad6Ξ6i:}{‡ᔱSI|ʶEj.*/*7-(q3 ."壊?7r?t=^Gg&NrspFYۍmajOܐ ]eJrR|a'|z+7ChfHr.F#ppSl!kHd6 bG18+ w( 1Ѯp^+2dr3]k^=m(5*uDsMxjW;[&׼l)uٿ".0?~0-G~tOGj9@Kt}_{`th[Z _)^ njpO:XY`*URNU=WʜB3>=!U*VЌV.tH'$c%=]բL)ѳ1Ad["ABIqKGzU3 "|Lz*8+rN6 -[~>lhn<6œ6ߨ>Cm A3->?%жlٷ' S/0CU*~< Mχg<_9G[Mkr0hpתD_;] b}K-; Ugy̢L_*ݫ6R;|qG4(ļ3}\y_1hBb*q=NUSsh\SScȤ'_z ^vrHBe6- <2}/9[M0(Vlb!Tnt cc_+<{Kv`}ȳi?dF_hPⱱ0RTOs@B:[>n=F5f%!+è0hDH_ÅЭ!Ru"b_"z0/O-MS糎Wݿ ʐ O^o/Ct OLj _IMDs8WaHuTL|4<'i.13 B D`ࠥS~)>0g 䓐Ħ?+}.N!re5P7,E{>%ӷ2^i3?]wV 'f>ǣƴ~cc߇$x {B0~Uڟ/D_.ʊnoyGֆkL7E%tcCUK gB㋟<7U3Fq$e MկGQWR:M"_l$D+ry^cp)ip`/b6Ӟ?;HNiBSš[;&بOhA!:Sl0Z@8P[J?d44 ;bV0rFrVJ#Bwiw#a|->liJ._Q o ՙk;,d f 0z7l#|<ߗl37|g3Ud~~Ud o+rAy~ X3~?i,YiUf~'fn>Ĵ?x?g}Dֈzܠ|C4<}" AɃmo(AWL. C#9?W>θ O#Ơ gvƾ=&h1u^权rO ï&Vh1WP`ڏs8S'~|HSyjA 4N.5:\>L`݄\?~-d8v>y}*pnt{'P|:_<~xvD2~6^̘ؒ BM~?{0u>iM1_t{!<8%yͿ˴g#pq9kBjV͘_QҒ>ao,Fh -->7Dp7<4E2gK=tO)[[RwD/d#$l8?4UL "9DP~ ZIctc#Ŀ OsM(i_Bu(P &F >QQ!;@qyq0Ȣ!6kUj8KSl\P5(\o*KOUr!D5'|dI%LcGHM>!=q""h4vx󧱾o#H+W];Urwkfif?'W]/P=.z$ * g.&f)qCPsoᷩbtG>?$X! |wa|ѐD@Zk6{(G߱x1gI_d"'۶p -foPQg(L#6G(#я\6 H(-kN?n&2y4 wѦB_О& 8[7 ]q$旘ohZr*')9d4{+NA궠fף<#~->hFXaQ[$i>ڇ&r02]f~i/쇝Gd~z*~s6ypxn?=Z>xY`ioO Ag=0Y %g5Mx?p!HHba?rp~(at( {YDgVB-TԺai?H͡+t),"b4YK8??3FK; K\Gk5DM㇈r_`>ڇ_“}ȱ b`=x|i^o/\qQۯ1C*0p/Hϟ *`^>-cHU}3?ݽu}1 ^wkG0yB}:nc Ez(Sn L+ؙeOFCRsR iLv0!ъisa~ +Fav*m⹥77>M03/b<#*w=E/.|.{vz2d wm.*a`E&mOʊ->PJlϿT# Lg QU%/=bۣWHZT]Lk惽 dAG=HldOx x vXɈqڨ! Vj!4~}>\rifIwHW`}B-bA?}&LLd7Au}Yj]ҭdiz*yѷS3x|7L51/n VY0ӯ_?:ɞ{2>HDu+'{Iڼ@`2&2'1 ~?7um;4*wN܏"mlT!gj`[r-E*] BxUZ匏 ^+oIKG.+Yq{t~'ztFV&KUֺO7VFOp]?/ j'E¶=%rJ`ujV-0%*+'?sTd *oA=*JSK9E8)J=I^g^c<+3wD[֕\̄r[ҁwX֡.FVoI "bRj=_]Djm}ue,VCd?aqWj1 L.TQXIvweu+GRъ%gk T֧6٫^1:3$KC[JFۏ Ƀ???qk{ ߲XIzOW $ jzlr: )i݄077p7Ɍ)8m,cgsptkO'-~(iIQ2Z S7Yx.|ȇwB XY =f[P!`.+.iVqs {K~W >wvxD+{^oj Y /O/;Q BW){9)0px걵Ϲ_ /e$|Sx|;|n!k%BL 2\"p'm]&,(p?ߏ?awYw:[!gA /9meqF:㩊 DP#K-=[NpetzQ^9B?ݕI(_c(r918OuբKZ`nzܷ7Gcۓ}5#ٞx%Qo10J^ae2ece'S1yr_LZԟWEnY 98ȅUJ5Ts(PIp#R 'F`MZ2 9k4nH=P8!EG@DY ?Iuš@kgZ<NG&j.fMoʒ'hlE5+s“Dbݾ=5v'0{j{6!|S?#BZe4hRIAv^7At l8R(q,0Zh g+h7jqMPL9[7f8IV]o6Eɠ2 zIw`NDaU4EFcDݕtUH /T`U #^OXQɆѬ_zrŒOR]HIe= (^$~VWk-gcINL@O~ J|ܿP1 @o(VE/avԉVB( h\ccy#9 9&VcaVN)v&`Q=]$'z84NԱsn*k${+q*{MR$K;!Baǫqm5_.c~`WJKqY'Q 'o5_k価88߆57ߍo\NW`&2B8yRT+y!K-ߣ%hDw+# |V6zqѢZ#Us$(%@UqYM% B1Zp!WI9zU'4I j,Y |'?ӭ_O}:ᶣ4kľֳ CQRcTѓ&;tkߨP h@ Fʜ)|1>G{_{o!8=mu7!!>c¯!uoFמBٚij* un*xa>xArG`./7D:Q'N hrShC[s# y3!vGHO/㋧,u{?~ï/=v{ԀʸR]*KVdTċ ]o&\ Ft*P'/l)S>3#jvǻ?õ::Kjݑ"WBOx>|*&n$p˰omIm: kq bMTF~ɐ(AdD))`_L^[cs쟶r_ )Qc;H͟tJz>kS$eG دD֏+b8٫Tf[K~>c[?ݙ/[a"8Hy y|'SS$о2g (w^Uc@U-ڠop_`OtC~^Jh/sgq8&lզ㝎Ñ{dljkI 0]_W_kGūXU*6޻7+xs%8y5]ͦ͋њ+<zCJMJ[văǷ_ش〵n/ƃ3)bε~ѧz?~HmƗ"CAa9R\r:S׍z Zz@9KV9Bۏ{J Rܟ?8ۜ,t?ۢJwY(^:VG|?8\5B7H/WRHlMIz K#VT|HEI *nt~Gzɯ*i<tMEgM R"\FWojx]х^7]*qn3Y-ܴ?T:n?}bMF& c,F& +M:oҘϤӖ.^o{o+ffmY |Eb #Rm|8fn>dn>`*|=qV,p9fYF;X͑jtZ =Tvz#Fk>,۞ k% f^fWٚl#ُvAy!H0[1j2]}ֶ|.CMʀ!4e4NjaqB 8 %Z9! AR'( TzO~?/F{;.@|>o @& 8KT g0>0PJtJ*P"rzQ[(2;Z#S(L;|p X\# gA` Vֱng9 G>*}(rv AVjڗ ?E! O4M8=C}Ll_KVzhCƧw~iDɲ]M+: Dף+fCN޸O3Y"]/եo{:JA+rBgVE-Rx"ʚ]WCXW5>_xK@HT< SR)X"gU$E# ȫCe0O9)E^=uFklwNF_e>=2wUP#i̢u}[Vc6|JMJV!L,#").nIZ6n$]6|56OMg~{ݿt+׻6x[;:Ë*HҞHΒGw#B0a{ا%CH9ѭM0Nq=66PV)\RQ' ^ھލ̊8..~?gڟ/f#w>$MV#wfz- 84=sT9 ޓ~wbAc B^]gUl׽k^M4Ts[YA{3SGx4$9 pL $lRl~'[qwr;ۓPK9D$' h׻^!FI:$>T} Sllv'Rf~~| k/9&+1g(m"Sqc.BZAs nǥOt"}pU&j[eI֢ TYW: S{"QB2Aڜd<=(J})fJrN~>U݇eD"[(н/Smɵ=ړ.JۓUA,cڡ];|w;?y) d+·#ﲼW:z6$%Qf^eh83nf6JaM&0Df{BvfnBmQzzeb1n|nk$'{B9o} 2s}i?)!-fktQF1B[L UMrV${)d]3Bcq@R#Uh?x_J^ |O<۩(%X(???߃ >(*QJS]'qZ9ˣ xM^Bd̍Z:UPek܏k,9)U+5WsRBJ!]CqKd~;^f~&.u~SH=ufYC:%(dm <&*>Sg|0KR#Ye~FOR0=[J)[{u\B0M.Zv%eDe!Baƍc2dOe/ Rx|ݿCa6h ]|_~q~=A4ZJ- A9D>}mjͬ2=9Bۏ~1 aE%[(|:?O?{jGҠ.zOs^]2)GU0"}`jm&LFctEt4!e"&0?4%*ه9!*'ٯM`ǹCz|՞d0Ho2&} ́TT٥hAo_Qj RU$Bw~`tr2:׼-aZY'ThlB$SMp"d#@_0{ݹEA '[VT886MxQ3m~ DSnņߢ^]r5#mRdz u["Dd 퉦g4H/i ] L!a"Hr`sU'4Cת0uo6kc95[`T/_jXސ$s1&3vAKSYIi&-Xf|k`)VxpL:ՈUa0ml\0m?9lQz~nIjE/HĊ߭w EKUrC|yƒz>_99}eOP>@j@FimuЇ C8\p)Da[_?JH>$NoC̡?PG +VQ9;Ź''GUoFdJ_ŇG$-$sS<\h/a ƫCi b&l惯.awJ %ߞ8"7||PEit77r|Ivnސ*t?6w__q:RZoO~^1!OzR}e= s0E~s{*n>DE΋obe+%1ٛW1lV%bYRtWQBՂ (I͉ص?:>hb4O-DUܞ-@ ߟUcޟzG*ѐ???Vw Eβ[ c ~QfC~\]{$Hsۇs{Cظr܈~ME:.|4ȭI?7f>R]s*a Wz`ht<ɚ3}æDͷ'$|>g:[s | v]n옺?xUBۏ8*bzQzԳ}o+$S |7ln.XBMeB"BDn* M|/g?wk|fk*j?8`;rJb?I!h"Bf2O0q+&Kez|Tvٶ32Ax}W=|X$EѢ$Հ#eh :tě;|tƎH4V77iGFI#B:?r xïkYQEK:sT.7i>3i23G}9㿃' lIvw"̀OIw ?JE23ٷa? |` 8tN,Øߵ!,g'Oh8~ וdFT7$z'ڟq2z% u%*L{="/NI{8JV4]s]cDYAZ]z:XL!'b`?̂w,؊{o<vƒN%W:!/@$PW陦H?=z,1Kx'Lת1-/t4*DQ5/">;qt|&X8J!ocHUm?d25J#|@_ z~*ÔCCś̟g $yPXQ$ %ϟ^)$~NYO{IpV^բtn!,x Z_=rs[hO3R$8|Ww M;<0d oEx:!AXo.du][|W7~ fg[E!dјDv@X*dY 'l`A%ghŃ=·׬!dn]H  Ӗư~@|k7@Sf?B'z?J2w- %$0?h7d}ۯ!zV,fFBߟ\?G_$_OلZe,"j!BPWUyoC7pڙdvEMaG :s2 c5M O:G?kѪ>1:c{%[RS Dh l?T! zOQRf֯Wf?p#t iV{ͿftۇQR[ =1/1!fso׻ޮwi@su>΃ўl7o7y[#`}f+[1g4=Lȗɍ1mndmoT{\9k -<}7]. *fQ\M]5?M^{΍//\Z2>0BO_o*ZT.w5퇑iˤiUHDulKԗa:uHq'61'WF`-?{ڋ% ͼ}Z|o-X,BO0뷞KrڟˠfH1V+٫xA9@`۟/cЭ} e ԸUch(~B))h´_F_m?m)dX<BtQ}V"CRZA~c)HHx}Gn)U3l> XI0?/FXKSC˲1IJ7 lYi~!k(9`52l|&[4=&Mn!(njx5&KpY9Jb?9^~NA}ʼibb;@d2~ca8‚/b III=Ea. > VF@0<8>E =į+J񖰐/SS߿B"jٞ~?҈זEm LI3dv e1ذ¬ӟ0+ٶC_`3:_͘HF; n*6jRI)㨪o0rd"Nl O'_ٕUH%bu9J"u> z%ݎ ?|ڟхbzda/k"9'\q躉OTŇq al^bRpHU`ǸBل9V}~ $H-G|peưڇq&ۇ QN0ΘC"ȎwGm?IIQJΖӴ_J'ә}Ou>P]n"(9Dn@k۔?A( *W{0 fD䖸ԞnL?g;5%賽{mK0ϏƂ#Eէ>=??u~CrLVMh%"k xԳBY}ZKse9y |Uȫy ۧ|}>?kEѥE< ZA@r[VEp Pr6ntyd+>tzQ7YNv)]򣤇\obD d@+۟(.k=v'E !"a|t3M/P퉹W03(V4`){"*EbO]tZE_&ٲ*Ɨ}+JƞoE v IN4ٿrؿ+z`<.!_Alvڿ$=~f Ah~Uw5h~4& 2 UdyzvDsy'IQB]H?E&u7:\I$8??=>EH{J3s.Kbvƣ⨬Qȶxchn%UAy$vM ]fAoc`6IڷO* sFb+N.65Ϸ)g oS!6xBs+i! ړu2kݲ'r;Ё}eimJٵGFVQE 9BXjaFN6FYD/3̜2J>.-u?{kL8Ť=4|66ړ^oʹ0*m(bi-_iPG'qL>1$?Ӿ>e;Wzڕ6*u|@W)˄N˩z?)W)O OХ #JpJc?gY??B?c۟DZ*ʒg*u鋌??)VvɄ}FC4@; X;gy o0`t\RLkq9rsA^?G0jԷBMPI"||en1x-GJNјcݍ$(] s秪0lCoj@W\*;UaowP~kC2JbE%Cpa-X [YI%ɥ@m<@ >C%aXjWRL-S#472V?h.+NE_,C*?}ut&_h?g+f?&H}b%whx?#}ôXۆ>As~ҟ9gJQdkbMx̙ҵ hl8 ($ 0{r_qmsnm{\Ԉ gPm d/Z.gs:U|ǘ@KJGbu[ya#qii롵AON2i> $E?/S9% ܯG߇$nRrRl~ ' !l%:c=E_gseݏlc^\`rXtBFR0{-CWw=^͹f Gn#vdAHiQ#>®S0aCa&ZϘԟ?V^lԖ@y Tr]sKNh>&f =Go^bD(?S嗢G8[2~cצMv'3@ѯ<95F ľH0!4[a$#GPǰYضo'v Y0Ѭ~^=w~aH_9>(TIdEdsXA 9ۇ7x9@K>Q ̇m{2I!`l Ϧ?Fs78[( =p)7,R KD b R="ؗq/a@{}̇^xt@E^JӴt &MOZϲ~Ԯ/UBOo/h:Dnsthm|lQ]Z1hm7u#8 _ S|L$d Q/[g7OG,ϧcv_xa;?0ִI=i|~(rwC< *z]0(/tz1N$;an{޼s?ߖs}a~[>K[oZh@?ΏG_c _3b(|_`{IY!K3}߅ Γ\KV XB쎤cSS60՗/NHVh&A0yxzP-Kc{xHdy|i*kt.AI%X(Hu3` +9ʊA /I5̖d+P GxE:!؇zt5%S|{׆2-}?XxZH4wUUQqd#}xk&7bȓzK WD]z#'9CהB'zEǠVPIp M 1-{FWUEF۟M/{>?R&x!Xp?ec2!yP 6ZdTx=?P };aGFI! ވdCPh>ݣ r=~^WLLjY/ƋbS1[+aޞܿzxy!VAP!keRބ`*E{Ϯ[%Uf{B$K1xihJ"i;7v 4R%V*{>%z\__YI Jd{L]hp7i/LW 6=0/n @~g'\T_Uһ=>'FvޟoT1L?ǧ)zwM?\ twx#*;N(DGM3͝Z˺R(~Yo߹gm#A}_[/ԞQo0VOo/Kr~kVD|Om/'G*J ^Ms=J[s%nZ∇4jĤѺVRh^_G?֎1ΝpTZQEe$V *{Rr5={l}x)LSoՏ\Cå `Tx#1/f`MȽtޣ'镜 Z/E7|[`^$heZv=ʕ7LCnƒpݷ'[;ٝd),:/3*í ݿwfRknBټ7Wx. %BX1WؿںL{Y=r0!yE&&zIOi?dGS~DJ~K g>guO a7MJTJWþ?Y6B3П3.F̙[)tr (Tš^C"opVJXlbIѭ%P]eۍSs_(]\.3QnAGڗO՗0??}h͎gc4ܫx`Mǒ__H=AUMlNe0;^S*)|C9:īi_WN*za+n5l>_*>F| F{PJjM, ycxzBpEiCnU#…#SN). e|K[0_jnW55ͦgwl*zیM>dL|N! /҉aSZtFɫ{m,l]ۻ>4OI$pH)RA EBTphQrTK !"P);8v`6>kݽ3u~o]aF{?giff~1ί5ݢw5VH8[0 #@0Bi^*B$^Bz>?>xé%ׯ. 3h U=a [ڳЈ{{nlX?#5d)$*iУ??7U*߹֢ޱ8t&o'&I- ׫}Lx 8&;W@ g|Fu;ci[YIł/tickYA!0۲"Zx4OcfՈVw0pF^D :fH}[6L:me0.#G4#WqO9Dm! GN3j[B7qV^Pwܸ`h1[檊H~n n9~3yjk:7(_׋3bV6G'*G6o!WJ%` F!_Gh77v `k;\#u+)$8!swlyPzD/E"mAteȊ\bj'fİ{ƭieܽ}[4LlKZY~>D3{a (GGGnK`qbL<y0] 1eJwk#nsoPʈ}%$ BH;/ʧ%h h; 'O (Ȯ7ԞTs(J-ySV <_ֲ*^RUqG'cAc%Wnx>!l2Wa ,ZX'yqt5 ֥rRYPX0sf9 %cc*̷'=1ُv[ӺOH2??M$/`OֽӏzO ENl֏kFzQ7Q7!+}tP";,ĮrΐE!ǝ9Cq ='Hq$ +Z}-$>H~\m}Fuanj齘?eW}?߯G3>( ho=.x$grg"΀X05^z -/xfvQ×9sq )`Ԫ9^=%OShc+,w}>'MO9 m'AԨ^oGT'(wyg:>7앮( D1},]W= =![uP=//bjOL@z|s?zxw8M׊:RA|MF&25TPYHz<d~S6^y%8\Eʸ?CsAJ3+EeV_W1z~:#{FoϸisH{}k=ڞ=ͯFFFGG6FS<[F|fc)T")e]e}PVF*jDSwkrPˀ!?x(g47 ~篤>e!R<~\Ϯ7T,٣A]A22Fw$K{#Je=x^~A?p:tv_1v<֣iGj.׷+3 a>+Z;~~9oͮk&.$l_&?$昐9Fx?? I|zFÞJR~!!Dz-Q[/,-9-CA;pgw{:,õ =aNe {ZcOBadO`xB;UXXT{GGP@2bMdz= ^؏'{=բѷ̌P$fmTk+YSٚOtF> )f\ܢl1ҟp3i矓lP)E !"  rRDcn0:z B;['[W_rxUB¯j.@X Ji+֣#i<3J"'i W8z,dEуbW*_a Å!=+諢z{p=]ogOIv=6g 6FGGH ^wIR7~vFеbp{[V7KCX75hCw~Gٚ[[I>f>NkLJ1xxjzK@4=,"Ôp' {ڞӔ=}왓1k{:3 iƼ&{:ٳB:jKp/{FGGefѷ|Cu)nӹAOktKL83~(>-LTd5wkw4PX3j$c_>vWT5Rb_uY%/ q~`@BHoBTtl4?!' QQK[OL'KEx5a-֣2 _t~ 䬲~w$(I~hn)kW/Vn>rSՂGXߕ}~ܑ3dUH}F-a'h@I]{-p9< Dҝ]w;`'4mO q8!wӪ=s NH~|PҞWi&|]sGGGs2 /?ӉEC_?#ܻS@;G]|D)] ҷ>|@A@,%r}¥"C| p@Ͽ~D~mfzpZޯnyDMsد.ϖV;c7`2X;RmϷϣ|J{Zdtp|oAge \=B9{Z>m56KmG)~P`>g+5pҘ dC\m~F@W p {/.0m=iO@$z&b{gXH,+ 3'lY QeS,8rGG驏Uf%;"зe9~х>EGCq ,w_w[F4^[BxŘZʟ8Jɫy ;߀$$gjHu-':}P?ZTu/sK(#k6BAFDŪ9fk4vLi҄--V utfV?3_ij^JeF~Ԥp7f<2(E/ #"J_1r؂I,¨XlY;pSbJ HԚeO̞\G"k{ LuZ{hXF v)`V\@+dFG~wd2竃uuΕil߃!"+}F5eh3<mA6+~ g­v֙ ҞQ@ ftf`ȦN[-s }H_cut i|~4pe^:H*H3ϟ~糫v~Z@_F'(\+e5ևF+Su|)7xpp5UwY[WB?2;6jSRx4X$4YG'λaF~|Co0'62 \t {jOMnw9{()($]3$N\`>#{b>sFs`OwW7lC:"fGGi/>*gI& RDqW) ' (C`T}>.]Mu@Wգz|{χܯCMQN.чȅ7o28K})u~/a+Rk BǞL~Y:x_F# ҰN+;vq2f5R|>'.Cj8]^Q)t6W,Miu~UO7]vɛRi:HUX}hbq] 0%חΞNyFѵIo'nؓʅL%IL6]۠3D`ZQ! Eû~~*Cް5#s@c]bMШ9aF@"5Bc&_'dkW3 I4TƷXDXmLḬwKdG"k4z%oJ߫~翚DBN;YcZLaЁ.kYqh&t& b9#D` yBX{ `)V@m;穾uzOW 2'2\֜w<8$T/|+ jy12f)ʞQ''mAyBadC/@Ƣӏ왙/?'ҞVYqɞآ'xY= I `{ -A'D3Ý s H܍"TM(Hs>WȈ( ӭ>?鈑vC,%9ܐVVG&xH+&wz jC*H7 |f=3Jvԫ55#"]wA$<_U odHbu[A40!& I~A$Ԇ&PI?]x,~.>hC&e!vWܷi?Yb%|Lw?|<vkW^Z{FsG0X}~~aWp3ߗ;̈́t`>6ZQ/(5nj'5<|04K8r1v>?'N`劫HբyHw !'-5{߯Ω"QН)~M ~]wpԜ_V)r8 S/gpn?}3  Xb(_DM9t%5‘LdE|Ajy}"ۓž*_X:A K=`thO/]*ݰD(2{֞WWT訔_SM?lYzߢPBzɋzͭ.C1GYP;^t+_7iʤk_I-*ďzU'G(GˆZ'sΝ%g6rR?M Q?n&Q"/`e]ہvAR@TOJx/m>(V tüS"/`6/vQVE:n ZA|ˆƫGj9n%)fCaIFO!Ӟ0ٯtR0|eWw(±/Ẇ\IM`@5_o?v']e<(͆&P -yzt~˪@yġ7X+!WٸqC9礫75_l)!%xL>kr{jj(*ȞWH@R6Y d9v.Y~ b)\缢W+" ]3 K|αsZy+8uL I#imX}ޤփ8,_4kNlڛ-D` } 8Pm/beQ%MՉ_"1C{dI¼Iy>l2J"HX|(IGŠ>WACl}-srt}@nGU`/7 Sf+%*`/ڰf`4)vt*!IYw%`҂4icwXIX-Up&{Ƒ=CqvS" =Rʜ9~=$C-Eͤ=1gܙ=w+E)efQ+10X?)/(L6p+WrH |o5"]zxI}ٹ nNNWv}bAfC/Yу=Wk }bAn30 fmGPJs@;d,J~OBnvQ?H[kY>v0~Nfr1)P f?K]xN nYv狵כ%:yt_*Kk=Ove% Dv*z(m) i)„Mw|qGE-|Ih xݯATp[{Ξ=CLB1`&{'cxb{CYkϝFf2FGd0.wrw|ra^=-=B52Tϯ9n<&&xܞ ؞VCgP=]bO_wnT,ё-K A*aɕ@h [8UuD0.YĨߋ6H?N[?m:+ ҽwfʴŒQ!( $%B%x\@0[(Mew$w"o)7\fl-6D{qW5Ai9hP@X X?hь_B[fz]~C%_uU\}5 `f|.k}`]!IZF~1[ŎRb{̟X6CJEQ?*i;_h;[?;f!jp=VS9a(ΞC`^y ܅ߞ_ 7vV>X(0g@@y0ҧpzx(hp=L\`>yG jbՠNk׎#Ԍ\nE#D"n&/?<_I *NpM*>C*= !Rn21@1Cixj"hBj t+{ wfOml {ZcOv>^t惴ݑ=ݮjK[/{FGhtTJ}ӹbX^k4BQ9O# 8?J& O1h64@SAPCh+}ܓQ# Vn:N_ׂ2ZE\ |6 0B 7Nb>7!q%F4gD3s0Ypu-q[}x~##Lß (0_d~L ]N0Vx&5Atq8ۭ-c;F\i^ K{,Prw 2ƃ|iT}]W{dA5Ũb +1<7`` Bq~nfW]az!Bt!nr\gL,.fYBK}뿯]dM>6χNG^~K}'/χ#y8>!O~Mv8>y>{/ٯz41|kЛg5\og/{Vt~s_me݀~F;+̇[SzC='kz{G!x7]Q#N`Ńg:sH"?5o2!m( $'3О91 Zl3A.g!{Bu~fG9?MSD{ׯuWb )̡jI2?$QbQIWb:P5Am&%TESo$J$%h1Dww:]qH/ǮJb&&a.#;AƢK#HA;hG~g&}#xkIP)2jg;HZDF^!+P8 /}}C{ByэIE,Ba;~ӟ. bx"J+T02l_@䄳4⥣Afw˞. {ZoO ́4vGΞdIaOnfbaOh e:?q}a<c#rX7q 9M}ݍ( 6kv4Ih9Qqr|ᜤtCu$e{ˈOr}봶^qptz|y|TfNu!~un[G7{1W9zȖRx~$|~d5 9~ygt> 萓s~T)ukizo8yD8H {|Z2^,-LCgq=_b! ʞzdOSgrtaO#{o- ) jiO;͈]_rHbC]Ue)W՜v.<*A˥1].ӯ?گf<]Iӯ&a`޸=qjNHI}m]esoNtvZ<$DM\(w\lo/?"뛚*<ۍb% \~+\m̎tq=C1~[e?yS[aC43AihOϗá~H =%!we?`4UdDדzwty{F_m(ht|쉃\2{}L٥~˿B6|HOҞp4n>yUM ˤSTFGS}12 aQeQP\=#wz=2lx_b=B"Ywo'氳vWm2`Hi.^a%]H7F/˒#.EKh1:E Ԋ ݷam΅cyS*؎LtDlX^K̊'m5`F5*8({7jy]ޡoX_[}ßևɬtY!ޗyB:LÊ9IJ"Qt- ~gmѫ%AOAPmOcpu ^z㷔168ݗeExmk{FkO0boO?]bϸ؞R惲g95Y?\)3={gQ %jeQѿM:!bIP[5%ݧ0Le0X A >0~ɯF u_ ru(GnS<^ڥl}<]/?5m(:CE4X]05x_\xY7*#\?Ժ 3ӤyM9(<PH~a~~{~I mFca-{P .b)R-^NBCDu_,V.'IB{n5|=ݎ.kC4{œzK{xlv|?tU9yUP|ߎ}Ε P`-AŐ'N[U߲GVKkUBeDeXFrϏ i▴Q1d ) 5 HpəBv4(&z[1;zpr\AC%4{G|ёWǶبmVs&fZٞQ> PX;P*c~bP#ٙ$Go[ _)z;pFN?eƹڲ&}=Z}Z #yHh WƉ71?2+,6Uu,O% 0J䎪@=vGDX e烧0t|zg*/idhSiڞ8~gޝB36xۊA'>?6A!YC@:P1a\Kא6B{/M#{[D\ybSWA? 8NpUq?l=i #_>`>tJ|ޞ_cG_h~Psf mϕ)Q'j5YCqcsη) _[əDP.A]Smb0CqW ?G`h S`Ȋ Α-Oh8/O ,3h>Gg܁i0zS<}}s_[ɚyZ;qR vujH/Ǔ v?1nq:=rak!-rj2zHو4hIojSh>}7g/bՌ<"n>Dv;|[7ydz~FPetQ$vi0 ]ZExx0nlMƯ[37,`Og{= ]nODp=o5SӀj[_OSz#{񻉢\ʽokOYiv%h9iQ+U*#IOE v{`~uhPӀbJod_2-<mu~`r\O){Mf[) *ڥ[}Kw~ܫd'3 7܀`{}: ?0 ~~Zr}\`@\^ '>kAk߾)O:\֬ZKMY~BM- j>(گ`8lt+CKIw[]|`< W/WpsDr7S?\∗EI4TL,AȽ+klޙKB4s$kb?)hm/tگ$ڞv=WL!=2{ڞ} EI z^zL`:?=*w=_>^s?&,qmP^0# يv/yaWlO7.-dO?gmV;Ҟgx =N}C\bOrĆ mO~>P(^pn??+$P@+IZW&sLNr$Q ֆ. O릳C $_I.K%ܑaJtC-^/h$|}6; Z?G&o[;~ +,(B(. ͛ba>b>1~wLa^^7`z<뽛 o/;[Ϭ^N=uo痚nX47&{4ezx~?Qmq/0VhjpBwyWsxY*e9JQ"gw/5{p\ $ ʾٌ'i+Xv="{0<{JPt ??9Ut0-V?f[ǚK*<8_9n1G/2 7Bko."v-'<sLd*dQA o!bn4ou1jړzG[;Ϩ?w`hzG4*oo&+dQ&D2P;nj o ^[yzPKfV$޹3#CNtkbԫ/T'N !v1 ucO'g{. \#3]'=Ύ,`{\VۓlOi۳ž.>B?}7ackm5}L){|S2! "AӖr}>?o[}Z,5顚o?l/JUE~Lt@0G 6J_6=p97~~D K6cí_{Ю~~lߏƿjÅ{3k"z=6kz2K48| 3n~,{6V XܒZl`OBOQ 'c olNt(IhU=Оvk{cwY=q>Tt)" } {3.z83z{4Xسq?/'N–!nHG8Tzs8D <9)⟻\Xi(QO}(xt^,q]'K VT~h'i.l 5'w og;ބp s% lEUYO)y L&@7qQԈQ[[ e9I_|; ub LEdw&.~ҀV[w@L尣 }k:_/`c98{:]lY\'ҙ] Tߎuh#6RM(;Ss8/=87:t&`(.Ix ;ĉz?w!Wh!$~^fnxlO"mOE]=b{gY4~ p>vdXi~ZcO8=!\M4 V'[|B_(z;~47sƶlv:UvY8DjoZwzIfbK^QX F/g~n,-5ᣪCPavH7@.%󭎟]jB[3BhE ]r[CcB)" Ɵ;blk}ZRF|s+qL*2^6BgzS!w 9T'wQd@Vhx~|_1\AWEߊ (it:yts戃6EE𒸎}zw'RHܗ/w؟x J؞QS{Z}EtiOuggO/8F=^\%f ?Z`Ue+| W[;חرBhvjHn)ZoYc N~}ʙP6Iobo~xG^`,k}@ٍZ>@{n"aIZd,;x za#7 TkpCϠU㮨'diײk)@7}~i>X-T F%:kc~-pѳZoϻU[_}Sb[nmE8\G<VF=h}կ\_4z+X=y`+XM'=As13{Omy<n9?_U]Yb0Xv2?Oif6tea[@2UP ԏ o+{Di} Y )2Gksk (ZvUyjQFC;R3lؚ(+C̨-Zj v[ZЗ!3]J1ے\49<9@"a y{O( t^[%Ku{K3bnN0fms^ Fg3'Nq.0 /+P|hI=or>\fO=_V'4|8=H]!yF4teGr2)_{:POPϣ1 ^s̠VʎPA.6ʎ^_fڣ@{^S0E[B1,"jqey2ݷ̨cz{Fƨ7C}z2eZ(&]"`)}Nwwekrne*Qy zcAm\$C#Jp=7ktc 4R,X],x$`!Kn>.CN< |Ka ߅]Ű@,q,seee.%:_m+?׽[S`OWw9 wSχ[seJ{c\:{6㿪bq+~~y4+ϘT@CK,#^Zep^f\\Ԉrn[Z?H{M)}٤}"䯟rb1e*Vu~t=̇۽/cH~1 pPdqa$7^:oO zO8hE~SRWrLn!K _M[^~7:wqHVSn52 f1 Aν-XW`BǃYx]VYQCykGyŦ =>h텻_9/ Z Uo`O?CoiB#"=}mOJ)Ξ N {>8۳{8>/3ڞؒ ;͇*)0/?Tӿǖ:UiK'v9'ʝ$,O"5nA\j}KN˨憎[ex|&A \mV6L=8m] : Zu?g2(A܉F=WgP!Чtyj_dBD($B ecvv)d\n[_y`4 ,%K׭2zLQh"`AYWdQ 5'nsF4:m(wI74wVJ_b1BUcpSΗS5yW9 Ts9d LuC8?Р83mSGM`JWX/g\bOYV9AiY^p)"Fiv=2{|XO-{}=-.gjO>Y:Uv[Q?TSCkέ $ %\–ߐَ7xU\-g7摾cѯh=WEWg&!Kw|,Ą!^qF t@B'P?'wt#-? aP?X?;>o~H^ sԗ!W^;m6_ihƣ@qp cOtu/ϯ -;&Zu^Yu#^rᤕ>:HTۘ1AJ.Dў}bK /퉜5$=%E3.'(؞vhO9=Ӕ=q>(mOC lo-󡟟v=h~Z3?mfnoϰ+A?.jIe'> 0c}z}3`)}7cͩB>[иJ LKcȽ h]h158]ວ(iq4OhOwoo&糧8T}~v~w[qfsԇ IAԬeyJTRPan e4Yh YC*.$^;OtB?ZK#o֯=+; }3_ne\8MyڴD3S栫s h;t}}!? VY)z '0y^.S2ƞ7ՎѺ8SY`O@/dO(=Xf>ܩ=7=ݩmriϲp8B7|(yF)]s7b_>>|G//~>O~?ߧ~m{d޶cH'n{qճ| >Yѳ{ɽ^Y}޳soI~X+nµ郂]=v_Q2,`S{ #k'{{_ծ=>4thW{4nkς9ݎfK/W_W<2ߪc!Lg-t\xxZ6y4%g pG!{p|:(ɏ==^ npiG]}~?||_9_//zѯ} u=~.[T- X x ߮:랚زj'xoƟ-uocOŲ5d2?wUgz['~ozhΏC{}җΗ?! aQYd^:;RK~# RR;D.0@A$ T>T?c{f<PCCѿK|S{ۿo##########w,_~^5/}o< y:H+1d3ZAy E_뛄pUj/`cj.'Gdehoqѿ~O?ݕ緽ů/?gd3(4Ÿ?/`ʍV<_s1⶿c{ O*{ABF6Fol>7U?ַ<8񅑑X/}+?^g<=joEefa- `53tHï21QgJvG4F4X95~Оբ2=sWr=~dGCXSGbdG]G/|>8,Ͼ瞯}_y^gM6ְB[JG&w,D&_S_ _/ʻɸvL-ȝj|aeCڈ[ڳ@ FlFcd~߷uzGFFFFFFFFF>{C_~ٗ>-[lZ+hs.}Eg=%ekX3thĵ==eL@\}>`WFr||x}|ddddddddd %n[>~}{fk0;b%@ u (tG;O7c{㷦\B<Ϟ+늑G*}{ddddddddd .g/{v#& V_&6 KRh3uYM`YCGy<'@Dv|)ӎ`o~q=imj1? ޴ adddddddddI%W?ݧDj A[<Yk IDY1єF-yi#{Ѕū^RH?M# (¾??{l##########OjO+e/Dph[,[Pd?_ `*cda0c.)ٸ̞S`ىTm,ȞD7V~l?CxfGy+O~/o @O7yiзDݗH/@N5 #ڠCwjaKgFy=hH6TI?m/Ƿ|dvᑑ|g}/#_Eϼ{}ϱ @%A$Y8=hv9Y74 DM E0EsH=ӀdaaOU; RđO:n#m_WЇfy=9~/ \Z6k q!T!8K^}D$V \~yoiO~a3A"E){ST?bc-U?CկB_+_WHh9np %?1_8 ,/ |]k .O,:5}Rt f97"=癣6-?5#_[̷vdddddddddi++į ݑz"{+'_M#0A*y{w\/bO22㿥=wÞ PFbZϾ}|w-|˾|/ K_tL4Frv҃PTVܽ4Ht"HG02`aoiO@7׽=O ;ENF!"cɿ|wC<2YyuW>+gw3rpfyDuWg^D0yA?$ O$S kG_W: J' aG_OmzCGFFFFFFFFFF{ү ڣ€k?>: 2ή;g,oܱBx T@Aϰ=Ody L'>s1I~-̾92222222222r(_ʯz ]'`B<|CH&ecٖ}Qx R)1 j=94ɈjXR?bc?{}#6ȅr/s_>{@&xOivĻQY<ݣ¡(կ:3nݻ6LLul>Dz<<p4@SpğW?_؏~⑇#;۶?&tz@|R뱗D&bH^t`Pn;9,P yi N84 lO'{)a.ٙD\یgX?" ^pafov6'=o<&4\!/{Ja@cHTV]`x_CP!_vާUrVa;1I=P,bۮG}g&02222222222򄒷cuT=qW@STS#Dmpr8[j%>ApGENaD.97phqb^8Cy=ϱkyb(#SX5G3Q&wGt3o'gy={#w];;q ^^SSgz z\a!D ьQqW=#iKd|zyߕYwɃDe11Ne#'71oFFFFFFFFFFFFEz۟=mD;A ~U0JT"SgL`i?8;lgtkGXcpQGJ=W +/~ۨ?ОW ;G3j-ZPӕO|WoٶFFFFFFFFFFFM~+Mx_Ss-eS9SNeDscO~x)? 8e]> EA;gLd @ e?Rݔ3}{׻fyɯ{ ^|n 7+)#F/Ͱ\PZ$/9/G߅$D<a{$Kw=-%nJ'*b08qn0q*[C 5)CM_ueyɏ/;>k/73 L ß2Ngg(eQ9)v&HQiDcD24B`-t )RHcڈ" ž 9&lbG1֏g̉"m{>١FFFFFFFFFFFO~Gwݱm{@;d?b/H^WG"UID*Ls [bxB#3BDC l`OuٞjɞWD`=#ߔ$#_|o M###########O^77~nHk ?;V4w8זLhKLKYE`fD &J"#4z5cnvS:qFqxo@=F׏'6q^_K'fWyGzk~^_oXOTl[J{UǪ5D,b9S?`qry #?=`fveº:2Dg ٯP19h|aGM.'P񊨬RGǟ~ 78W^x:)3=;3YvB4Z_XV4Fnyu'kvio_2<{m)'E`Ԕ3-BO= >!aw/ƭ#K?"YUii,L5 Cá=OڿF)|?wIq8z;E0~2(|2zM3S_h< ;Y1c1wQF('>߀588l8^#3f8/*ze?rI"M@M |3yD$ KacjV c?oc1c?,l0}^ZgJ/RICX=K o_z3Aۿ "%RbDֿ9"/᰷^CǙ7?]@'>M1c1߼O=NcH@֣}0u;b1c1ǟǟ{,KCQ8"\.P2q0m提g|Z?`Ϊ @'3eAV ɒ/!iC_`G8\OUUC"mE}s?O_c1cYgk/ 2zųR)QR5PxĴQ>L^?&U  hUC,!g_CJAmOP3r$SROWܻ".Jߐ ?zpJoK/'Dc1c̍Ҁ}wd˙;F] PŔ RS*cddC2e 2fQǐRBeŊ-bc`_1 BHRhz{MCe;}""{c1cÇǏg=5- |JB.ʟh@\hLI|֏ƄQH|XQrA~dekg Qc'\nã!?$#y m(nw1c1ͳo7diuDcfAHd DO(JjCN.g%KLLݐ/xZCX=֤މ'#ӎ/~S3/1c1/_ӟ7zѝh0\feLU\e`8+I3r2"s!$e?z"R$gw "2'LxߡIl p&YF"O_~+_c1#N<hLx>4) z0ˆq$ 8r62Ő$?`&9P.K="H7I݌Hry^"uFrcs p<+^|?c3a1c1G_g_9CqLQ avcYX=b1`Lj%y 8Z&MOsO.i,|tphIgW>ϋ"ЬOXDD!Q ?_y-a1c1?(ܿ7 CVU~wdZgE }rAjShHa|cu\sSo{/gsg#$k3p!K?ERf\h0#D#؄apO__B|7/"Gg?/_c1c_>0!Oׁ>6! c!@"0 y)+#Ҟc<=Q*(4x/4/)2ߵ佁e?]0c1Ƙկ׷Ȝnw_Qsw`w\2,h6r| 粇$ԉgS"85cc1caxO|=BtW3rþaX;`ُҕ@ (P cXHm= )`FTlaHng7 7iXDxFpZBq c1c~x?grLOpi0KS@u[4DOu^g975Bb/yKSJ!I̋M( H^ΣdAp3&Pюg ~'?c1cQO_{E  g~QtOO-A hD ,Qq7|ŕ@?Lxe3 C zK%R l GM߯ٝ aU8{~y+`1c1?Z~K_z^q\>ѭF }G=vRg 8FqȥXBA$>Zr:2,͗$Is(Sӯ0\4tkC5~CCcŗxc1c̏> z-qKhm덙9\@C@4`_( smb&D !ǝR$ԧl! A)^ՄNmC/UA Q' Mjޛ!`318'oc1~U$2mPU@){(EhC-$.w'@H%4ejX$ y3-s8"ղ(^)3~#5ڽ?'c1c̏?YY3d\ NUmXS*/zETo(qtRof֞@9rx!1Q?(6z/ANX֏3_=1c1lG@;{#'h1aθqy,j'`ZMћ0ε$G`ɂj}R$ჭ+)n􃑲4JD$Bc|RI]^( 9UqvNL/<~Sc1c̏=/pγ(Fq8O!r$2ý(?*];T(o|R} jL];с8$bB L&\/_ͳ9^q3O@P )0 x ǧ5F*Mx-q>,/c1||3j"fnG_/>Xd՛t{ #tF:C[bg 6 e?PA %;8^T#٘^h mbY񠵳?{_{n1c1O_٣%hr= ǰ0HN ,\(H(&'k~bhbHUa=IC{!tB8z*KE*Rg(BM?WOw(cG#CV1!g~W_y-ɍ1c1ϓWo~?(qkGi32AH6dv@'.fmdY)@,ˆ*bGg'Ȳq gJG(`::D΍#~H90h_7^z>c1c̟??;C4@| 妳p4׃+׷> ̨"(LͪWZŐK<{J Sqg;p$mlO D5tEx _|c1~+ϞM Tus=l8nb  NTQz ֛dKE;rO8ALɪ,!lьMhBP>9P]җ~~mc1c7{1 fgAyˀGe>w=paV3n"JQL^_N5%HЃ"4adSɽ^>"J la8'Z瓟c1cb;_v42du!PϏt %GLa Lb[lEI ԌL݂F$@d0ċuPsch~-no=5g~3yO믴1c1o zAF.b MRSI_L2PmjP2CZҏ7 N5,'xb1(Wf{KDHt MPz(_#1c1|_𨮁Uԣ䬨M zT`@Gm`hvyX VI5_('(0e`( \'" T[_OEm98[>_c1c> |w>=<yxCRrC LyG*=HX qor~A$fB.7??]q8;lC8nq= @"COcmCa8&G?o1c1|xo|QY4BZC6~.&LŘ9!UDMc&?@ށQ =(o]`G=<A?7s[,S^[DFɠۆ`xx Nkc1;gH2WF ǝ 6=P[ P͠ϛ!֌6 @yWgb1z,s3 Uqx=Y#".4t0?|wc1c>lo~G]ׂՏh="4u?"+pJp_CRƊ}M@`7uX||?*pD 2?oh_>̿p[f_Ͽ l1c16^x_:`ˑH }tׂ}`ވάS]˃ !"fh%T> I U6K1 6d\H<%W+>mA:M(9k8srx ^c1cpO (EwA%8;CvFGcBfmgF̖~#ZR $$ٟ" zQXM\ͧe}u8+{0I ]z G ?7_z_]c1cpw/ EnIg A~|JAz86}h4_"@C Pc,F5V3)r&t,uЙ?xA'*<٢hKZcyZ?@4 ~75c1Ƙ3{9΁c.>1j):ȕ>d,}<%A'(/oOP?~>BBńr`{f[""pj9?g4bׁwpUuGLehz4D췞7/1c1|LJKtDd,DP(?4J,A"6)w׿@n0z߁D(OHA'!= 3dH WCgzOC79#]#Φ4>ng0c1Ƙ{9$Z"ͽ׍ yY)j@S2~ *Q ܠ.(L{,h NB ['s 8s1=*#:yXφv^~ c1ċ_{?zw&F̩9,s3oRv4Du,op4@SUYm#ո?26HA]ܳ]s<<A"6Pq4@UBa y45oj1c1~"y]"cwmIQH&ڡZ|= {s'C30$5a QG#>-l$IJDz}P*|l(C&냚FjiHQ%sl* 1c1|@/|]Ke^IHvIOQ[$bQ"ɂFH0$?e-  ;P[VCY;)kOzv0-4gЦg=x6c1<9 GZA 4`)W_qqdÈMӫ13 SOP #q# ۈT"`IQ~ K ma*T6 17սF{+C9B^}m91c1ȫ|{;5BorWsYqbS^kZCf$40{ qdk8em!JŭfEk2pRvc\OKG`D]4f{Bd28dc :[iF~峟7c1c>K/_1+G*7APGkDI""h& !"5('H^(8 v(&0 -C' ]D&Lzzf8Z`0R'}_Kc1cW^ycCDjz$C ?^#F!Ɛ3!Ĭ= >z<]B.g/TO.nβ7Jh?2‘8ѐHQ8#t ~/5}_z-1c1{cz!sOd#d3HH|ԛ_א$Bvh5٘Y: g#8>@=>OwclcZQO||wl&&?W$xߥO!H}fЌJb9NU\vqh i8D"> c1c^|a 65JpJN9.aMQS t )~P˄>X) cc8*Ezjk?zYx dH-SNɩo.lR(0\9;!sP{?]CJ?" Pl.%_iP ӈ4\TD!Ʌ~%'"I2`D򯬮WEivId AٜP֣堍Dཇk_Wc1c~{|rvz(VlFS0޶ёI?z=B*1RL\jDP%ig"d(]>Gei^ɢ~{`y:7tƉSj|S:܄1c1<-o?vC]e8=Ϻ<$#!)jP<P$z<ӱdqB\BxѸ!5,3I^49"i`L\,[_ŕꏠI9>BzH;8~*nSkFlEk 4c1ƘzU ;GaFD"ܽŬPr! R HZQ6;CpΗ^0闠 HcIͰ5;yC^ϺE08l]v ✚8p&\gé6Q[_`1c1Op\&o:wn@dYƙ%@FE1$LF]p=M=~ar$dGT#g}Ah!τUOZ_:o3Cf"$pi*0K11=k@|嗿c1cw޻{"Y6=~.A1tY{*1eJ(8KI]S;Js?!c 9Ezy9J)5rnAH'ΠJ~29fEF@4>Hr::m9q~ Ts2 c1T[Ӽ/#~M# !Yϊ'Jp8j=^g1Nwͅ6.q AQfQ*@UI#g%QFw 4m{]44s3e}vC)=l9M?)]?~_?c1cy ^=+Z~ 3]@Qk5,FSCJ  1wxg36C.}3?"25B"|MLTAdwqu?qv4&bv1z0bF -vu3Ł^?$3&b9PU$[Zk>/~c1׿qklKg=ZURˌ/#0| G8hF#)#''p(3DHa\]UqȐ^,9ƒ/R5:F6&EecpNokL -1c1~k_|M N6*8Ē3)Y+[W,x]mm rCCW"#".Zd%3}C BRtƸQ+F\>h &?("F4v4އ>c1cg|, %2wYBF! k8?bQ-2gKH$!\ɿ`"䖿Kz .JDa0rt6b˴EGX%"%!~AUTpB>A 钹 1~l81kfo@+y<8*1I4EQALЦ,&bWr%Ϩ AHfP|fs{qs3Zk c1cr> 6'f8`@6}!>egG/AEPteտ9' R$xV/1Z|2fEF :Y}1 Rj!,`Gqe?A e=/gC6y|O믜1c1<|魷*1NYa }*AWsVb_R9̣cbw q;ss$9<$k3ϴϋ."| JV݁]S&,SӅ).lGDGBehIg%?z++g1c1O7ݻw }xpFW"lD fUARA6Y˙jChE遘2`4A`zU^M;ҕ*ZHڞq>4ˢa^}X,eIQ8s+t)Jrk`eXA~毜1c1<<;F \dwG}a5}L*!=D1%3a'0PsG6SHq]×І:gV3 `Cq FTбkSоai!"G99#'oc1s |w}4 ճY jU6Gj[Q7H:EɿL5wؕq2/eD<l%G qhGyZ/T n疌) l׏ヌ7Ln8}q\S 1lFĤ}e3c1Ƙy<'& 2@f" 2w<2?A3aܚdP̓<1Ls!7@|.K=R7BF.SX?ƍ:OH2^BbYrw`A"jgc_c1cnyk8 {U(F GuY2kxH&5535 f!MIuRTgN5@ ȣ!A A,=-h1@r,C/X1jր 0N1hPоc1c ;G G "{ӎ"#A[fzrN;!Zd Ѥ,b 5@T󅤙0DMƥ D,ۮI%͛(kGT˺ڹ @ȐE _ x܀@f"+;f1c1kr~h2Q"psT 4{J@rԹi^\jy( 0*Lm୆^|!qW B^/) ,Α3`(5bH< #> @,l]@khХ -1c1x޽&qgF6Yr63+vlr%ȍ:>ߩP Ia8LG)i#!^$u{86SzV5m zGVeKN\LSay,4c1c {02 1 s͒|"kFɏHj tPL' @m jR:#jv)o􂼑!j.Dt94nP]_6RAC_UA69=OGH$ͩNLJ;h|53c1Ƙ;!1f%i{$%Uv5c9pxJ~YZw cv@m l9|JT[Nܓ&&ri[He@BZl |- c0($,Fz x4<=6Ӄ@5 c1s[B{|ĈI pAu/dht`ybKAFޘ;F;,FR$hIXLP CYb&DY )l+8b9@sg܌Аokf1c1 @%fbhUv/;h*!@R_ -dRDɒ!YQߵ~7_E9bOr1&JWy1c1c5^y- FF-P* l#@A,2uM^Nj$(ښl!\=JE'jRuf޽~^67fХBst1( M gJ6g}@kc qv4U c1s{&D6 =-}=`s"$rK@=F:L"*r4X .ۅ5t:gO:54BcZ,1vYeIjXXu&bȰD d!"`c1s{Bqs:}/z!jOADm^臨q1cPкzh=^J(DDJ ?ew h}ɌgJQ}l9̟@OQՋ wi1c17k34PҶ4JYs:!w֚YybBC0OQ/Qv!:B)W-qD]?Lr|,Ciqج/ #i*c8w!N{ f1c1[lZBr퉑_^&GP:2ʐYc=4@3saWƤtz/6;H ak SPu=h:׋C[?8^f%z=1c1!jdO6,OrYT׿<Ԧa#`3B!NbNM( Ue3Dz}#@6 *335K|(dR0`1c17ۏ 2~|-l@F&Pr"3ɔUOch܅ GGzV%9IWpJq(AkgOz\=)~Tm%mh%Fqts~\GoUTaN>.4}"F 8pP"Y@ɩ Ǩ p G,!Jѯظ葿`c1sk8$F r uf [~QAH PVCNǒR`KHmIk):ELLLlG_ȍcHDbh"W2Z9n@2Fezd[㯱KGfrnCH Ӹ Ec41c1<0+m9Wv3d?>Ǧ.URN iarq)RT߃X͠/f$J& {?P[Yzmm8"\8/~[Id7tG1c1mKeČeHq.kRKd]$rYGPi:1 < #),1 y|k̤bIHY(keJe B&Đ8rJq@;7ݰ_0c1c5rXqqÚmf= ` bJ XzR 5T9.,ΎAyY^հ ,[zVKS9nϣ_,WU1@1Srz3:1G21c1ܤ@ѓ5,GVX#V)g͜s41Sߔe9335OPmD,M #$D!" U]ڀP (#ETi8&x!71c1f9 WP9rDH1٤/u{7C !w9˲1 *.Kl ^fEXݧW2&HPFe}TM@i- 2GKHGO}Dk"Xg0c1Ƙ[%gf!k8) WD H/hϸP;J! EJKyeCG)4AͤG֗[H^ۏ>9lFPe+(9`n؜c1c4L FȈ#RQM"etA+<rscB7gBRDNG@'j$>z<"T5 H5XbHZ' %m28gg91`P mi1c13Dw2HM$:Y lΌ]bi5$:X0\z gl'NJ%[\ цCOPbj 3L, ^`tʼ$ @Ri1c15YN!{|! Y ٹn{bKrR@J"die^|r5>R="X(- YhyE%\ -C"c-9?"I/8EF ~Tϻ繎\|WI&Xz B:yQ(S+(M|V1c1~-ҍʇq##i0y*p˟\hS?Ћnnj@P@Αb@Ѓ+( Fd~2.RȘ@+!@ Q2hu!L hP~)CPcc bO1jz1c1ƘЫ 0'G^؅*&y=K=43TXձ8b/01-.s`$C&EqH_v}PDpCD$л0>J3;ЗmF60z:1c1XqTՒiF<#\7&ظhHtwÀʠױVhB8pDH񯮧uv}SE#LJҠGDuc1cJ swL`7 Ƥ))a6 T੊֑"1t! (1'R)FuAԘb]T/\Ye=vC* %jPZB ]x>UHKu^jC9~hdjV)פc1c1789G|D%.;fQe/ki "7@Dlg9+5 sDLH&=Dhyvщ!Ȑ;jkHF,UEA}u"J.O^2rii Л,(75c1cr3PSC:8C*FÔ7fݻ-D9V3a;~PB.F[jZ\^D>!eArFs=DmOb lyir/m"FY~1c16 zy x \bD0b3Pֳ@nQ8\0n M(u8H5ul+r'K%r=A S' L^$4#i1c172dX,q$/vl0# ?(Ԃwv(, I̳Hqd ̾9_;,=P!Wb)E69*C G@9@? 0K/'K-`xIfL(#R1c1ܮh8j˨ׂSp)ֺ6}RfiRR|L]I"bXyB X*!>`ɥ@U^1rR¿ҡ@.O ic1c]js΂~jNI"1PBrtVC.DiH3s=eOMDi(a4qU472:u3DHfJ ?ȥ@}G\_B΢&`pbUC g3Hc1c]GyhY(5R Yk,(@LLdlo'9&tWY*U$3mAZ&g4%sDbW[8âhdfr^-P;UKIXD 1c1CUs!|? E%F\7&O39D!SZcn"i籠Ń>Ն*:p#Hn>ŵ4vqLM\ )dgc1cnn 0j(S1#=pֿ) }mpĜǴi8'ž*%)zqc42P 0yu* IULC%}ahv[\Y?g"P~U4=Fc1cn9%r~ֱvW@lϔJ,3ec&|톐@,^0{ \zփvkBX<#} UԐ`1c13԰(E;YABއqS\'Zʭ-~烖 sτ6Aʠ R KFln=#Iad0m O@'- x͘1c1Ƙ[a.~#cb hm&qFhteRDb-$+Iyu q+ME,m^ jȧ0Lة`ldiJFl:~JC4~< Ϳ w\c1c$YA 1g8Q=r4(\lpaHt}Xlfe3E:Zˡ܊*Fpy6 f 2l4sP=c1c5Pl 4Tb15\AeHʳUu(FX[TE%^"˼z臈qHPC|b|,E>XowȺzvIdzѕ> \/1c1*ɥޫ1CdPJh_wM9'6ܶZh;LVRKaX>I}ܽ>vNhfyvEc1cm ZX&=1#ZZ&՛)lɵx͠ M,D}y޼V_yשIA>suN#XsL 9N}%'v 'sz ҼjaORc1cn ฉ}d .9aV0~M'EiR@<4Ѡ;JBKNWЗS+2%B!O`D0MGW55ˎz=cXk0c1+2ø gsֿ4\={n,ZWnH@  EhB!B V,Y(n$pCףXHޱ< jbŹm:]o1c1Z GQJ(r(O̗pE6v!   Io@qt{|-vgd!P%=EaPFDku(Ieic1cY"3l0דcBPGM.2grRss2R,3r߄mPށ!fp/1c1Ƙhm-roރ(-ҼϔzPU/C_P 8Kb"͐mp̤ d|D2""UJG@$ .,) uH".XmŵKVk9nj0c1ƘVz?>P2H ŭ,hT-sg"r& c?c{n?BH2.SPuWEZ]]:Ű=v}VX~p71c1)~>ҁ&Q"thUy><F|*4-,>ج+rG>d_$dͨ})w7c1s*C\32>ĖL 9~YrFW&*d^eTe$a;ᄈ"A:=qGwv, >UΈ5c1cM2A#!s!A^ y0f] M` ԁY6"tx`2%Q}gΎgBh6$k\z6zSQ͹xѶ C9D75c1cJĨPRFbs@o@-GCudqjf\qiH=Z#wqg8 y+J Fۭ e^'m>hb1c1釒FzeIdIJIGw?DE`1c1uP z#pagb;ʐ7Ԑ\ʅ`n8wksȐ@ϼL+Rҏ<ɭKkV"">s*l%B65{6\Qb1c1 ؄GDJ}8/l2__|aDP4F+ qWgPp (B.Z_Se`V~!=a=QLxIuc1c J 6AfY{bv.$#\ 3bk'we>LG8753yxǚUq(] q@8*%}ՠaUF8:-cmL c1c1 CaKv\pO8p9G:?2$qF# Q:x'F$0"502؂񃭏+ n c1ce p#gۂVc(6 %{b@vWr{?!JPa<9&&ƥ]#`bՠa8dnMڥ1c1+pKR }=1(8t9. +ŀ5_s""DP$ZH?w@̦g/Lĺ~U7f>y}y2 %nl#Y?q(c5+a1c1O2A2eAR$(RYjmB.u15-Fe Df:2[#@S@3ňasEb@HI[ͅDZ `IlP8u2c1ƘۖH-Y4 aо7(6N _lX P%Kbԑ@ ^uR5B%?5^YOJDiT;kS32c1cep<aOeI`}HiYޝ{S0L+)@dD8.ΈR Dms(뷢W= ww1p36G* NAc1c)zûܥF 8Ӱ( \0nSpBI̠XM2 >rV#J,rgWȈ}ǿ!v=u룮7c1s shk 2 x8"> )&X:O^{!p9{[ɂDfNĮֆ"62Էh<=@o1c1IqB2 Mտ`IP9. -jA eH a$ \\/v4 ޏ5tخM$6D_߱X)Wwh1c16un"!W3 ! W@> 8B`dmNz>dDyn{pߚӄ;d'/ w?76PGoX4'c1c14ch;AMh^`&kW!{RBrQh)4zך|}Wbtvu?>h]bc1cn_ƽ1AH} DHK}'՜'-oƄb lyo<9^xutCgfI.@Ś AZ;m4Xa0c1C̊=//RNSƬx } Aыb&0 ly4I~~vRϳ_fDDŽb vg~|Jir?/w(4c1ƘԦ-7kKIo8C.q, PCܼaUʆswc'9R'"P|N79JP3sg(P Wf7mi1c1fHd]#Xb [A(sɢSnlְ85HFJA>7cȐ1c1ƘQ 7Y&X->ׂ3t0 9,s)} QʍtP*$+l rU1~c dȹ_J w: GHИJPEeJ,ic1cMKOW'G@FtI%jt ׼/egp CPSdX#!\Qؙk*Hn쯩~]>b6an1c1ƘKKJVSv6YOsgMb8p& b=S , A,oWֳgDFDO^ YACdzx5c1cqx8Xu0\HdƨsO+X:(tlXNV #ȳX 8XA¾eP?X=4WboN㻙c1c)3Z9_j`vw#@-k!D.ym! H5N!.DN] Vb MH>>vY>~iJD6fD `c1ci8!ɆajY#$hlvB$@:EXmDQL'DOr.Y*1*4JJc9;ȍ{̒je}gTqAX3y 1V1c1f!@ b18X'2ĀY?Wt \v˔n?cc/tL9N}ಛngr]Yim!b0#rWEdV{sA>{BQAKӰZ*^B[ P:Rz05cE̳ɓP[n Y>ò0kV,s*:) B].i_XQQ 20oxom·Dd=&O1́ x"Hơ5e#6R#jPLW:4QC1) 2/% DŽ`OOi)VC\_ I03"T"i]jTچΡ7}Qg ,g󩴧o 5 zt1.@DX C?8:İ]G.dUf~(i:Z)Y6.m#YSb7# ^S$1EA%g{*6m*$+{z %d^V~%Red4[PJ V>ˋl4ۈ~9è"6" rۥ ?x:7F2 Kk7#a3b DhUۦKK]A(KȰ*{/2Neђ#ʚ/VĜquR2L|Cq0 a ozQ!dt;iK%گ&sg+>zC)kFWܐ雙 됁v@d/GddԷ3#uV~J# QQo-?{+)Ba _>}>+guXD6 <4ڨwVmuVkfaAzf+uB;ǻ>]qp\U}mRН|Yy} #O7n { %a㊺ 8HpEpf,H+Uy\ry_ׇe?rlq^_# !d- <1)>^&xob3_V~O߿[Znѡy ˮ"!y3bAΎ? ]鎒>4QA-W#z?K:2Me:RT/CTòp:2f SLsjkСGMq8>ȉaAg.;B"$*/T%tjR8pֶ//eWIBܮ7šzX_HjԕаLsh*˘ pv%B]AJ%bD˦<_f4_aB{98I k_0vϏ>1ig/ݮW5&`Jz<쵰.=?0B&_3,S&8RD)0P;g"LY{::̾QoZQ P脭<e(UL- \kcB[ŧmA5_X]j; QhLv(l*: B8sq,b=sǡׇ ?]=TOy>̜ ^DۋVd:h 4], p[mq`k WGC{W]#pْj+i#-r-s%1 ]${DַD?/$f:1К˥ m;vij{mc'MAr\h`x r8Joȣe~8zU݂!e};E Mx]*iC&Y/1{.RkĜKX.|7Eh3"Kt|@v}ʊ^Im S}yu}kˏ;qc,;訐0Ίn9kyw"{"@h+[< he-1%Q[]*Mc%Ӄ1^`QқK$U6,gAc@ɕ?#eƍnphgm}5&Ry\/j)JsZ2"˽:k'1CQr 0Ǻ5P2=z~ 'ǃe yP^5[jjwtn##vD13"c܎GrVV)zK { "'e4,SKO{AzkUsL'_P/ՙf>X]&䞞>GEDn,l?S. NK8z{'B5C4T7 DTTF7}ZF+veϋf#d`d`&:Hާ މfjV{CԳL2σ)5SB;u$qؽĴ<\m= wrK/X-y~ m[", iŐVҡѪ#*m?*zKqxYXEkމeƊ9R-ÖY2Q-c\y޹^e(2dZ5zv9~ m'lt[öVWaXm3 CR*w2kw:TP_}  MОr]X+F>ǥחH?/ !ɸK~hS/wbܐ: tp'HHW/J$s'I^]bh kjڿPjr)񿭗_7D1 Rc=fm\"DPI6=x®7 /iO]hq9r$[fQc?K=ϣ%bXFKx=>ċ᳾hr̵]vB2(!S:q)I߁;IC %5!qՔRg脖! z8z_#?"A/Z%d\t4YaSCrW/e;1Sjhђ7g>=9Yv+;AΈ}71r8B<%Q k8է{"."Gk@]OI\/<ۡK$qcQ35hg ?뵵]^W)v% 1u~k-B͓f\d@g{su"=Z{6 MU@񌾝# V%*H_c}^{od $cz':7Q~}4Jfj>. L}8 qcjX$;翟6Y%I|"M(B+>B !̜wk3{rGe122cuܾv(CB*%0ܩ1FExZbD2jP¨6Q'#b6V;YrֳvpqjXreiGe>f#hٟ^m[De3JI=*T`lm'|&"*q>Am Q=4>S 㩋A=!,~_zy k8C( wlڝ~&).6}!䱺!K.aC;H"$9џ:eDBΗ:sVe4Xк^,$^ 9zo y}? 5n~ oj߯8f*L:<0_dV >}/bjBW/Wę_w Wn O uJД_wzD3'Ƃ91KHy?$'z5$x]]( Uvʸц#20{!CL?fVWDK'Z:GsNmoMnM uה hM\?r~l_8?62|)o`|ҧc3K6$x_(OCuy/?,]h;\_splsxFr7; xSK񲄁W+ˊ΂\8sJjc"W1"t:a_~:~/Э[QnysJbJ  Me^`] ꏐNmv #2BN)s ݏs8Hș,ZFI:fuQ|RO}$s}SA6Syhؓb^ <[r<%|~;2- VGHݞ׍Ax\kh)TYA|fF>xYrA&_h݈Oۗm,:WlU1m)ph ic > m`|^4 {X4Z[>cC2 hNLH߻}l0eK;Z<@ZAOԂ'I4,R-I<E{BzZ4ʔ2>#@b}`Rwnkd1ĎHīWfĸ;f.fyqi 5ԍS ʹ{ j'Ol5ItP_BNl\4?7ǰ,&;,K:ݞ?jY!~Q7T."ELmcQkq㌨)w@2g AېvUUg!-~Kv۬#B"^v/э*3YicޗyhB1G*4u|ւDg+4 ֐~U9:W؄MI f/Tۋ~r }JB CB6:1,wF,)SЁA]}}w-O=ˇ_FXj^ըk}}_FB01rU O~OjqV7nhS^0/E#lxn\a7}x!gXuM=oo?Gc)C[)1R-jt hS4}iukUkPcB}\+ӛ,2}a &|>}uTF}vqrIXqeOY ѣ(?rm,$SDS&<8&48I+N?LI7Zî^Վ Ĉ>Aw<^oZkthtBmDb|׮b92xCAˏ܎ |X͑0OE˺LkȻ7V(*3-d{ zI%M} ⨲ሾ!%tc5]c <|YcU^3<7<4PAYdˤ#2zB~O\BBfTL12QC-bkxl3lvc4]؉/Qc/dKa{ߚowguVWB Rp529S ǛbvY)eBRD }%KP=bA1SH_9{vESb3 M'RFP E75|V/w0~REFA!JC󲉎90!(|3$۔|LBqݑw6da1{:>hN17,2\{N͞O[Şbs Qs!Ňrw4h Md+cd~gЄFN80%K,dٓ|ݎ+tG}WfPМ#m 5'ZsIy3"u2\%V Vs}dBV[0l׵+ۻcz0H =,icKjian_>P]5' m]/_e /GwLY"T}5ehWHb3'YFZ•R&OliJQmZ^?>pW=Z9Uݘ惰 }Zߌ7վnL@v<{ t)6Hi So88KͰ̴zӞPï](g{Xx~\~S:(Rs,rH25AYBW?Ͽ\_^[ʭC2T)1yؾx5@ތ@'(0_?b>mAwLI+cF8:*8eex@"Ȯߒ.!7?ƼCM׈; |A,䠁UgEPM"knqI%5)GwJ [S!b,, 1/M5K u@ވutUcƲ'n\l 䘒0? 7XjSyq>M C%҃K!v| iK?䀭YCjЃԂ~"o1Pbѻ-Th_fF 0T cӤ ?h(-uZ_~v1- &j۞CU.0# ` MqFq)5Z_#V""^? ّZ7ɽoG᱙Qrp#⾪QչfCKjW w V?B2v%>P=ԭ8VLѕyC&5p;M\&*"J53|>gU=1ZV/\_qƑf ԩ 1MO~,qasL"čWR>Y \GY\I+m+"V/XM\С# o.3rGxFf;ddl9Z*lr:8氘YxĺwI&\= 0"rTC9}yq#rT?wC ouD8wG ^.3FF3^՚׿{z!5T^%T7Wz+ɤypW͑!zY{ Dޝ[~XAjD|G1&6 <5cyFXt}2,554r{`ይ'~gĻLAbZ~y8 =eRG8C@h3ޏi> >N9uKkC""Slm֫LŎ8~tԝOi}8<s4@[}zZ"C:zٚr\hg2"4e! va@%gAIiR182ׯ3\Sc!#FT3`{oW[w|MFi/jz(q~:󐈑auMtS8H! oW\Nnϡ6bW2iTn}. &x,9&r)J#`֛9m`dhtrXᔡNaыZCA!tS2w S +ou̙=~ m}QaD>5oʭĐҎ~$inXya𫧠WeC{_Vo& / %6;ܵpi1ԇמ;X>ᕿ -:gcݩF+Hhqޔ'v͚V/8LITZq2?vª򎀣́|%IJ;HQ5a6 kJb>tL_1)A (%/čb㆚/~cnGoVvHCS h# ^/qa#s:"tXhp5NsbX[_20qc6 j\uvyGsK;,5/pOP}va~5Fu\v=}+qѰ#C@ X ?9:֧Pe"vZYPx@֞6 ؃%WF]Mɴz.h6TΰuH:I K)u 1.\ǯw²0ZC :H!]|?UK,Цct8fn7O>%QgJƊ8oEԳ f7cDPO$Zj3$ 2~_ "z@j7%Jn[ S]w3J6D_ɻK`Dk;I=N,<kZ=u 5.˂=ן). -`b'\h:Nߪ^ř5&1|5Hsӛ)\,zr]>+.,4Nj@.1<0Ԑ[ RLH47U5B^xgg :i-6$Wbi]$޿62Gg蕼[Վ3u翩jEYd4-~L5qj3DH1b*ierSEwXcџ߽ՖBђ/2 u7/}9l};;wSoqmw^\oocmFxDYj)ImcLVn⧰b%^ɗO*vۏCdtɠ?較cxE-ƽaN\F9c9٢>4C=3:D%I߮"Aۀ#V'x߇aVof"N4P8i fSj~>%%Pd^cB 5BQ__%CB:HQ2dX~ C6SC*MzwУZtt du~l^~ԔjN AݭǔTr[ΝiaU!԰K>hS `uA3Mlfm!Mqdkc>-BB$[s< .4^۔a0$(8LD(R{t}Ymt|尟~Cr=y.*JۺW j~e(O~\sZ-E:m[uT2AB9MobNDTZG;rȭlB@[n~p9*1t4XM-X]&W zXΪf krݶ.bdjXTz]&~&v]}}3Deј1X_S}7)h$O#5 T|We]R=]"G3qRQ]9_ߐf5P9R[MqpsY5~p>pcCBo^OxA ]FXUg8zɺ9NL ,JZ-2"uHdW*ylrO5/8h䨝ݯ#([,ōnazR@2_@c enMh3+Ƅǒsi9,GOm7#o%(GSQ{΅ HiO;]PHGCEjV5ޱ"V&4TɑqI;efdM 33*rC iS2?>u9 O<t"{_YQd/~'O-S߉ϳ|P芊aY^|L>߲Bx+Jn;d zѧA%<"O։kt]=ۢNǏ?5C͆P%Go5= VYhl D-ț2qTA UYw^l}3z*Ahm Ṙm|]ĸ7Uvwlacqx}e*Z_ۡN -բNw__2Ov`N@sR! ^P BfC@ H+k ?1z\_QeJG}؋5`G3/BN.(tIJgK kj{]G5D<)&Ҭ"W(FTqa"zO_|{(^b8=s uNmcHfe (_xk8o'Q6Ƒ^7Ww`Sڂ?BCXo5q;4fC{:rLJDkh! mC,zݴcMz8Ayfwu2`vݦ}B@x֐aGW`W#ru/TĭP :; |A+wmȪmW_.,v1rcFb;F(+e943ό1NA0İ@lx` \\ߊ#<ڣ CCC\ q{;p")j,l{WjC$f3U.: 3CAϨvu2qbXH`|~OYZͯ| LT`˭LNc(^7k$bFF/ ^{3"a~qUן~5DqПi]ndT BMyA- Ӛ1 GߌZa̪b24=!?ӥ H6i@. ?B3|' ?F5ZF\ WŮj@k[TMX ǵ^)o}yW%S3Kޔd7ki!u!ΐK4WȔٰPpMMGCnrK-3@M}pO/8DtF /X- Qa3\ 6ﰔOV|f8~ٸPbbarNifU#3C8+О٧ ZTDog}vs+~)6d -qt_2/{eL/Z{.:L̃+R$VF? N~S} s@~[M4YavıTF@HBh_;`[OwIvhC#4¤wAecfBS_y [yjFJ(; W@o?<ճklh"ԍpTb6iF!~F'bdjGwZ'׆{t4{T~ K4Hb`ma3T"OuSs/I<=Ca=RVf9.\qD8y磥4ElwBeKi9˟m:ԄڿǏpplb5.lF 91r{^FH:FY>n ;u!|rU ʝCv.3kW-!\:xTښ꧐ܧ z3Ae M-R ->w ̹@ ?8F{Њf!}͏'eX8j/e{TNE<Ę$'RLLP Itvm͜GX:2d]ns`t?uK*WF+X'Z|jUfP`F`vqAy?>dCeX?zOVG#w@B,` V:)OΉcb/jxPgILOe(3TʐնгFe _'ÿYlG|2O[ۑa (<`#C`5k@*iCvnąEڡ;F-̛^` zy5|DEDYxduiJLItM<{?=oXŅ<噔U{ó'Pff"x,?."=q+.] ڷL8'U] >/*H逊dYPwϲm?RNo ?X<ౘ5 %az1x(FzXgGg^*ai{PQށ:С#dhihf3B2mB5=!*PӠVy~"Nqe=ˏ1†;>kA bp//͐!uͲң"t.-s+{a[wʝXQ'_vQ۷,F ApArx<)1F652GR]2 !͊rJu/&GMA%erO{SGL@uktȤKSUIXM*<*=2cLC}'^Vg.~EY8(,jB K(?%zanj5U;B~Ӝ z&"Ōlm Zi^^YDZb45NX O&Ld zִvhN g1כ#`iY +YKțGDSa-BpjԐ94RCV*{?9$ɞXVHќ{ƜZL٬." vE7mZk?_}Es3ӬNV]ˢRk}3m# 2N&ǹ岍4?"fbV7꤀45"b/hx8<Տ ,Fqj@4` iGk[4:!jЏL~]e*4)i!nohݤCݼ/d{!ZVFҶQG^æ˱̖m$F8Ǽů:j*v{>B5Рeuu3$!DJ(yPڠ0oe 0ʴZ7O;zRSn3{jdx"9zyժ, b 5q=oB"m2""^K-hp$zI-_IáF DẒ̌K,. _$ht{౸g1Sp,*tۀ2bvٗlS=GJ\(sLl mXbKdU$bOug;Tُf%Ze 1NNJ)dr亯ߧNQճ-ˎWؾr%i붖$Nqh.*Hk !İu#%#b_;6_grL!OXC9jj_:p/csm818w}_J8e/ӈeUcD Vna?55 +N,6!7edtOO9&/ êe ӻ-9i2D;los8GŅhVX YŸcM͢; YjGqXqdkmT;QjèO52># 4 UŅ#qMgXgZؚ>0T ;uM=In4uR1dIo> AUUjQqme}(GdZ—L&ܠ<)gLȻ?xګpX7[">-ygZ"^^PaCD8Y+u=Ptpt[mn|YucC5.4ȡ| ZȅIDOX HSVcDrⶫ: 1nPRz]<fZAK820Z|s;TEkGB.!GY0m^q?Rs!:aSȐ sjP;ɵ^2D8| '<=HZWAPO96t?i4'}3AP\Y1޿MяJet5YmbeXq}Ϸ4ct_ uV[G@zBeSCĭ/K824G$VemNq.4tO!r-M"2_^w Nt>(bH˰3Y} '&453.d>VͺѢ1|?"09_׹c S~JӋˮB GD*QI5"EKKnH%4Z1|( ~kj4_?Jc5V=C䵆S1-8ZBLBw?k./ȶO!jl]oJZľe*MC^KYD4AЙj qi ΫXS!9$5Dc´` S>8K s?SXbܘDd_ڎCb2^ V^=f2q22mJC_Cٍ Sa7ڃ@|gk\]~+cv4i3kpyįDL $lÅv[A8Xw42]CJ3*npWx `=FRGM(|isЏz."޿\Um)C@5.&UDNhQ2[9=csь=+̢!rC7GһG_ Seq+ǣiŝ|udĨy+4Q՗4e帜R/#5BITRb,LS%=.`,ڧ:W8JH OW%_[>1$ΠgoVShBig~g92>e #YS;z+.\ JMφ9!4v(5q 2,h3LjF̾uoQ#;r_"5/=1_gXj{-[.h*T;;]`˹?cmf-Bj1 9X":ONČ Q"hU}GHc,״ CY}[@gCFkOS DE`ġnwwweA=ic 0g OhI+b)=)$J+2"FtA -4VK ey!Dbbh GI.P/4UK@/y}εB>=G,{`x9x.ɘ X!7>BycJgC7|DZz45 r 6Hobp9GŲ]P]9k %탩Lψi ?Uo[Ip؁ _S!f3Bzӽv4DxB)۲)gaԹzrQZ.Ǽlv 䱦!AŽeI,5ᚉX %)kjCŅuzqlK{WG?hhx2"ܼIX-W&IdI7@J>(#OD鸮u3ؽ 5?Qݛ;&tڠf? Q{?RLmyH⿙/ֆ}mbY`!ys-^>K|zƥ%tl2c[3vd0?@̫ȷ؋aв*ӷT u&X fX% "(qOSPg7Vp3B|]*xVi9t!XD77?m~\hGH# l Gvv9P6P:F8!=Jec'Ȱ5645<a ~hTw B~U2ov-B V;_/c2%q%miR6 U-laO} &5kPqx2Je/cqhA1N´f4aFȧf_2,[BKrj6)mL[}g-H<! ]RCh8|T G}ѧ L4'B aa[+7)mħYG\FKn5q]e<"DCD3b p5d E;єv^&|k/ٍ9ђ/TVq1QC,fHr1eHpvnfdMA(_W&Y{vZgIK)eK٬,69 L aa3hF]> kgr>ӡ^kSϱ4lBDC/SՎSye_Lnb!A#,/;HN<..dWzYG/ϥCmJbD y,|Bpɦ'Dd:)i ;EskH.:hD3&My_2"Lu,U/Uvpjh} qg}WI/TMᵃ52|8b>jfD=U|% ͣdL &| 6oYa?obG}}ǙvS%s'B5v=)A|,b5n io\omυYpd0gvVioHEz|%/8a8#,S̎](e~.٣fRDGo H()k.E 3 Ly RzSs%U҇!aw[EHEA9b5b\'e)& 9e7q@YlnaH• h qy5<ϛĀ]')U }Iœpgz;OѤF\،le{.Ҷ\ =rj"*+Ԯ) kX{O" ]_B</P%zF4D [Q\]> kC`5ZI=pA> `%f ݴEݶ`jдT-j)#i"#T!ăÂ9g۷k.Gi;9 La =Bb߲ Op%bfEꉛp^Qrlu92nWHwgr\v!@M3C>^#fEV5L4i}5nAym2}_Z\jޕ՘`S7Wl5GEjH~ϟmhNIh…<*3F̄,T> 3g42P̈͌Cf)!ͦ_ q\(#n1hăJ8m%cgXc7hĊH26!YCBix*ӑQ vCfѦ*ξ_(7%Y3' ։А!Ѡ!N@CЁl.I_%s|sqO=kO P$P≸_1bQ=\0ǁ%IMD: oxuDK^m22f7]%c *gtUxBO i ~_36B_ԗVr[Wh8kHR#n)FÚXr9ZGCbb^ΊUY!5r2zf_ˮ m??"jBy  ۿm])Lכw&j|Jo zXYf1o725}W֞bLA(& cAM`Q;`1m|@8mjܠ|%A;O ԉmI`6(׀#X}H@S/ԉ84k"ʘc̾=/ga9|)߁-7cΪ]cb%1@;y5S$/}joDh^S6WW,HC5:>%=*8,*x@!f\IAH 6șbP+΢zx!z=/PtL3c]bcNCnx70 Ƙ}M0FM[S954 DpC(Ħ,{c$~n)ښQ!$4SL(sM)K*l<}9uc[Zb0Ƙ3~r1f_Uo JlİU1O(=|l#,h^%HeACG-xA8gŗA l&|?z ѵ t1.ԒđfZgkԯH$lz1ݙm1ǖ1r1SR*ɶ1^ 8LqNB+PR6cY-Rtԏ @m:QMP닞Ua]1Js)m^So70a`11ӭi aISp~jb)b@(/%Zv"4MnMY?3V4TW=7S׏ӑT({së-1c̞ ?opw9-&.XI7AѪoV煒Q, V-daS{YW( r,l>v=`]ᅖ1l _0씥̬/ O/Jߥ"s'Vd_P&֏+~ I<N1vnȚ<-}.YbZpbmXiW;{V!^SH11bݖ1;BկA A|&.SD ֶ &"/􎝆x6A7ɂB`ʎCW@2#R8dC4B>а`9351 r1f'dB1G!-z CNb\ 2 ܿ~>a]PXS=#GKZ[z`p %Χ( \_/]$ 7(1W[$,1 `9S~# 1&xӣ=Ο _BO1U[ٺ*73I ܱ#IΎͅ- Y&l0#F$t?,&x0%cNWbx%c`9RBϕv}c[?~ YoO-6|TaMVM$1/F\%QII+b89HR 롧OB)4sL)"H]S 9~Nc,1cc̱~sJ:)͔ jB>TЖC-̈́z[JԈ'`#}xˉAGvaew~6> & Q~h&65EҍcnALG5ɖDX ^$W4&zx% y@M GFb|cGqc̑In21f@<1HBuuլ[1ВG)$E i 93ZҿoA4Ka PTH-XRv+:XCy4IIh 4Xb0Ƙc$7r1r-a3lIH#:?rPF2WQۘNXY4+@m$63]K ɳ+HZ^f{N86c>ʤ~iccp ƘSԦ( ^ZP, J&v*I_8Hwlİ9 qh(C]dP/×e$GvKcHz-XN'u/%'U 2l cp+ൖ1 `Y汴O)3~C%"zU'6 L [ћ0,B(ks|%0 >ce(@ JJeR =IMh8 z.N|A7˻}w)|W%AlVbYHbB5HF&Q$YB1b0Xb0cr1fH\vUrD:DN87B5 S[OC / lHgIǁ#/Hz KdHvM)C&+$7a!SkCˤ\s4MuZb0sz\x2`chLJvh <Ђ$Z|Ca_(/fٖc11kmy].n˓#T~ 5VwR &bkcpoQ|*R'Cq.P$ 2L ,v_R$:) 1INb+ q*DApD0_ eYXLJ@ػ`mX]q(F < i. F]1j)5%Pxyc̑%c11W6)HAҼCkڷ]ȕoS$BS$ʄEPHAwZ{V"Eqo%1JHDy AUU!2b0DTۈj=9*kcc̙ 1$;AԴc641%@ihYM`669 2d<'!CI@Ҋ2qAUaVkE8/s.Pc?Žry1D|Z1K qc9r`̡;%Th94eFOm61Q}(hAW)c7ҳċl :""|Qʴ-.ы*:dk#}-fT@uT& d1IbAK cEnw>c)R)oqR( \SЧhR*ۓ^$ + 5Oo +lM4lRB@e$'8P#xc2e"Bw9^2$Kb`J<sh%Yb0c  +HMyPP>|ȼTdԤ;,~1?l[@kΉ#(;X22@X5" SMhU=1w7@Vy%#4czK c$_dCJ(f 5̻12c5'pDj EV(#+b¼c1AnE oT]mJn:( AzjEڿ8T=ZD&lzPWc!$IKq$\bIy.('eA8RZN~ Qޠ0`+,1c9r-7sLwEwWD`-cߏ?1VzRFU$"Awba@91ʘ@Đy\A`~-~zRIj8c9;C%bO1I ϵ`1r1fOY*h@'́=B"x#WzىUS6b?Hڿo^,*`NT9$ ̦ItD](C6AW8mԳz_@O4cc`q%g 5!$bs/KK_XKD. XbuDR0Y/0dID4FI\dGb60YNGX/&Cz1`H o`1 aAhKO_0@B2dʠ vE&b3"Bj2Dvw:~`P"BY=sbTN M>La_1N$AttqHR+J1+6 >c1GWn,7snp+cweb֐WDŽS=!BlThCh`qC%B-؂mB'i ͱ/$K ; "IH=L! 9NhT+ 91Xn0?9n#ۭnZ$/8|JDJun,=B~IR6#(.LPK߆ 7},C>h3DVzqLb/E\'F 9[l,1c9rû-7sXW_٘nO6 fC ՍÏqr{qp^HN 9 HPMq@ PF h# ,91nu&P=j;eMSdbe%"3za ๆRpv)7č,azcv[bc`!8 Ca7Kd. VșրgzgI 8?Ya3,/9WfUx  /l*NN5i)C 56bxT(&u݋Uc,1c1Mnx7X >1 _M _̤ǥmjQIQ|ŖG8Y%?4"P=3yA*73m<[Dj=G{f3Zg ҘK `1/_"7|Ø OAX| cV~n%Q4O ڌC_0d4LC+虍 |ͅzdE$WEIB;∺"Y&Iٱ1Ƙ'7r1;}d^ǐtqKkn:˃K}<@iNI# 72.;󧖝.4`[6Y7`-AV Qk/P N1'R0%cb1.c&K ccI1A!oYeN C!9c0:LJUmD!# q 2BA&m$uYA&ާĴu#{p=-XT6j 1 J _0cKDm[5@h{GPhAy䆞9I9*a5J#ZN+x'$חپ$Mt.sݢ{C83h\)1f;-1c1^n DoY@1*A~ $K˃ b1#L_XcҭE)Nvh }$52'JHD;Q> v dCȎ 74ä/LfEH}gG9m,1 /~ħ`9:x> Ɯ]4ر:П800HClL ?1i 4SS*9\Qč7mP@S :vO!OM!@{b6DFJ1Ɍ?3eYp9|[s,ypPC>=~r1WLwї1gwz[W~)GǺ0?hRZPQ@"6b:k@K&YIB.Q0`3'Y3)C;0^b.xKr;cLDZ| xpM|Ƙcχ?DZr|Lm/,C&/n<2%S:M@73к@f-3HTĈz<2N S||ѐ4;YQc\!'B0r11K wİg|xppm>c!>< p{> '3a `ֱ4šM(ti a9W}R~iMq bCA CDӜۘ@#Cc B%AD :~ʏSoEflcaKb]K {81fˀgnc| \aա|TOc7L kbr% Ƭ8p!MzJTvΠ=mĆz.dJȥ-DM\=m&@4xEQS@Rl#&_xo˜->^c81s? <DZ7r,73TOH[<l)쏔7kT##Ii=1OcR3Ps({ 8@o&f $AC 0١|j99`,1x%~ c8n \<cZn0f~10@1e?B< 8m%d4r>X׈b RAL%cSk <]k)Z 1)B,e$+JևBET+>0{ 9=Ű7$"F 2c. <co@> n_hܕZ9'+u)Kщm/+zB w( Uh8Ŋ-4KDX33 JD}_T#`MLhEa1\U><6pK>cU><8xc䆯qHhx91 g`dɍvj7dͮ?ԿC& $6z jIѢ Җdz9G'.$yĤ~bKt2S;a,1cWa1{ ;߷{#7 j *%HG5HzeCen~J_zB!V2mgGW,i)Q2dZLDul"mQ89BOj7<*,/K 1 |/|x2A7>ݖcSJ7/ИC8]Ĭ=3A/DP=_1NG`S m%MGBP4(JIP!$86ԣ JP&7=ȥĨ˜#+1%"^6Ƙ1pCr1;Jj䣷Ml%!h}r8!-dZL>|p wRY=.snȸmˏS"Tq4dmzr>(-1x%m cn NB;}*)U=$SsD_w(;W\Rr눙R2 Y+^.=!'@=fsh9DJz]>]%Kn1w |DZrïZn0Gjx'6a9@ e_7Cs2_?B]ض0 Z!D?{=&&-L14R>0˭KVSh]l'C8N^gbc( 1`.|DZrO`& в%Ԙi fb_81y<´o6$JAzBhOb 'b8L: T&S6w8$}R# aA21]# H wİ|xp k}sHh<||HI ! `[QMYP:kjgO1-b~U Z V䆘rj7_rHUG@e3)sȺѓEǰm%?¹Y=6sn1Pbx%]/'0ƘCȧn DZr;-7#CKdH2P 15PbB [X{=8MFoyw(AnL9Dl!jmvs[۷Q8EY1Q^`:P"CjlzAWޜ0\bx%=}Àqc!r c[n0XY]R^Ǟr:D?C >^CcL 5JC.#1{v9ͬ^t6ho"cO_lj`EVŅQ9y_bh3OiV/?ӓ1Xbcx#く81hW.Y ?e5VNԆ<191tB2_HRЗJ"FE}L"c?ON4IN7AAlX! -=/ PGzS/V/%ޝ0Nb%c̙bMr1ʐ}Cst7sA&Avܿo /PIYvP'z%.u&-i!K)S}OU4L Hy|QkH/'DL`٨8MLd8bs%߱İ{xc'ޒ`Lm96t9f^38 ]Aj[ιݔZ{VA/Iv%sMShA GeT#̨GԶ!&[aGۈ A1;#u${"OTc,13f1ƾ{*7<9df6m D}̉27zTɣ/=95"fBc|ObX@zๆ=& lQ^ bXGAxڊD_.?"$U4GVtvŘ9ZbUyf1q ? \dahyF=yMdR&eRGs orBL\ڇlDkJT]=`6,9|E=dNjA}`A!Yu2b>?]6PCH9X]) |ĥ81 s ~y笡_D0:Շ9ւTv"`!_v61|YRā6B5:@)w@4N2RE @/1%-]qcY%x.pr95%򙼶4P"$c/QB ub)p403?E F*ۺ'2X!S#0䳦, EQp3K@-AC)~$5nc V>0sz-p!T>ݓ s៓n~;T.1pD~;˚15bez8ޢiP޶6*Y)讑}&%YplDyHDYYAzP"r~y=^0/^!Ocqp/\8v~r9d XkerS$eD`GV;^8S^4Uq"(AٔC5,P4O%S.MHMO]U% N"&Ș)1[-1 \%7>c1;C8v[n>s4ۃP/bAdJ h-} м#C7'T;X ɚU|8:AM, dy C]4R ˃lzITSAok.OIG Д@F[|ǀ_. a1f+s5.̮ Yn0v$@@ xD'l~,#N;&؅c5~9Wrל̐?QscqL 9Gy^^Qd-2T I͜@0!?kzc̞}*7=I8y>*Ne=xYE9gc:cVkH ʡ6D (?Åx.hh%ؔ!%CN" F]x#ScCb8DZc>< p{>c1DZrýwXn0{1-ˤGN^ӵ| ;c?͊2IAHduW0Ӣ6$ 5 }"9gF^r;!EiB_cC"}*[ᮖv~xc!SӀk^`̠ Dqʎh0+_S8|.< }"!7MD̮)'VYIq>| e]"S 1;z{JG4J#D$h 0mKCHs"1Hg98ErkcQJ Gs;b|~ƛbay{FyyŔdX &5{;Yb=<x6Y9`Osy2:Dv,7 xk$bS}VBoOצ] ʵu|bkFcAAR-[nc,}!Fr"T4w6EM$ G,|oųbHdꡔ3 HA(/PE{pk 9YX%ӭ2V19^:+.e D`ːP# N1v*^=ڕTM ARUF<@-9AlM| ~<)2rѩ" JFn6U?!2@ :ΐ؇Cbg토xȾ2z|dpwc9^`)-PC>C%6 r ۠2G c-1'C,RFfTǑFPcVJi3GEϷ3x L+% 7JLBK gK'qc9\p]_8vInxsňI+.ogΥ \5ة`e!S:Vvv2&}GNKhP%NY?Ed*X!LD:CPT׃;tIR4$N#44{g w(.3<0w=1739pwK [>0c |3`.YIcyZ?@pKܿRXQ˜\+e &frCt%([4P52UQ'1s!]S0{ܘ*1 )pcۀX3cN{DZKr Ykk־I/DM:6զmQ%lu;`L`C@x!S0K0P=!Y%drK .ң;;jNL1!7}%33c9#><8 >ǎ冷O`V~SuЃF -@ T BJ^)N-s~,=f{7]ц(gu1b@\t1S͎r~;-5=4jQFbh0pK ǀ_. a1[\ &{Zn0k,B" Py4@#&]F0BVHiQj@hp^1|xpm}.Cs!l)ޚ刔11UѨa!%dۀą^?URWPڷ=)~ Qr;Bc/C,0 /Z<ť͍39Qbc)1Î7pc1{ Eo^Xnx. n'D;fɕ'8i : ?,@peܽ+xa".d5N~)KvM ϬzM?0~OcQn 4Mr}[s TaB=@Dal1fjQ5urp%sz|x2p!p;>c1QyKl,7hl!bX)x80bb0z,?lۿL$D|tp[=aˣ!{'cb;:z7 JFsy:\k ᆿms0r(_pur`5aqc1OOAU> >?B8N6('$H\h  }!KP"! }zInNd}B,owHJ% } QP)Zԇ)l6, 2ղ<1jXfyQ~N;=}C81ƘC 3䆻[n8 ? J\p8}[FLm!R э!&@H!EO:-d0 ~b␼ E325,={/$).Єg>3 qc1 |{g};qIZr3 rR%KdaH`:\D\(oߏ=Py$H\ec dn;'0X͠ʓ%\}()LIHV-K ǜn\xFb1 ^:|;fh6@wUF K&t 5{A;Jz8{kA YT&JN 2{F\^L"xmz&x~vQbxW%c7xc9r\ 4pxO> Op$ՆoMf/ffẐv} ( =9둫ZINorê"! INBgVSŖ@),DN̢fq&&D pJ İ3><+}c̑柁_~xL冻Yn8zCd9"h|d 0TD߬+ Kf CkakYMy˓6t972pZ&/9@/fQbkTc̹^(|E4x# 1<Ù݁81ƘcÿO0:cNs=EИA~,U fUj/~:X'Ihm2/(bJA S̲R"&{|hLͪuۅqCJIkGзX?.İW@>c1Xrupli\QC1h):F3MbX߹_WAِ~|O1QML̬V1$|THމEiQ5GS-gRRPOٜ)j9$lbZVnyc81N[8v 7TiGʐC o!+ [CS0n33c1<*3|h3+1֚?Q'&zCNbRcP<{$M~!,LvXIU>yd҂J75`stHQċjEY/y)UIrȉccw0c̙qՀ0GR 0?BIɅTvJr0E $ojk= T2=h~D <Ў>Jt!cHh-Cj3fPPiqss {}c1|#}HJ )-~m6Nپ rjwA,(~XIj?.%`ڿ{jAZ\3Je =Vvd]q$\{1DF٥8Md3t`G VZ1BC N#qc1f{?n|;%bEq{Z # I0B2)!0U@G@t^gʤLH5\"@$H73#Ly$%RL ԚX-4[H5,k؍NJmbKn ja5 qc1f/[o~9Vh026Aݥ,>GԞ~5e E dqa6ə =Aֿ1lFҊOx.o^=&!B;m$ mhK, 3K<a1ƘW~ _>sd出<j@o?Ra`؋=Njk?Nu"e"BhcI ,%3K$i'!)(6JFNAtc:pI 5Cesa1Ƙ%>0G YS!SV@CK״"14?bp_|ֿGJ.5d9 UL )*ԩt`C\aHC!\wsdBvk|c9+y=8̡Dc9P).f5)g ( ?V@DɜE GdbEZ.mAɟ$c,I- u. ']Xݍb-)MD,2d aqc1)7~{9dľ\n)CJ{ +$cŪwAM )DRY$J#'?Yf b2Iى!1T $Pu9;S~Cy9 0\Tc6  |a1ƘpS|0o& g˨ C{DfPeA}u q׵~D>z|N!Ea3 P0fR 0I.N뗙 [4; |a1Ƙˀ =>sE}hhM Fi ȻAC'e&\LwhbAPT9$f@;Y/uj-'lv`\Y  AsVe[e EX>!YohiA⯁[6c1zՁ_a,u][߳!C>gO@iOSj.((j9DCs/qbk8sXP"CCl*V/?F)qh"6B#Ǎ@D9xc1 .~ 1~9HPV%O1>?fcar+*C\gȡo xehe];͢vБAR'l%%"OIDdwz$lw:?z!f0ӂ&6livg0c!gx*?8́P2&S"$BNƶGľ1@ dANG#p=C=)K=%ٟ$4h@ 7St 6="lu;~H5SB^JC"-mdNYdAg0c!+/nA-1c&!!t `&AV }Z/FB%#5]^sυI)9{Rv"A'㑔;#@;2@HȾSWĤv{o1~[=/c10p#0$ ( o4鷆m-R"[\20hbnW%x~5xnʾGbvExAH Ġ]PC*Ccc9KmTsOOa1ƘU{o=pe9D.C;ِ||bg)~ ^͡{2A/Qɥ$pb56@{,2N <^YI5Нb x+Yt'S2 ǢdOh(㔈=!ddԟ{1c3mWu oү=T5A& %!"!jH=b6{Le%r8/ /Q8/2=+6<1F9y1G_>p#1cv xps=%Z(ÖDPs6R$ж'/SJ~DB Ah:mm#x{?ߚhh Nk/qGM` 6,W͇=P9'Aw6-/!TMcWn5U|"c7 x8pU9zmlcH0b>2 _,hPSS*')H~-5Q_o~/X&4j@(I:ʂ Q8T:O}tÈP`ش@T?K= Ո9|#$R781sRী7 pOUxe19ڿJu,ֳ}WH\eqY:fR/2e31#eَ^b),dea􄋨 *_1LJi,@-PzC4KZ/VŹ0HmtE]DU 7L`_$JPbdOUrŋxyCڐBpDԋcO_:s ہ?o 6c1Bq%o0ǐO'Q;7Ők hfDm%`Q|'A-Ɓ@XV2E!M?|%fx45ДU$u&+!9,Jre"9 4qtc,y7LoȘA7^x>c1Xrpk[_1ǵU\~ e!Tۅ4a.i)^ԯGȑ0V_l* cgFE.s]>籢y|e2v11Ǐ<c96G灋 |9E_전D2: Z Q? J{TBh@]Q꧗4LcHV,dM"e~jN!T/͐Y)l9wɨ yɨ#'b1Q.ÀbVZ>}oA L ~KÛCC;.N%}󚅙1fx j,I%_ m؁[ddPbb!czӁ81Ƙ#ė 9>c*(wgCPZn„8*BhC;01 9?$YPrqY=2uĘl )+]^dDݙIr(ŪgUc+1c3 p 5|Lh2r*ћY,H*@e$d,P2,}eT7J60E'a¬@hȾԡ( OߚtL.I#IXAz4Hޮ9T'¾-o.qc1/;Dˁ?)JŤ}MhLEqD{{y_,C!!SH=S (:GT7 vj Q?&D_ uHA^@6_Hzǵ5GU{ /s|"cZK><␒2"84&d( cϙhׇv+ vF(6Ll!c>J{Zn䜘y `rэ4AK 9ثAeʾJĖ G #\2xryZk8|x4f}'w.?>|ҧpKp/;|O>82C,S :!Y&JBwXBfq!$q㖄o7[8h#v&DBdDvEzQzR&:աE)}G#p9oL=%Kk~n c)x>79f *> W,=w"2KPS62dG顲-rr39$Etq Ք4Hɶ蹣c#xBͿR%Mo&1$01#;q~[}c̾w/nI7{ʿx(?Og{B43bpG;x!1=aD' mu+af9?gR)lV\@L%&D}`axYʻ[ِn \ BrȾy^17|;%}ہx^#!cZ)GѡbjN'w$,c(,J=QhÖD_ ˃ hTf&"(BdIpFi֒ hOcb),1<8\ <c% x=r}"|/u8*}=A4/ >o ,~Y_ ?:tǵI=e??Il& UZ<Pf?D?`pf)cpgNGWfŖId H"ু~xc'7/n \'b1Ɯ) \ <c4 #oُ~9x5 P_jPuK"M28C6PeZTk{,o,!S1S?^d(0&~7n.]iz  ~p>};gqc1w^E>CÁsqOʀdfA?njv{Qh̠Q h/IeB1{65\`2DI&Ȼj=5Q"Iu H5匐3c.8Yd˼z=r86i8.\<!p9g}"W11-.>}M݁C89zȟ[~=xd/G;S]R^-JYMsR*P4lCY5W0$77/RM( 6Cp9U_5,Y1LC$Z䩆c+W c^ {yYݹWILL\9vK[,K) RD8 Nhy  "5"Z8% 2rg"=\gZMOQ>kϳ_c1fQ |+}#H\議ޟ$hJyRb#Jm׸;U_9DC#fb"t%#%lcylTtT%4"WWQ?t5qx73xߨ1cx9Pg?c=p}'ȭˁ u&߈J/~$9CF1>Ĭ!rD6y%l$DÒ{oi}{wЋ] l)U\|%cc`w׻28@;@#FuIm:/@r EJD\zFg0|ˀ8Y^ <:5c.3;z}|'˻?a.`2~cAR75*S&'b1^-S@ȒK-|A3ʩ}#-024O"=x>'oLB/?*w~N0"{r`DptB)c}>8Av7;N1si x"w|#'kw~k_ R!݈c75XvvҿV}P"R3;摼̉he_t+)Vߎ6[\ڨj~Aߠ8Uvm/g'd9a1O xd >}F4H/0\er_ ,XcvPl^惍0?b# G]ݼLz$=@b (Ԓ[,+ōq;i\lpPFߺ|x:w8Y>'W_7b1!/<GC/a>a ~b5IqK^7YF]wCYtnphn6^RsGdAUmB"#fJC| ["sc,lOL1*<`>n~*뀗FN?\{+}cN <x *a]|#'ہ? a>Etl3 #栴:v ұ'2vz+ջVR}sӼ=4PPNdm$gD"JB 1*Rw063/Y(_1w?8Y}gF1Ɯ,^\<Ǿ珀oE#s mo/rNoG',5v%9M9=@ CbOr0dm`; 2;Y\%1FrexP]esƙܒ ˀk6> l' r+KMe3<`.~8._ljs0s'9c |od$B+o~oC|e`ړVPr [ίM^n~ŽV[8/A\( 'Y$"tCqIݍ\YWUhGY{&PȘ;_?x8Z_ljw'o~v|#c.6~*_lj~i9_:ńZq|u(йXou?QOA^h}=Nk#N`r5)K/#/2U^Jj7?:|}@Ř-K~7r@e7b1ÁW y瀧u;mz3 Sѳ HaE;@5$b* =<-1Dɵ졉Tf9:5Q uW22)%!SF=GCyBRau#/_lj󏀧^ qR!C qoq@>Ӿ7Ẃ<qcN|xJ|=w?ucgx8O?a.b5Z4\Poԍ XQ|>fA-:uxC$@G8?0HRG^ j(vށ:|Cm6&334D9Q:Nˁ1*{u\<\R*?l I#Tј71>y5M\ ,9AA6}$QΈK^Y!y=A)L!OF3ry[_~\jx,px2p44ۀ+}#s +I7/x)po\jlNc,}ӨC>TH';"d3"Z"?"U`~m>OCDC. pX%?NX2uo>}!+N&ƚ mLz~fXsU7:N~ _1\|c;WvW)!#:%K9EZJc$C&M)9`8ue?b $k)(q;9tT}=)ǃf.b'51I2KHDnyr?JnthlD`;ԘKpo4Lແ s}#s9p?{_8%<8 < x\6LA u)8-h@ "W ,ͅNة%~N[*Ct~iHZ1`4&l} !SI9Ѧ8E[A%sܐ7Rsy;?8% <E|sI7ox龑SCk_>0#C1{zM/PzyO9qšOR$1mjM/RYgÆ>ŧY 'tu$ 1ovEyuSʯ\! D:_+73|#si_qJ|x!pO+rx}{ dii([(]{^YPG!gc(T0pCh|?W^\цl H}[[%}$@[=+ ˍqz}7 *_1Ɯ_p/?ox4 Gou~֛3a! !=X8/&r*`Ar{(zr~~ $h lftQ=;@bRPHOO:Ou˚ |qJpqڏ_1Ƙ; .!,{%@ OFͲ% \5ֳ܇p=ːAI},Wv~,#9-HA 2Iص` GQ 6QRW9@<40gyWN_gu,y$,xm*ucE?\x(\W:B71RLGM(yd1R{KZM쌘 )k$!k9ͅdN1\*z?sُ$|r<` >p-Pվ3G x<7}#sz;4q,[|抢 vuǢc5)2,Dqܽ^y$zNI !4eS$ՏdlG ,) #'"ULz~ !3*q@2J"W oR_0Ƙ?%j;FN|aVzsS6G.2bͿ$cZm+6Bn,J&}wfiY8fbp@9!Mqyr~4{)W̕G瀧u sL߈1\{n\8=n^7"&߈b֛CEע:Wz,; XtɅ8FjAFd)jK*mL <"h#l Y5E<vBl'CތrMb,j{gou*_p=o:1 |پF95À:a \GؐS\K (mO] yjD{S~a%dJK)^I9\#!"ta߱d5J 㴉(1c9QfR@:rl'c<?=ۀOc 7/8U~8<xQ1HofZ^ܭY4p5krJ bI$I~[q?;rDʾBF;$ /f2v,+'WɅr{RsXpU>8=xr:'1$w x CFN?Yþshfb-Of,?x>WOMClIƀ?d;ObRy v M:fЋd\L%{MfCKo%VS+6NRbpvs~ S 4|Ƙ'E*7/Z7[|#`iE$ŞbhzUs*gf& _>J^(tfte$o*h& #$+$‰Y1s;CBj:CpE,\< xT10 N 2C7y* A^K?EV7( zɎٌ~x-];5XZADdיאk'YcR7@K|If6u7Z&?l+5p xp/ˀ[}#c̕ۀg':P v"r!5@՛C{#p. I0y->S To 'ș0^WqzG9刵 &IhD1JY&t13s?UKb́a5s}c̕~Ø!9E*@]j~4s5v g%u/63 =-4uOhFÜzG:рCi$M O#B%.Ё"'V-0SܐYDhfc~a1\|U7ٌAU֫?@@ѿб_h'fJ%BD2,u8EhLHllrbwYh\1ȺPCRʵȡ!hA .H(ޒ1fχ_1s>'souf@qlT[r } b '-*~-Wbwy! {Xhp `p]Gh~Ջkżi R)[ԈQ=sYaOGW>0c.a/^|7bm !/:?VMJJfEq<^`Ș36buV Ɓ2^KUN JnІ B2U9RDgILUc=3〷:1ƘK | }|Z^[MP-#&$.LؐעŶlA r7O&%#bT3FF;JN 䯎{?i8`GN|/- c̅%ZK1sp=cYq[}|* YZ*yj7M)d'6B1CG::Az``Htu-$h z6s7br&)mY?A P^#yʼ=nTiK|~,z,c9%^|p}|hKeF7ĜȤֿ!pd.$BJ} ZԈ'?aWnLc@ ] &lU\MlS -ցg *!aplik̦vX qx;?)c1椸xp?lEЫ#{THTd?>v7PF1[b s' b߻͝L}{[4A3|t;gkz;cq#RZ7x#St1O0c4> <0?:hh+dmə]"Ck;?\0cn'7/ xpoĘ;8~̚kЇkֿE`Ƕ查}C0B&ڈ}N{ȔLM >!Ә99*sP/c8/h?m wuc1\^J7Ss ZM-{N~D D.U4f3~Km @wsdb:!If(̞,@ə"‰rԨCH|068`c1sJt)n@*kdY+AյDmC_`KD[gDŜhJQD{9(CC%86T9|vy )v9qej1,y`'sjH0 Py- U$\CskD{ ,yv(ddU,BzAhf?`jB=I.~#;Cg 3Wɟ:sQ2y"b n1dqn1slzÌ9%as*Yj pN)u u>@#EtG3b桰K]3R`3!WY )FL% CDyA VCk ,cF\j0p1ƘC}Ssc7:9EFOĔ;j:,Z"x!`S=APY[I+!zHU1^&Bd&Y5Aa7P5dwC/zg;CFP@ 0O+|~ Ɯ*/x1poc̕? a̩-p?b"hK% Aj|LDH )<)o󔁋XP<ҲyToƆBi-r`IˆNwI]o肒Հ@nj (cizເ>0s%j''|#\"pfAĪk2ej'T8J%1# YYSg)iw5ة\V֌H$c,]`v{& )탍ђEjƸc0aK0sEQk0RcKZ^A &P#tyA S; юWv=Y$o 숝,Oըы1 ,p :ZH*V$`2׹ס:JDT F6x"@-T{#4h'bz*lm|LÏrbGiӑ4Ͽ4\>|U7$c1~aeGe?HN a̹zy-; z/]Ӗu`"waez PʲԊV@\lѕJNY.ˆ =12 |a14x 5s}\IvCﰜ6(0W 1淇*V,rxutp&^t^t^M(N2G)CҬINh0F-Gj#0(mvc50.x?dC?O<-w>L۷`eۀg':1Ɯ7/-V߈15S)ĮGb楸9@CL9<:R(9" %a%S "T}1O9^LyIute&c[*놋$bFOObƘˏ c̝gW0JBu9DY79A6ez Z#Os2Ru"< _u ;Ręy{AJO /A>9'x"lcn^|5o%c1~a̕g/#4wR4I%3!i ]$O 9-8?ٌU6Psd,#,P(+-%!/5x‚~`~˷X::=s'ww~cUu*1W$cdr/:E_䗸"~?A\PAq$2 U =ġɏ;3va[NDΥT#j4salT·oN91-sB!4jfMcsp ;}cn'^x J?é :q_OR3qb*{cPlD&O+$%ry=[4mRO.4/AaM uTND(ٖͥLPm\cDn\< xcmSsc7:҄U"uL}&喃EDQZ ~jlzB9Oӫ∝FfK䕊TPAv!Jq GTmZGH93<`Ap+27F1Ƭx#h4cN ?2+v ^ôsR/RLHFv %a:Fr"D)_1q,[}s|%Z}&թz3UWy]1Z8 @U <|s`xpx<6_1b +aD0,X2+UG LL5 ^RA4^({bz`ȭ5 /+ӜnȜL˚:?̱6ԟc{/>1Ƙ+ |azkmĆ."?u"V5,O yP/\{8?:TϦnؖ#. fVfJL ~̘qIyN 3[3 Xtc7O0Ƙ+[poS.Zyށ- iT!=;7CIw&;fK9JI @M`^'߁8"))\ .(ț\WDКt$7fژ_5cOx4F_1\|x6p pൾcL%je6  ^z3 Ø[6+|~V1u@YdFgSŎ9ZJYgAf R"Z"x+UpY$Rv"We$;HG數"d4衁Z  kP,{G$#ZYЌD5ľ꣄M̟H4Ƙ 6I{|s s"^ncnq'7GHaW GUT6PP#fvt?%8/; ^ECJ.EWR&o8C̆ѽ%]bѧ-ČIr@7G=g4cn3 \ <xc.1>< x_1SE(pYC bݓ\^H& 7xr|[pzI s\̍ ھH?ŎܑHg̗TMԱ0X5Ķdu'&~U!/j5 ƘK^ 1Ƙ-c|Ƙ O*b>8h-!KE%C4>/s #  sg( _^-T!g"CfT8V@9LF YJ)[sx-p}s-݁uc I#؁r2C/F{TQ= z(Fh\=A{sHY `[6#lc6j='-ǡ}; Z:ψC (< 4Ƙu3uc̉q=o~>gr~*(zT!# xJi yq8 {E`zIr1P 1so6d"eR~E̦FKED=QDX\;W ]jçwxc4 <8|/f_11J[jh"wRape"H}~qHֿ=pAK&8Zcȝv匪 s0wOpD/ \ ϿȖGTc."&߈1\<g9i}Ƙ-DMe Ԓ$-9~"6mq,c F1M46bZ_GatKBf-FODf TK,R4Vsu" <^Bm7mq1bQUӁ:1?7_cŧ-h2V$BZ2dZ^ah,(* lO/f@z3F#TE5f\bP0d GȞXD{~;mIPcRi^ ԝq lj:c[|s; s'Uz]2 8XT!,և3F1;b12xeAԇOB"(Fr$jY#wI1ᠺLm*"[r>|HbsDM3s$7|7b1+^<"YucN_Բ%FW7$f b?tR0hH&Bm&Y!G Z{~x}~{j dV2HP| _g6#0bUVX͍4Ƙ瀧uc }1Ɯ( lM/' TעǶ<@+͙+A߶A 5g&ED@Bc"A 9UsaHh0&2 J1ޠ0Ɯ4 s53]ucNJLLHd]%)SāK%5K<3cx c9ZZ{Qz/Mt?H$Nq8E&i~/h0Ɯ^sxp/sʬmAH"J⪘ 5 Xoב49R<5e+)є8a!5н|Y5JO #W]rG;,KC0XdFBlF=}̜2H<);aAMc1cݸ%FLϳ$!H];)<6e'6 C?O=zj.KFJߊcTYKhp]+ꌐ@#c1cj҃FZX6y=٭(uj5YRDPC S؂_KBNs;mB zR#횐9B)s@$aToO*5Pw\r.vwu$&8>1c1.0+!Q pj+HIOb8 IGJ{fOdHr+=?;:b^@PJ"=%\Qz:Q` 1wBx;LrtR_@NߥJ$/ !oTRa1c1@y翔>dG9@# %vPp?5`Tr4aly92ƝUs\jhn; z'IQRN)!mZ?{(!c1c޴(I) Z 1ҽ~;M:P44$qZ`x 'vM˱6)Bw%F~@11'k9uq7 V دlXNЈHc1c9d$> D\lm)7۴ÁqM/# s t3D>4ӁL8@Xа uп[*Ĝ*)Q!A{21c1shr6T!4A&)Y!-]:>\6?_P FH Bb8Dqɓ;Vv J.ƔVd #T41c1 :R/g5%!X_l_5;S`==%p9"+PB5RYCRz"FT#$[q]fEzģ~^DODʺ)ݤ4c13Tw}7E: ZCZ}1?3rѦ~Oz~Zq~l fy@ݎQAV 8@>0hD?O%4c1c . V9e H&wl9s6Y6_T9ˁ e!hdOpe6|ǐLB8CC$ dBj*,M|~까 ߫Fznc1cû J581I !RZ45OmsuЇe"H-G@S0c5($sk/@*HnH](f7`ld: O 5DQQf$S.<1c1ƘC%ѿ*no$R&?|LAI&4oU'Ҝ3[IG,sWYK2b < Lh "R4q/IhU)k681c1;c1c9XoGoT`&t=eI!!2V*,6~ӡ +ߩ3ڐQꐋN `$,ͣJݒ~KP#bh1c1ƘK1EFI>O4L 5i}.y; 0pGhcy HUAH{ɤ YcɗR.Ȃryx|V c1c9tb JHCFG)o07ܠ,wpe/X=A?w|) ;0G9M.Џ)R &#Y6K+،_O=?{?4y c1c9T6fK z3;jm"H/,)Z24@; C"U{W'"zH&';4]H1H=4#(eO5F'?a ΐ]c1c1GFWHRO;h'fSZ*șL Ptf0_6:( %;FIb/Lb =4خ,C:Pr el-%0VB[sP1'A.HRB9['+H b( rQ@A_7a\gG <ΐ8t1&rX"Բ ѿC 0Dzʎ _@28s e)c*Rx!G}7g$( @ImЯD]FEJʣrFŜY! ꡔLiiC lc1c u|3 )L 5  @ .~Ю ~r¬ݑVdh^>HYˠu n@Gcj#9J)d6#2g=wHT' X&n+seN9UɅw"R!Ab"R2ϩ̺jc1c̡|:t>8I_(1)>,DgC*5![b bXqBMFC|ЖAM%}#o2; j{$qΑL9Hsϓc1cWrGXҿܱ%Wd.FJ%"I i/~~$S9Z48PPI2zGP5(VpU:|ιAǎGD1c1,&XSJv܊]襕Y$@0HeB:,X~K{ndZFd40[M,ə(A-T1f+VgVSc>U>N1*c]퟉f4=:̚$#BhLCPjD;OQ(e03n;1/P!1!B2lŊ2P~eE3w*-@LP5fd&1c1kIU(hzyAWc&8_;ԇ׏<|;yoޯ]\ 쪥3Ѥ$dP}B}Hd 9jhߔ/q"C9`Kc1cT"!I{_<: 6 eob0N lySdϳNNgb42d1C |֞{3E9t@r8 c1c~M^kҷn Ԁ" D e^4VLO`— Ro(53KRUtrIDHRld JnhqOLE2igؕ󣬗b0c13u1x!EM)} ) k gwQ/_Vhx\xPXr M s!ba(2͒AX>Y? o̵61ݝpV1c1b CDM/&@5-Msn&M 8 S _ȽA_(3qHm/fd(6ί %irlpNBM1c1$#l /hl8p|6\tOfMEI !q@́)sjhnh~$c!@/B6>kI!Nv(1c1`)͸{%1g}JI U@'=%nԿ,&cj%>fB|$^!}@OPgen 0~7h(oj,xz~`zvrܤS^8G1c1i;QģiMoqyR٥sѿQ2)Cz%XEW=>B5uֆ9ѐI.p=^Nْ`_@[T<qH&x"!B4%b9hG+<`1c1NAD ){E̲ZكwѿAgD/W<ß.R$t; %"#ُ:sBHGWTϣ[!m-c1cYS%.7&!UP$ žɐꅔRrǠV 1B"Btei.l[>}#?r&G(pH85c1sq!% ʃ,Q<=rD0D=>Hܭ#.GP܉q!+ANd@X(?mk3"c1cZ $W"B>_.ǰ@\( (O;?Fp˜@`8NG7hX 8SRel!&9$@'3Wc 2\ag/:c1c9d!ĔrI f@kLaY%(e}lUk4+ XCzsIzz GjW3ї}stY@eC5֊<(_ \DR秜g]Kr$[wFUYw{ՊPqwc|!6V64@ћ-[R݇ڨfs o/3f y@V[zK+>`,;(?GE5dQVq*w#$緯8@%G1O{J~aǰόDL-ިxWP?wZ<@$j5ҳ!mV$7-r_pB݄(/g1=2[;pS]߯y~/-e>8) ݏ%LqlI|z"ᢙ dvx3ݣ4h_ejԃ%,M+,/_Uy2Qa1×؈C g"X؆,$e%_]mA>}2Pð<2GShgrdL+Æ2tܓ͊ IUkFDA9]}'B(d;P%;9OUyFk8zO4c9ĿO-|JLx="̃9LxM;iv:?1tf"-"b4MUyQ~U{UPu?Ny5^9 _F&1XCskdƒeO}kFԶ!?)+oa߆n۷n"GY_-+^mX(Y˪kY{IdYq9y##%5pYVS䃉~ R6ch,$:]YFz?vw\h}g3"Q1Q1< w0`ydD2 RD~-dZbks i{+U7qs|=zT%\Fg 8ٰ6ʫs{z|M1b%hsq|]%cԸ`.T=5JTQ C gAվlyiX$j>%V(\jpo*.ICPYRZԆU^ޯA^QA~#Ou=X /ܥgӿWaXh6Agt, otC$FAuX#md>_ڪVڤy -MЄ%a/xŬ<;"-6oK*c) Dz}e#" (j|Qٰ z:^-Oʿqg$ANi6!\ ݒ8=- _PY&S{AyŽ74k$J7Rr ӔOAj oف Zdu[t{!q[b03+eف~kW1@Bβ$?) &%3'bs(d _h.A|`7F mMJVᐦ]dbM%t~ &W|-IbG9U9I!Z5:CNGsF4iRY'&ά&S޸5_bZIrxp'?'e7뫥 f|1f\}nX0>bsTSPɓvG_ 11q$s?("od|r%[;E>PXvnWN#k/x7J$b,zD!ӯ߳#-0dnAyybȆbB2U}!\Ǚh(Sm<%Q.[pj#8"RqD{C҇B*[]IoM[͈w4rF0x&0&-!$O1bOqi|'| ]0eMd ̛9 F*t DCBJA5a+WŮuc"AG k'#C͔bf>?w2,_KmX"Í]8bj, H8 v~֞!UQ hWA m\E{l?ksM5i^QeYaӏac Z{q4SlKi}(ϲ N[* c`VE? P՘bD!%NcnJ(4yJErH7^6OwQ528WP˶2NxY:77S˂͌K"40h>@\KsN}gi e!e; (U;MkBOPCXh +[-ElzY?!C!Nwx(S1,?:Gtog _Y-\K%$Q{"#3(rqmiX4Vkj_tOq |G 7KZmITt^{qS>M 3 ϟ!qsmC2_\$!f܇xg.@-t9Xnsb͟+9kO:͜&wPB>|ˀ@=!TXr1Ȅ8֘h-YwG>~TKAy"C;5y!\Yፘ&Mavܱx5Mp/qC|.sZEk(Ȼp^$w%!wJDM< ǡ""^6BfŇ&NZ]hzf],0 7Aщ/M]1],׿$c$!$jA15r?~Oya+/s؂.UF62Phz<=8neNk l7z 7UG0$DBFh/*{Cm|oP \~ԉʜ m+au>ߞqLZ6V3te<,gczQ?SCQ&:Д|Iey&R&JS;5sF0o||,B4#^2 HqRcTEqBk5f5t&CHԏm2E@zqo %!oOE{ "{Bl)aߖ YOuf!al;9r>?jޱTxDl57N/mI4cQ7GXC(X3C|Ő7 4!~ ЌMv1RW'4@_\~Ar]ɡcԵ&9PFFAJף|JZ:ZBD{p懶9` L4@!#+,}26_jH^~_1˭8sa2z'^>4|0 c{5-XcփUX+F>H&DȘ@Y( mhM9Vyˣ؅Y=vY{;fnWx M_ HGPPQ.`st <5#w8iU2`&&D<ׄ2A- J-?ҧAӡB%En0 2hCJӟPOz|dAR~ A~ϡS|ц̈|5 >UBT-Hpݙ5VFнla0is[2OLc_#!QN{#$۶A\sgxA)Sϓ҈Q l[eEkXc~lDOȣ 5ϵ\>l/ y%qLѼ Q-10ծ Xx &uc-L?ĄOq{튽MOJ8sbjl +%<=% D/{fH/b/*Dc$Wy_R`'bwyCD b8(a2L"G7MLd ݭ&cBG7 -P)R}rQ/klO0yTzX@.:#+83NȂ/ ,~q@~DXj)NY &@r8u ! ?Yb=,p'z%n܁>]GDɨ͉Dv78*1d4\j,8%ѝV_JM[Y߽ߨZA&Rī,>h+Bŭ1 NVV}eLuCNd#t!MI=Q{C^5Vil9 E{ʺ xB}l!֚7Az$dE|8doKKGA3 ɼ^GpCnA1ZgVƯf筄[)f5-tXϳ8LvCmeכkV.ɦL% j+-r.`+ܐxVcRB޲YB]>#ki|q?3͎)'7&"F'|f9%zcP"[8lo&uB2db~_!qb{c}W7MrH,h[ b_%12~cNU 1 ?MoZp J 2>GLlg''mIhÅq=β|m kpc3$uOa _B}3DMށտEUu3M;pn&EzmDkyՕmB;/ڋւ9)|p]F+ׯ~Lb&9%pőx_?2oHaH,s"{ĜH}ftnH)`C}Sye̊yib.< U\C?f10 ;@N@ QӢ q~ \1B䯏f*2DݐQW=10j)vb?X발6=\h/u#-0F S.Cn>J.4_uW89"{ Q= ٯcO-3= '8D3obQ> /%=ZC_LkO/P2pBOLs-;*zF[~BD?,@ah v(Q߰pE)Kɖu9<2$ףf+ Vy+~yaTVxrp;q?}wS{GR_O-4y{=avp wA[~f}~֪% g%!w1k#|[Rh-|A~y8DSu-%2<0SDBmBnhc*N4Ga/_|  sRNamWm.<+- WϪ{x&syPCIb^]PLT] z?ߦJBT,*⃻ Wt$a4Q ', S?篡vh{nOiaΏ?7Fe{) zk5i-#0G ҅vz"=zJ\L1DP#RWR<+;5] r^uZ>x Y0Zô鐞M0 ҼW֯) ߌK+ YQm0!?_u?ExfM͞K'FlrzI^q{%ڱK'3O~f( ZY]<:p^EQNKj;UVzSq=q6~4v\^!]g|D0{b/o6./6Pz2dC鈷PV/qʫt,h[0B- Ln|\9g[DY |נr8wzS朦}4o FĸFxb6`n>LKl["]\kj=Qo3 B!ڋi._}<"OR x6CuauIc@o%Qf71j.>˶"} qeoɨlI؏u>\]HŖ[PB xzXslgÇW>- ]_;Q#d-rR/M=||NZeLĻPsay @fhC a;U>rlO0sy҃=5|TqomO /QxG~,{r{7?j!@۲El)F@цvGx͡ i1f>tR΢Ƚlbf"քȧH4W߶ܱy;mR/ .CU w/T˯o"MQOf8;q֮g% _ִ"73qax'l+<|]x#M[aU {czχ\W}' m]^i/ Pac ݙMћ ؅9 w"㦗ft?ek8؅J> Müg؅ xG0 b2gfn0MVq Qo=mΈ '%T.e?HimMO `f1_Z3–Ob1AZCxf1B@s܂\dqXnb~_io^E\}=. %~1x.Cč\̟x}`xAX|,8fFBLb 0+]jM÷_VByˆ%)@52{;v0:|0"lAn̈x=);SM cSOEZ7#= !nsdm_Nk4>h Qw1gncr0/!)EG]8 ~˽L P2cڏ{Y}A%bhXMM'e\.@VWYQ6ouAtl8(׌Q*!7rX!"<ϙ -rzqpr?P$? H/hhǶ!4zoMY㨆P " )כ31%6G>_5|.BRjg;y~ɘԓ[f;[vGofvUц!}5/9rL|8<N2Lu{bh>=v5!uaէ=JAo-vC[VՌH[s)y >&aH>7x7w֙hS[ mk)毥ն6bk|^KnKPOR[aa#pߓŠe 'gJ\l~ yy&e0~:vΧq+agSOlND4}FɞX_Z?:~b \HBW`P3SK Цf=d+\M_і5Fc,_hG^{i- !^H<cVEq#Z AT?Q`\eii^ TFD<1& "Կ*Nl MKXV3Yzye񾭿ո߹2#>Spw&2nİൟlZA%ڴEjcH~bAH5+]r9x5|>jzL( ^r~=a]+PC9{}&8DO3|~N7IݛiБkH? e0pj?ZESHi "*c_Y\hMgƏ-)d"8CtD[B{4$QcA4 :!SOyA3|;-O1oc+1<Nd}M}ש'ǡ_QOs<]jh-Bq"zTY|q1L 8CJe Md8MlzpZ6DzgoVRZGnA8'IdFUjW*GVZ 6!n w!2/,4YD3ȯA, ϖM7t ]V^:P}VM? eH]P͟M8S]ZIdP= Z6B>|)s^=a-6a1c#Fh~6MY'02s9PJ-OU< QwݤO4x~TBe#VBsVK{B+ΐA/~Y3a6pm?|ףH| >⩐RHR-Asqgᆮ{ mK,bߔq/|? Z$*k-s־ 't[DԸP N9ӡ!95n5<s e0JM/-,jKLx 7u˭vت$J8!T.'DXa׽sa8mǡTÆGmrwBHSڂ+7]<mK#$R70@OFD?#ݧ8ws%NR6as5 mp p=|L7$ޣ[AsN 3td، *V3&V<=t >9:f&8@6Ŭ} m΂$r8 aMd~n VxXo1x ӂ ?jFzDHwhAʺk0|eLp9aRY1-xeg-¢"tLOx-3 ע &R>Z>FU1V@; OwXD6)m?,6 sy?}m&k?zu6Gܧejh;tc_fFugT?2"']t(?uM hym wѮrr"ݨ" (-8{RΙrOA*A ޗB:G_at@yy+nUtSGGN ƢcA8*$Q!Oh HB;xx܄p -؜f d"iFb){޳-ČX#]Bw]&j{d^Ȑx=ƈs1&n%_צ{8K2 5>!;,<>|L+Ov?^[!b\S)5$vZBRఽP sjIt$ThgHވ6_70e B/f9k_-eM w~}o߼WD{Mf+? Tlq -G,i!t3"bO^2lLD<ƽ:|8<D(2Y?>H%ɡd^ &B|ԿPXFu\3xߚgJ4!6^ j%niVoX|3|q.AEH>8Ok+.|.:?n±jL(\[+WZMzq@|A*} B翎ß/LǡXͅEƷc{ cwOEosq:>n,OD!s>@'fP^wơߌAYeppxөYx?xh-po܂4RDY|˔W)5\ml!.S=L6YcG^_F [CV'8:"/`xO4lBnӳa Y$~ί"V4|-5@1d1DD޼# 8+$ZN\ / M{>%q,ePUݪhQ:q]4 v0!P eu[ɡSH&(ӿWL\lA $Bud9Fثm{/ɜ6F1[0lPr~lR&2< Coz5$>w"Lx=*q>+ 1ĹѦxD&~~!?K=Uw+(I$ ڻB KahGOkjLW3fTW$|mͫ4[Wi[ڷb#TyE_/DC)ff.#%X{Z5h]i%G5fKE;G2ЛMƶZտ1K%ray2pکR#- v"w}Æ&챯{fԳΏ1b xJDs<~3'8fêl W\X5'( 1FfaH}w^'41;)3«A۳􍫖 VJrć4|V7,JA3~_G`"*yEnrk@ .7=pB 7^m|TDCr–.~XurvUXEr8, Y#{y 5GVal92Ѯ]i@1ہgXcr-z"GqВa?['@L{h73cg Z]mR AKpCLN_L(l|?R3϶=Q5jB}Ȕ45KV!t#!$!ZʡVWc#݉Sag!GG Xfr;g{#zV3N^Tn,L`)@;`֧DU9Pxn'yN(>޲bSh zMa h=87S#!"ʚ#: ӡ8R,ta7zB0PC믡x:. ~GLYW@.-pcU  V1$~l`}"h"a}Ҁ>#|QmyEVz1YTEj Uby Oq|IN[?|t\<'Lh(@Z0#9 "E/Ƕs$Vx{m4BA$ׇMV|4ď9Mc0tȢL2XBxi{9܆\xB,O[5W{(LKw @hA fUWEL^Dȱj5{Nvmj_^~Kިz yMX7v$B{_fz/ pkAdd"|G-YM-%o?uͅ)?85Ϳh-!ŕV ~ilZ-D߁i$6$hkh4ox.4s!3#3?ggfD/_9vl/{'[62|ᜦejBI(Cİ!ڧ#rKIՌ|jM Kvz3c} ?Z#\ @A]sjO,5eg q}~͛̕[qupEKц-=BXj./=\m4@2MW{ԧ)|COCF1P=j θN4NIj퇤]f"K'Y{\8 ?s 5|1~]=)(!3'6<#Zu >TCDkk9S) _(99tٙYdr5*$a^j\Њ7B:W%Zѧ '/PIv#r[^Mf0 >RV6b/DƁn"OD;R2G~SifSo3̷Bq$+ oNLْmX!-"v=~x<M!G8b br> aDu3=2bֻm S`abpR 2utPW5|!5 L[c C!>)ul!GCx֣E'A.f-c $F+H)5Tblp=ߣ¹3Ӝl32q?Ll_M*w4y .64hM{aU)PY.^UX$q=#K rp4ܣ(5='"?S&_9tro 3.2sQ9;5 bh%j:&D+Aa ;ĚB%EejEeEz:.Q<7BnBFuYI>ÿEfMq*Q-@z ei iG-!2܇_p+*PWss|x>??mf U=O0>(<[>odռk:Ў7̗KtW8ۑ重%Ff b8{]CAcEAŠbV[g7.p8xտiOn|c׿וX2NʹЂ B{tKIlf!)i$dhn='Gg|dBxO7vװg@ [j3e+8LSƞ31zЉyͅ;xjk( ى;qNb&3/݇)ݺ0Qa}hA 'pAn͌6D 6D^TDɅh_gs2k)+0\m8D#DF( ӟ]ԁ&%9t"s1ff?j}8Of3򖋴RN6?)}qENC!b -0~j\"#j|̇$[$ZG[#D54~zsF%SfxF?y_I#[DֆR/[Uw;~: } s9q8 hK= I͋wͣkn*̮gü Cu@J^D 8;֍*Abσg'F!c̨=>=P>_ne#?l[({phODCHZ͵-?O[hG\_Cx&•7P͏OPCy 2n&@<ߵ^_~mQWq'$a6G,#R3ASpC_3] 7<F'L,GRJWY MjBˉqϸ@ t,}_O?z˲vt3a=Dϐ[P#47Ph 3|AOh%N?(J*ZG]jb.}|9wjG#λgta5!sl>8mCW22w'FekԈi(7$ܱ&A? ŋSa/7@[\E/UO\vy^fr,$s^ǰ: ":0 EjҔi%V|jfنY#`:+3cS/{Т"3Mg~0#K=HS>G-1 3Vc[h&MH"Ex8e#`k^Oѿ92&͠'yE-MC)jx|Q)dx>LHWn}6`79sц^XڵͿhj'&|Ҍ߫3}dO0T==[dF?U 8MH0hc%"N؈S!GO!eFJc:0K<8,Wt?~SW<#cM#\]-9qOHvHhGXbe]gڏY ͫ }^ y8E; 5/i2XB9V~g+!&.Bw*-_=?ǫzPݰ91|{bCM<bfWFP7͡A9Z3\"@ӏտϡM˙M8/A$qϯzլv @؈?wo\oE}5z~}l!|"ln< }x?eW|CjHCQd%Ad5N.Zhǃk4VjCh7[kAڊa K9x_~G X2yth=qe7zQ+5aAM܂rEpabش{q|nV'2}),#ů/VZbĢ1d&@F\g3&XQGoE3H22_%`٬nzsli޼Z)p׿ߐJՕe1/^?_ ae]7 fݦ5̙նSbLHC`i=CG>:䏡ɜ 8ֳ%zYl (ܚ"}x_X݇3=3<{ótdIm|޴2 ])LU2t8:kiEϤ=ެS%y<*_\("T &% cּt|"{fz:j:/ڋXz戗'x™mvUfw !/r>*~%k3V ?1Ur2, t:huÇmHT|Կ=0W|Ͽs? ӄHo[8v!ve"PtCc#/tZHZfxe+[J:1skeԿR9 Im 0g^ނT/Kgd}z>!߻Qc zD^68 *3y" 3 z^Fl3z@ ߥ)͜U?5&s|fMpv)Iku`vrWŲ[ӾQ8sf(X;j?Ęvt(IpgI4̭XчUP0[o=4;j: m~Hݪzg4M3ѐR2C eqGn Y9 )c$m"VP!2',nobO `>B IqWǡ,@ʣg%7;3_n̲J 2gQ6qfޭZݩ]j~00p=_Uy{ xT = yqCʧ$NcXMGkz,2O]Vrz(5h7Ճ?AQx]hAz⣊ǾCK wt~4 $tC-+l.@?R5e Iq8\Ape`f/~1RAjl-fOM[%jTȏ`<{ jGCiǐu--tj.'BO0_?^dn‡ e~'d̉bkyBԵuXzKN'Oz<= UyQԀG?SS"̂Hk !VXc$e$3YћUCU_PcĐUV!#G 686}M9'g$nueoUhHaXFUk%{d=M՛ pޏڈh{ sLs ZDHbՕ:j;+S_sK}"u{D) iAHɅFEBG=s{}h؈fup^!$d[?b=P;Ϟz>d:Tǡ8O̅l*0evܡY$0R4r#VI^+Xa>F3+uzC ibP֮|E]>w[xe8bd,P[ d+l { HDK23: # ͤv?QRW\=hP*eӆ\oN6<{k07r2l(C^g\+$:G[>~r6y??rŭi1jv~Ο#N#v/h^!ڍ.;}@c?2ZZGhg[+$;nF4RE7 G:GmHZس 1+~&2܎5FG*0-b$DHF;t |z4WFE^h*g2jsE'HQ~_LqGu`m/b/؇t垵4'4|;09  }Jcl!סŌS7pAH%YwQ~$L\#D4|A 3)v׬q~ ? :R?vw$Q+7$ֱ)"{ǐދ>԰WlƒIqe~ H+PBmmO'OaN@/qGh:珶{^ٷoUϹ//PE2!))(d 8)GeY0 3Iύ N'vH'H$K(&uk_k1Zϡ$J3~k׮Ǫ{`s 5D0؋ +$JB8 'B c2X9>Ov(DAIQf"GmD!) |ӨᶜR"7̻Lŧr4!B!ī\9:8:`7B YiϊJ:{G}tj0HЈβGg],%( OdcS Q'ZD=r~緤l<;IhB!BWgPYɜ˷ؒ{b-ϰrj¶{bMyxIq.lvFaS,Xb0cac S|(q *e wo7Jm̽(HaDf9vB!BrBCksc$괟6 \߷"7'qGUa< #b9Yi`"_HVCl9GTS9<O!B!xEOs:F>z|8"'>} ^(jȋ? E2D.Rx#5.;`9 !)>J^Z3P(y_#g>ccvB!Bj|d6<|P5_(ay&o$6މ\ɾ}RDA%izeKbQQE:6+N!B!+рvݐxbXC{K-1ZF8(3Hs-v]. Ʈ"NŤ]Xo=?r4!B!+(4{=m<0Fgn\ |MBaKbߩ=c $5S悉D&Ŏd4S^Y9BSX, 7$4!B!ī'4|]4Zܙ } M#J+δ$q 3`0̙ᬲ82`q,0) -ߌ E%ǧ7!B!xx`f8×~[j 8v.DnK}rɥLuZ**-.Rf)̛Ss/(]`;,)J'o+s]WW_B!BJçPbؖ-"OpyD.z b(u1__>f~]MF2 RT ]PB؞$" (^bq] V<}sI.rU,\.SB!BJ5|-\("aWt,͌l"`E)aA6/tԥJNV?;A~1a6G،cGA?+v3bf<}?pu?3!B!xu`@Kq"a 6$.\Q%a_)Ğ\ME˅KPa9.p4>1LtH3V:<3f݆yG#r4!B!+GаX؟ov+pdcqEo&TŽ#?0;}H dR?DJry1u'AÔk B!B* W˸hb/ŹM r&2LK(gvBV֚*AU(:\: B!?x:lȔ?`Qb;CŹPL ܱ;nqmoX  B߂ iK/cXQ %8Ty~P!B!xX}k %<'2$ႬpT"K>"˳CQ@##?cKbB-`3ߧX b_vA'B[6W})erwZ:/ kEE\77O !B!p^o֢d?`nxaZą5vaUm1<"Q< `rLݶ`U1PF) 'l4A\JoK 9Px1OM!B!^>yu=Fa bOXV޿*vkklP jg( [2_CrGig 5G 94hDV<<]?R:C&gh(WiWn&B!*&J9CtJ<:E).8pF?Na*m^x tMAOR0C.9M. Gx_XΐD D0y΀״BG䭄!B!x%͛1]"cr\Gt_mcgXk5Ec-:H#$?))14ĭ9PlK%6 B}8!z8W90qs/uff B!puJ bWt.>B}-% |۸#ckK xB 156/0QItq{r'pzF!$D(C pwÃ~Ҏ!B!SNf?|:uT?"*‹&U_tG5Ź`7Dl</:]FwjH͔`)0Dwht;8)r'JG|X1 nbF]?xK!B!WW׭i~shOVge^. 4I\ER[{( .n E=(bd`霞vLx+ũ#[*HpKDK B!t>uu=ЙB6?<sV>x!C ,)vNv[孍Rd|#śi'bQ0ͲaQC[Y-Q#*kŦF0#4l$D'TFB!B6?qs'vEp-ŅI/-ʐ< ck/zą8Mh@X, a }9٭@hFOMD-lrV Jxʘ3 ~;w25!B!w+ZgHG~q0NdZ(##l&f{9Kxs3q1%Ro#)O4!Lل00Ny^'B!_^'kk̀{)a XqLl(X-$P旱yX\ir|?\9İY͗\'`V09 l7(ZXk %\: ӳ'B!\fuKbo%]GL<}va`y(;U@R X JQ _({mD9pm̦y 9(끫 4*@tJ#`%ZMhI/M?F4wãB!ond$X\XkF\EDxZbXϳF-x>Oz؝?@oR,ZϢ$(4̻U%CB?llD pmtEj =Â1+.(A!B!>|0Ȫ2 b?Q<1s~e`vXm [WY$nV5dL-d{V#,bOE9V*O(9~!,R"Eq z xEr B!B?=>q*c'gKY b؎Ecn{Pck$J#8gY(EȽv~SK"#R0C$+Xn]y͢Q½[` S+nڞB!Bބ.1bf=nӰ (~-\$.`K|<15F]Wx:s -  2V /x<4䖈R~_D@[eCyČ gR`,̌_)7| ?>P!B!>PBYdL q\,)4Jg(YD'x"@a/H;^haGs/SB!B|@혢?g1UbXz|V孄Չ b#kMa*[Pv-O 2Yq naUu?belԏ%s!9?BԠGre@5gSB!B_Έ |42꼙mf%l'2v5q»8'ie`Ű$,:%P2 da< #4YD"2nX>?왶'B!57}snj`@| },Bݸw̐m4v~q Eb/]]vŒ<ܧ.@eyc2*hEB+ȡDw/s)#I`p !9 O=;=}AB!Bs77a#na0.C~%ɧo͌,7+jBi؞eÖO;Ɲ3vN~NLH 6YPnNϋEe5N|Biӽiwa33g)B!w~60yƇ4oB<xBX^&NrK?"^3 = Q0Yv{t0cq7.KTeyƓ>hQlQ/Alo밍\} VB!B~X8L w\}c-P{+hfDx"Pl#<TZ:Ͽl]£{iP=(m˷L Ź,lȴpDi͘sZ߇qyD:ka5|QB!B77ws`، cIO}G(.u[Nqa55$b07o(r>hG sFPXci?ƀzKBg>_Ȱ% =LDlx2vavk2B!k}vX~(Y6ѯ-1M-l3?QɎ%l Up4̶PŻ4 WHbK |ONZEieZP.5* pck)R!B!w01 [c<}a9j͘DA@Q?U|݈aff-v1DD?)$c nZj#<sVd䃘; >^J[wqEXlG.=3OT!B!_s}ѫ+ }¾K -WĄuXl FX ^}Az@, j\Tc]&YRnΧ畊XbE g|H,ქTѩ.2U/j|KJ5'B!Wz}8>f~~j: t~ؒ 2lCrQyN `Pw(,#h fvSnK"!gZ0CXGJǼF@&B ǁ0O={|֚JB!3CTx^K js[<"JĘ oհ%|Gd<)߀4"ykQ6Cv ._bKj2F|p70@Dq ͿL\qOLߡ8X/=A!B!7|&DŽِ} F14Ay͑ Jخrܲ~]Pu<=˖0H_0I":Y`"Y$gpDd:滼=P{$F뉏m |HH!B!xyw1W-EX,u_ lV$3n~MQI ,z҈nOPՑo⡑p]eF Ѣ" k  ENæ0;/a/-gpıF/<>U!B!|#W'wbvPXL /8`RRm]X28a,X}"Qz5Y*+`[?,eب| zNbt~wp[8rjU2M]S Dw>$0;VfTq\>?W!B!xKaue'sY?z,3G`!r廿WbU֧fU'|\'f.k.2^B@ ;a Ȋή#Sn8J+yc}>T.F?vwwwB!B2?~}cWC;Y/5! -#5 Hs;n& *z/v1 }`56ri:Y!0aMf,\j 634M5em`{xl q SD '17=v&',Pdc1G#4t8J Gv&,0ffnB!GO&ĮD_HJĘ Iw6Aˉ ebm%!wV[ 5 3"a_n=PmNK@Ki<=a" 19&F5~ì%5!B!{_oX"Fz5tK a BFDHi .l%KĺQ7` /6}.uiJ=!0rrֻx=QQ9z`xCq& !@+ !B!{7Z;ٹp GZ$ Lyz E]oq" ljx"K<0 ޣu9}-WN7AHxB,L)|a>,o*$ַxAFϏ 3c-bwF3t3{X!B!k|zxN]Cc;_\-Я, QB` - nPrʒQL [{*(\i|F/XxQNiHmI)K /2mFl* ʒpDne,a ! A:Cz`;Cg޾A!B!Cڗ–Տku`̵#a^}=rޚB^2/D^`NHE5y$ hYe-\^B9 a&)n+,8br_E<(!0&Ğ  m>F ]HA8&ъqT B!%pECW>/D"У}Rf({ נ=M/H%{MȂNwR EYt 8@ԙ,4EP(mӆ<,2 ECACEXߚŖ2 gB!B=-J" 4ڪ^Ϧ ImZ䧈K|^Tn |{f:_Ew B! ~dcHi1`NChװf1>)lŅ:// \a3w餘k32x?``nI2Gb$rtGMяDTT`X|F uSTȐXF !'U!B!_ 8~&؜>Cڑw n:1dO9$r~-ƄUqsTbAd'@Cbf#q'`\&a9p#|_MAB.؏6Kc)Y F28nc7oB!/KqPF@ GZr }jЕT`_`irdIgxvmn"ߔ}DSej^ >E,T-0  -ӡ`>L MA) = n~k03B!B,>s}ۮM}_Nea~XAXIfV] :b@~疄y@^\A) fnяn- Qf7O/"B!ϙ~|-FDE#Zot\|/.TQR oXy7j(BJ*,?KY ^3lf@XrXl Ģ;3.adu`&\ ͌] >{PƒO W?B!/4B&0VŔݖ6>1̃1c_ 93"n/TezYzڹaT(L h/(vĴր,,Xu rW%-ɔC9kQƻc8tFKoDq6^~:/\!B!"yWg74im 1;2/u )s!@X]0UHxPPӐo@6>esչK e/),yfBZ =ur4,^ڣ6Kbbazr0K!B!kwCG9Dڜ漛u KMH SÒ#..ׄ ?QqQUߎGC [j2HOhpKI3#ԑO*'b<x(pF*p1`)(h66"`g~FUB!B_]݌{A @c]` C|| K l"`<,".,i ],,OLqF*5`-0RОWm$H 0iSq8Տ*<.sQ(RbB~[F ]k2{`Xԍ~kPr|/*C@2F[u%"+Xu3/+QJ(h"h;Ycj'!Te#q.O16ߞ A q[’qEW,~~F" 1 c#2Yri3EldW_IB!BkCxG6'8E,7 nQisbJ_$+l Q%|e(y,8A;)3e6.0މ@5Ӏ]B>%6";٩?ؐzfuup44ڕ8~ZF-J;JSzb~7OB!Bk @k#De-^K,;>rvK>2H6zX'tG"9Xjt($]`9gv.tm#1_`\Pޓ+EAٶj/ҪE}l?&B=c= 9z.osd4>{gZB!B?7t{_;j&1v%Ùw${°ã*̈HB_Cz4=4sCD\`$=A?cҞ- L /̖ʢ/EؒFi!.D)?`?6l p#^UrBvkz0+=>40o./W_#W@!B!|tՇbhCRnI`$5s%m8a|)Ƞ>u.MeԷ`?XV!J}4c7_ߗ(w]{5*$RW `:'<7d`qX,wCNh䴅ތA,Ga0/[~\y2P@_$"7ut;!a,)w,JDSj`f#la7*k->Sd<x'Ɓ?8;/nwm%ȯr͘M l%"K RϼFi0/u B!~NWټ.Ml01v%cF'y4…ɿ`X4 )=yL ;"F#̐B)wNݓ\ QYxzw:Jnr~@O{sD*78"7 ia]B!B?+wӐN>} }^ 0 |w)apF(B;S2{\&5 {o. )1J, 1M 2DNd<>Z鼰fD:*X@ Fϔ?idaTҼg@g:2.7B^y Hլ[o>kM:!B!3>>6ډ(Z.OeaX>Ȁ<8ڪ,)XiB;wL`<@`"j"bs97_ZDžkz2mI F.*<t}%20Ld[QV+ rCbpt[N 5ӻvo-A!B!'Ch cVpkG.cgF)<&cҟ =/, py]K+ ؅9ȳݖ<\]#xqI829@՚kgQĞ$7 ȳ@|MC80(\A(#Y)k> $7tDW<~_WXB!B|Ï]]\$;(ֆ?!r pkkmVZ)[dp\Of_cn^Li2g݁-kӽXvBaɄ@t4OﶪYx,uU{B;nyn3!!_M؞8IYkGEODP LSôW=B!Bs77_C8.0|)cKo#\05tBQ2vqIl7wD .([H]B| |ɢs4b+l> /[ǨqfY,[PŞ0S 5Ɠa a76Ă(5 Rq(J鷟}*Cڛo~Z^!B!|tGAHv3p4}0cZQ0s1Մ@:|&)O.l[N'> ߗ9-nKeϡELdX F %N_%NdGv+ ԋ;*IϷ5?|Tz I9=| [ƼuSC/Vm֦7kmd:X" n|;C !B!e||v w7[s+cjۨ1G-+<"=[+^ۗMmNK |e2 [#sM0LSCx΅tklV$lB) 5B'/}wO "Y S_OCkY#9L[5ko_]oBr!B!ۧ6ۘǐ\65 !₍ga|׸fQ]3%X֍ݽҀ7tZj儥WQ|Lk@R%2[,K%,R#N"ŖKE,X"cHA=Hp%&Unp,P Sp 9 дX3(R!B!vç'NBk3Ϭu;5BrDN;C0$0?T 5b1 νNNF[0] X4PUk`g_]Dw4 mFy:FG r}*6E,RE:p 6qGN/N H 9n| 0(lBŗ3 "B!̗oo|{z7 @~Lgͻ05Pc [s&ak{$(!FSxBޏpD=9 ą2zgF#}~mX(\AAº1A19vvG,L0eQbFJɞ$Q'`%y<"VSZ3Ay`mnY!0 m3g@TŊ_yO!B!8RR h!n3tؒ8.ypyW+F׏ٓ5"K.!=%2P'HâD8]"؈Fט[<6pi²2Tϱ 4Ӌ4a)^.ٛq~󃕅*H1bE]@.LiYsL l@[=è3C"{H07ǯ_!B!᫫_|l]A %ч1>u qV.2#[J<瘃IZ,Y>I.UqzS@K!ؐg@f 6 %DjÌn+#B!xuO\]Uǁ@L9+-SEa5LC\9 -l8=sc^ F [k lKfŋPo\ux4oK"ziꖇ5Hrf^q٬AkZlf!hjElL4Cs C0Gon[o]IkB!B\g?zu5VCo}E[3?_?yNghÿ`0we`@mP>C_"֛}}>Xb~pd(I?Z2md`Y2 #==8xyB,^?_51{.<ުXW13B(%S ;D2T釔|u({6x4}7|$A!BAdϞ}T^Hy80BST~I ֿEyNZ@ A3!#hc Z0o 0҇mBw]%EtsKe}%r 4. y,\:y ME C_a. =4ꊸ/%>B!`ߙ#e} o a$oy"Ƿ33 YD285v2%|Q7(؏`V3v.œ=l6g#`5Q$G*D,uEe cևbʰ<"dA+@ i  4ph"\{%R`kB!B|@9}ccoiؘ> -/Fw!ntc, %p*:s2xJzBef bI \pZ@a‡~Ns[:9wj502wii3ztVGufgŬ5۰vw !wkB!B|2g܌`]PTrUv%-y7?t ]vf~[͛5ռYkE=z!B!{z#rS>>yؚ5B)ғ-$G?9˥t’zt[ύ4ɥS4nY m#Uk ahd i{%K\ ^RdA SYԙ$-{8n~>ف46wڀ!a/6W09?zGi B!B3?zGNW)gE7#{ʼ0? Ih =1}$PH)8w2ˁ khG|`T1_<1ORCiGFCx$,28X _0+#HYo1 6egI`|4>oX[N\rr?ro0N1 }ԵC*1/4WƷ{}7N'$B!x?FkON-SOİw8֧6D7)\hpKiǗ˨y@.A -5=Y*oy~7Q` ʡ֫|3,v ssoh0'vp2fdK`A6V r}a.z|,F%9X[6Da4`(05@9#!VƟJ~w>?t}B!/~tgt ǻib&\)cK &؋:[N^H8͌Ϳ4aGG|_)rf9,&HRȥ<O+NG ZQʥv"6oPl?ECtXc#<076Kr\x/е=j&F lC}Y&F!%G=o~'B!O\_[diں>@Tg1Ok0?0> uӼizjq@ ;C2/=Y[$°@^nd79*q~݉G`11[˱ K Ne)0|!8&@_dKFFC*̹"nOG&UG0f5ΐs=]%B!xjM4.`pd8Nf'p?=nNiv>Х -<uoI=5E[f6 הr(a):8~5V Fc)g.xZ=Ģ}̽ ;ј!KtwZTahH.m'ϘfUwq˱Rނ_n`Ԯs.E?aSSdC?Yٝ<9'j0{wGB!GNy20(yNYD80lHH~?v"OpTm C_@1ob$~#%x˼gxDV2pO[\uYT:ng"m#a'<~Oƺ`:KXk#aى(Iz@=I=?R.v~@q[HXaQ)օ@/5.:$>}ɟ3!B!_:רa|q_Y#82#!с6No<ű޳!`Sb]H2\7/RYú4u~9󅵚F/[Οe~cubLRwh "BH%R $1ɑZ=UC@q,wL+BCt8s8zM0S- k#|w:B=Kt\x~#N炍Єna8ÎGp6ƯJ3 Gc/OW[]w0ϿI3?5눖 7}|7 B! w?yb!5MhCߦTb$2RXK?%fapHt= `hQi&`sv5 %W;$ nHJp/Y_Xv1pa~g?t<Mc8 'I*J 0%ЊȬ}OKKj%s_WEmx7!)_v44t;q chԮh-7'vSὀ'onɇ?['B!SWWO=J#8&0H\hi\2<5[*C8"@ GAGG*,yED;s wK!B!/(^+^/taO82qĎf Ȁ{. "x2B(W'j ϫN4oZXaD0|J;e~ϲ=O,hIHccp[$9`Ɂ X-yK5y&58EXpR0(CJqzgc8wR6.V GO΁s_h}6( yKgo)B!ˇǏN[xp1fؒ8HǮf.Nh׌~q{cHX^H%5i/hJO2<0^W'ysDc;U8phnrbP 1j տ̛uvELo8#K_1_Y*ok̬xEz}ʪc6.x<glDHjXyFB_!c †5 GICñLaGF%u?wَv6l=ny>.`~#frq}S{B!B}nxZUcgavLԍӑp(iHY1A)$2&|j ) 5ܶ/P<hɼ|_d2̧%b̓(ono5F(&FΈb,"lj`94kT!1t8|J 9x݉plG-560 %v3@;o)!%hapcx}\8;ڱR;OA/3wUHB!%+8(`)F$;r )/[}rD >cX*C/0!{Ka"lc.9dp\<E4fc#xc~O =wI4fap+Hͦs[i.\˒36P~V]Z ,FPgtH2'cאF/.6)z1yłkO?v:~ڤB!B\Ov3یfBz-#^4 cB7/]P刱IEeޘ\fGi[cDR`fy^6.剾HO̿Li~'Qv,p@nEȫA`Jl𙦈R_O|Ő<$|Ͱxr )Kޭ#t @ttrw!uuf Ig7?+A!BAWn(`|b`#S!Gt[\:CO6Z-Ef# ?Bْ0hKc$N*&;;6՟p.\L๛4kkww.#pu!bx#:#f4-2``4[{6ͅ|2/BQCe GCm6fby(,q~f 8z+}o>k?ɇoS!B!ի_p;Yz\n8|K$] BЀ{TQ_(-g1`J@t\@}.w02dߏW zB3aǟ\O#$~-NHsHw3툊l Tv27oOB!,9~ǯIbvJX?+ 6 #Ƅ!"*C0bh(1 J<pD? ;M$;G0le YelXӬ^S I*gg ":萞rO AOR˻iJTWZJ.TTX}])caTH~lPuOl>z(zDp{]*xݸq;aq772#p`5758oRQ!Dt-viwε)<@,;_HOȱ eSْG҅y( Hyۅ {i7]|*x|,A|p +$n8 fgٻay=Ua:ώw.sC2/ARKu?wo}_|ߐ B!ZonN!1Dܣm }$:hmOr.CXȿpi2Pi^hQAK{M.Y^unB,7䁶lUa9q)4 /dG ]0I;}(GwFʭA\σ%Ÿ syl8F~DOpB5X kh0kmͲbVXpvcRXJ?57nE1 nvw]$Y^?uGZB!ۭ}s77WYv Z}Gb0.sx%*sM986΋ZJ]5h~MwCȾ5Wtlj/r߰ˮZ{|mE(L= O}A v͕G%{뱫0Bk ng$KO@yÈ<̦qD7͛Gk, nfeE0^ } L6mN CeL؋ GvXZ02w[{ay*ˀ[Yl ʹoБqp9p*7׭ @/#rvo+Wvv,uXD} EHlh$i\R_ z &`K4,HH@əq*PߙYUw.wzwZbL탵Ƕ!I^(-/" +DF#Pm@aGV$ĮW"A~"B$?^xu:^x_ՁyVZk hUԺKeh-@v^%udADYQ!m+Hݨ\¼%x|ď6@IOVQ*`lYoO,;@a4NE#)`s0@#J!)"('APrB#0 Ep~= XMɁ#f-n{v %yr!^755nս_X!b ȴc3NEO|Ͼo~5_:^xu?@oomCaMmk%h @}+ rD)*C;,jLdX_[8T"Nb|n@Q/ 6RT$^Ï@&$x#tpzX h) 6By~g߮E8@Ž(5P5FY 5 ~OsAcj,[?BK*hxY kʟfv* G+ʝ`}?ީ_{Kb /KqC`R*D@tCH& CRwCR :%"8:^xul7V jv X Dh,hDȺH㝖_ [HU4An% Æ5!rդZQ¨J.+އA#BghǛJA(4xi0~W擉ol&~W[XOԝcB@JV ~C]^&QV c#tON'efB-ڋ[IA0TF 'ylD;m哝%5'iR!Yr* w@bV#PI:@\S!#%ZX;__o~w/xu:^xOp.|/ 2&Љ ȹ .Ci6wJDc䒍ФKZN@oiw=, 1L 4pbLn *v]{6$'y :k'S 4He@@ٯ,0%HPMC:I؛}%)1&a@Ago,}^JI6.%"NC+YNþ34JB,@c4_v:Z`Ҏv}/X[$NR;yY5=A]z~/Eqxu:^x㽏ψ'?ϟ+"w\iz]BTLlP$T GmX/L^4ђUrvэ6$) .[ym!N?>ӣ%ؘ XYX}<T8b0() dwhF eLI 8!d4-fzoշ(:]l\`rVi*E)@4RTDhi|z w"C,:6h4b3sJp(* %߿_:^xu:n/ooϙ<֠f:YwEdؠ+5l##(~rVLk82htI#qst`Ji!3<`Eޟ́h:iЌHD@+If!p"X4 +(jRe1$/x #xNN"iW9{~\/[[. yN4EjJc-*Y3;&Xb} ёي~Y^F&` qfTX&Tdh}_~_~|z$:^xuqm÷?|߽}"~h`q'R!Ͱ w26lҏSс<2F& H.'kG{#u 6x).A@&ӻa|5,5^ 5}.Y3`2FCM D^S#Ē+ahw¾5B\vw/GrZY BM"tCа4m %)ˏww~x^xu:^9?}GJ!F^h? Aa-Č@('^ ?nЦJWJdk[+\he@Qbt mFI 1A` s h#6H4ߎt썚 `#|? J8 50Y :33UAƁjKEA0d#8T.5e5MP:\ҾÎSmlydxs?% -Q&Fg8ne`_b RVP ձu:^xuv_ӧ_|zo?}5 )AaON&dDbG`j% dI * ]"p؈>!֕]PcJy eN^@ֱG lLѲdgJJҴB\F\lkE 3 vd,A<ñCZ6z#Y2%o~˗?|e^xu:^i>}oO?{zp&c=&_" ҐuhB@LAh%>,Tl}.@&D(A]P@Pe8*&xKmſvV^DAxSğ337Ke,H$&TU#\$Qrb5 /?~?~?߽u:^x'w.?|O_oT-!nJB*>M&jR "DzDep \:~ >LD,|: S3;tp+& OSk`mсb`oforlǿ|?~T:^xu:@EOh6 ٢{_(R H ze@D (JkhIAdb a#,%UeXfPd [ͦQ Pu+k@dj Q9tC>2o*:ſ V&:OpB~ߞM0*y:{HӫL'a) _.G )Pp |p~$ xZ ^C6p4u`$}_NPkΗt(DVڕ*ԉ#Hgg|G䩍x$/e}}};v߿#G)Y]_yu:^xCQ"g?G9 n!n֝\ϩBDDE^P9!%=IE`}%"C׀.hR>vBi!B2U\Qd,QVmmށ T\?0B ƛ6~wW%F'vZ\Mlm6Ip(kK?U\[Ahi ),spn9LdR Mv?u-t(P9~ 6[oV N{0@K%)`cwh HUp'B8a(cvzfVD]zC :A"TE%柈O2JI$fE6*I.>2]9<O t?%tVbڃnsVoEs>r~x\p'sy۫x}3 <ꣵ dDzu/$X,I1 Pe(TePC$5 Ap ҫ&G'C hsza@#_, };CJB7$W$P4QR R =!S,DL*^OŹIy6plD llQUH&zTokJ=1yueD7XcA3 , ,Z1K84! pGت$F[j Β [q`CܱnК܁CK7a8Y4 O6j +t;_ Cݮ)=,dH ?n8V>xI:Vœ'sɜ|?>,-L[g'$ A;nzUdK$zxL$/!2 2}N[`܄@,^bjw*՝ѪFڢ Y *q_$^2H,2H= 4<vi VEPmhF0xINEU425 $", A$:=o 6GI93Zd@&o\ONTa+%p) @!tt#_l &.E8L" vƒ B$8!vbo}(X27P6J9״]馲 d)8{'Jd@\sD[LVct/$xwI}sWqU<w燏I̹'y9p?d}2;oӏS"lg([W,,C8OR!24.]GQph.׀,n(떼8T!ZҡW'𲋝<@(*&"Y(_iΠ$`2CFw$BBa&Йs0-0nuUxR ^>^*@UH9CGL97K㝣EiqXJ1aC c#n/Ou}Q=A Ms:oMm3i +gkbL|Z*4R{PUy'wUaц<T"l%` ĝhĽ ty*d|5yqygu>z~傞f;xh BVMa@VX_$ Ctkz PJk PD&?e]@<RrBQv`]-e"j Y+q4+҈Z +P0n8{p=Yt OEO@"-w<<30$ _hqQ_ޠi3( ]{ҌK|'I<{k ` D5PJR1qd<N^,)rQQOALj f^=f=R9@'#?} ~fJX`WOϙ=svyaH0?9s+<<Np73N̷c{H˛=7Ԝ!_Zv8@/N_{pt91k B9ʐ/&t\I|Ea;Bc,dzCTRC>YdB/][1  n"dNe[rvEM[/%nzZf e14!DJ0,-D΄.fZɌq/m2Q*HV#^25nyPC"P;J I [j*%*/ JaP؁v:T!;aCuD2gkKzA+8hC'20XrA O9D̓.9qkkHx|e*}w3|?OOv{z&6o~yomY{mts_ '?;l_ "h/d2?Z4d1@Q| jh" 2M* ="+8HU3/pcr$AuYM@ OLb3@ -:M(#i(-h;h0xbxI2gy2iKBp\ IoB*=R KagA~OC-euUUB==ޥB: ;ъӡRBb;[@4a C~]ǽӓ9\-cORz«}sjb׼3`zx^åSϏ~=>ߞg`8r44GrU[H¡&J\Aاt \B--MP%}x VyTU # G=uB!XW(1]1L?bFgp [xR dtϖhHRLf@F^o*OqEmC'I<h3RM/Z DDD;.(X h"@^4Y6s7͡)zZYc0-ِK6.Jd }X/yG Ay8c@43n hZ{yj2;JC<ݞ?twN3^>dx~9_=6OU/kqSܑ_Pyze½k_709{TnCD+ S hYG/ {~*siuPt7Є!fDm9QG~LK"V6ܶ"+s1":%t &+0 FpQL230#Fjdj @E)cQ$?D3NeOx XQ%%X GHuCDEi*Zz&ZDiNB R -` U 0GB?a-/ zHĤx\LTԥcOr@u8 4S:XN'K%=!n"'2lڰCJ(\jm&jXBGdnD̀@{EI r9绚t|EJ7\;:t /U7֮r hYg_8b%Pm}*޴^L&F zHL ۑHm/=7:BQL\s J0ӽSfA?$q){niz?#hrsA9<@-(s 5,'VEġQv8zU--{ z%s %P[Pd#*de;XADA 1H*JM:D~>i$~>`.:Lix<#H47> "<f(i'1 N|9''L/RSAO:L˝ГhAzt<[d󅢶Ɠ etG&ى-ȃxo<0Aƻw_Ȳ}La0| 8zF 23_Dgt|- NN'|+(#C98Dlj|']w 3(IlϏpgěGxv"|f~9_ 'ԩ;::rB܄DؗoV! L 5Qgd:bxx`:5PUogm U|akE=5ǁ^VI 9ڲ +sP'~-H|7<*hF7rAzG]9/de<Ǯ @hǰ D9X*QL tvSmWl3*R5$np0 ꋝRd} }ؙdiq6Jj2E䲾 쟀dm4Fyt?q #+bw%ׇ̈́xr|`anB(s:m;TZJa[ޡ!XJn8j9l:fRkx&T IJy8A22 `2$ %?]6e0Qw # {vw(><6g[ߘ@Hٱxϣ59O1DD.?j֦tJmXtPWjy;t4?-=mjRN//~hZTXB9 N< lYa'߫0?XI1UX Ho8Ekv"eh<ٺƓR 1<|y1R< NoE7ҒI6a4Fq*.@A@=tMᖈndn Y\0w3o H'OK|?< 6?6fۀ3|g xw(QV j}H H =P y!(K$z0p.PY&!%1/Z,lm5"/0}?z;@N@q?#п#[籡 C )CʑxLGCHq]c?@" W$նͮCdìIk0j=Dei#A HIHRC`̅q?/=RJk ⏂ cȨx ̕sÈfKM^$: t͏iēF|tByOd=?SxO5wh#: TyV&I0 ;.P$m=EKF兦X!׃D.P3 =‰ uSUIq2MdNϷ#7>Oы7ir}xZ̢1~-[涣H97a!8^TucsGyjpOg Ĵ JZ5I PФ"G E{} B`JMq6t֥BJb4Ԇ,2`iY+km~|7ȶnf p>j_IWQ-0c x}+?9fd?& 9ص8aioN"w?4ra=Op.͛` J$&"h!J& Z| 5Tl/) M&PLBR1j~eЄ`zG'G$","pa$0N(ݪ61Ϭbo"H<`'+| = T ~@'HPcU F<O/"a~- -p0ι#`' ?'\RN2.fЛV/PBr_ؐ7#'P5#D.p4'Njh@Zؓ[3UJUܞ||B;ſx6F 2 İ<5|W9 l_s6K4݀`D¶&w[!_ {Ϲvۦ~X*>]__^I|9'aԞ#9_2;yG[9QJidZtxȮDd ՊR:JpI!Pex,7;&2&cxsƜ³A6N<,D`0ö*H)|^@ =H򐭛Α-p]{F0! {-(}+hC C/Be,[&yx~#DV%!=IR<퀏g l7D-j*n9r((tM]Ǔ GC ղNA&TH8jڂi4E?AlQ==`  9MV&g|ft2@Nv}kvx᫚Z澑}94皻=*;ΟJdNXu?\p;A?3BE|/|gsn3޵S93phѰ^zd'Dv#1u@#'D$_D\Cuc`$^Sh U!UfAD~]:jCd+$cege`V+1?/(_w_!'VID@˲0t [ހfpڇA 0\{:Aw鼪~qO XAOE ~Ban0 P)hNj3/5l_oK {ny tƗ矽>ߣ:p|~e'>_Sp?0zw6n2Onk:ΐ^m9}*o]2;Hh 1%br sA_ Zq0B aMrgE[MH#qTdXѓO{p[r(g-A/*dHʁhz0k_NO<q5=U mwgopɁ<auxC%\`2h"Zt"zO5|Kϫp*Gs?dɟn9?|+ ms?z3ۭ=Z=Q#Vx߁5V;,6$p5Hp @^CٺWѲ*L7ͣIt`o0^A/TiYw?/ ݡʮ\$+9I=K? a~<~' 'oJh*Ah R %%=5eUő`)bOD+y~8sdE ޴)VrrBoAn7R6.J-zF|^t;NAU-`j Y "k8E$ObxR (O¨w1 <_ o3w5H>Vx[p{Dz?C rJYCb`,VO'@ ;aŜblUEHI??M\`~|=rgo7ښp9[*ǜ%_ F]¤bd8>8 P4KR`` B(8Nԟ4 V%EU"m;I9_3_6~\:~wTĿkyNx94 ^T6WU@ z٬qllcrzO\ӷ v t@zJIK_fO7 4wZB5 Q 5A* |Sj42l+paI2rvf*BڜqC>xa#7F7s%8î}IguG=l}hCG넻3|<Ětkn_z)s~ koIrgC_rB,5JȏH)^V:k_{-+S)YCP~Ae=C d!Rw' jMDgWЃ\`|h*[t='-4L^'(OK_I@uZwqC}5w9-px5៧x]#Z /U:̎Yϋ$qxN4q|S`?`xDs 0ϨE4=L4y:/_(>9z~?i,JD~)Sd 2yHi"XꁘBx0_t C) %LNb KxHфc42HέtP7 ;@ `_aIDO#tAgנl\r Z8"0u O l~d ϰ.<,*it *P`/E( UgdKTy[K_0$(-go[zXO6^_[3뙣r{!Mx$|;@aQΟ.Y<&nUV懇oYǥI|/FZOytO DDc҉j$z;z_$x}TC* MB 'dԌ{*B pZ3+k䟎sAM_-M4`]#pF>A _G7y|'OoV9QǬ~7s`'{H֘02A) L1A4(SE/BDv1ZKe>~$0sUdx] S= s#Yi :B=x?<}bN2?:%xT1F.ÒLNx {f3^MS4NO9o7gf~e̷s^_#7-!{_X_2%x?gVDFg񜝮xp=&A/`8J$JJHV2㟷/RV:! ^\ _' 8SwU{w|ϩE'L3W+qg UNH<N'nҟ:,U_8Г<'R ]Q48O[?3z4x%6 :I?q&F'ϭ/PJ)R`*)/ [GHT77&4eO7x2!'ie,d4AzPhF9rdeި;.k.0a4?g xFz?u8܊c_ڄOy5?<(<xIv}s݈36-%hBDEu5Єyxمb:0&lR{äLϵooK^wǿSkOEo|xA >yd[vk>;c k39>.ˏ>ˏ.੉ I Јv +zCMjJO#.p$2yZG6+ xô Li F ӧS`|+qNOAYhj|fۉx 6% @XG8MAmk[2?!XܖNht'# ijxZ>Ed]'B v.+[xnb?3Ryt[N)7gO% ⼜+3ϺRT?FVyX 0򨫤9<<d\ F8́'nqd>xjl#4[7j..6N9isC *uNdtɆϨ́Od?yxN#<0gij<<'DлgN P '[BO5I9O5^0z`њyr=x͆ +|Њ#k($()=&2_-^fDBr<)uE1ِ5C%AVsб2Yr׳'_H< lĦ/s:wl7MmٌR;#{Rx xF*cȺŜ9#$f{)sz1ɳI uÛx ۭS7!;lk_Eu#QXLp #V`" y69 <#<?F9d]|E<3{^,>y\ 2E#ҩ-ʥg̞^X/pmx:KxDΓivkNO$'1M,ް"oStd\l7JW Æ'@K.m.<|l-}AY1xjOٳ=AutOr<{d;}mkلO%j ZOK"@"gş L ̭UsU%tvt-,3CL=I# ˆI[d1_Hl?#<.71ÁKt*--+8~Bu3 (U.V O dwMA>?"a{'N׌-߬-LgʹS6VT5 zI9އaŽOG@PW]tSi'G 3 nфYdSxKyωe^gS+3"sE4nvMxFr) ' Ix K_?glx|yBYJi&@M+MXhGOIdBk  ˨&Wh倃h{+B\?3e xDH?( Ǟy(/6j`Q2"xMkZ' {jy!{w6`yvQL58z0Gڦ=.-[2 %>^9|֮hG9+bxbd֙m>%hmOREq.b!“/@ClQ!EaX StܚX_Os?q^q h}'?Y지ͩNc'z5RDy<ftx&SxRg~8㬈d w7 ,!袼C5E%j>r.~,Sh;3 }e>*%ɵ6f&: epy CA"6Yijt xBȇ/T?xxS v|[?"N~dzbWsdH,aܦPo);1NaD<œw yHruR35~G{^kF-dkeLteM"aTispO܇gz\<)Ɠl<99v@C< &RoG'Q'DS`)~x*c< KKx0+M'I4jRHx:|%.JvO x:KQPi~0d=w*_0")VPȞ#k! ku^9cTQ=KZjwғx9<޲w)3_"tgxiO=N%f&ו OY+~f|݄ `cLPM5<5\JxZܠb@`sxm}g,#?݅$@~#w7D9A5<}<]s3e yO\H6I80o~鹪>8~Vsb6DoOdm{,Ɨ+q  .XXjLX_zmVDR݊ & ?U]Fxړܮi<UŊw)xjյ$uSZ3H0L_F6gz7(-ߌmJIl?ᩄzuoO"'~O`lZ<)SoN  @$}O3+9L`KOO_fAXf-Gol8ݷ]!gFzV0F`Ȟg2pOx:Axs%Lv/dkLMK&a1"3Cφ?2o)+xA`Ld,:S^Oy_#0d5뇻z) O/?L~8.# gaO~&3x:zȇ嶚vFHFO=pd `&PJ#<]Afggϟnsy|9{S"j+ ed`|g]w*7b_}'ν1|dfvEVI#Wb $X dR3s<1&) !O?LPz|-4< 2FK&$Ot̟SS_CN'H슏fT?c-o 7v!\y<,g*g[* k29P}sڪqS&IqԎϚ'jz(O7vE(y|mWI$4ONj_+M<$OĮASFS 1_ݥw~&ĥ^qЩMS[3!CdLJ0SR$ #҄O+YKJ_hã~IS^.DT)(y XScBj%i"$9]Ԃg'+ﯲҌSxҳ)vE:!'w <_SJ`T_iUS;( 3:YOwO+#_ zX"zǫʍxW{zl162-O|9 և.=@1U_|86oyV aXw:_lĻs<noUmOۉ|G (+]XcBIϕj|19D03 ϵ59b_h7g/_` 9'<" Qs;Т&短#gtK|sl/xOa9h1k ⹫'E,NyJ+/ Bmv)r#' yK[ÈgЇyu*xFwJxS)m>Y9O;_U1^8r)'_H_/e+l~|n$bIjlOIګX3O+WvĈg&d ˇKu+FdyO-O%Vsugz'>$\Ug{:W2ݍ(Dy5Osҫ`YY} v=<ΗNu|,f9maۂ͡jv_'baFaSٔ 3t\x67U@j<_~6<<+ztg^M*G -ۧE}3OWo6cPÉ۪8.vzw+c)znӅns>yL@;nuW+I)^ls冧NܝhI<x"R,p<֏+fy/x'j:)lP+(胤`O5Ok۴yyBB"'?VWɜSڕ!S (x38T'2OkyOEǫb˥GY(oUY5D\Wg}a{O9j |Q}@Yq!AXgsyhN Om6&i֞q'THևil׉pJ,qVaIqM=mhFB4܍[zF+/&x\qtPDS:ʳOE3'?_+Z bW &c)RdXbuPf~U:8_⦬u(-OYIs'@F?WPCc[=80 92}a O}ȓ__xT$D"h)OS+\Qv<%?Qn[RggOSiN$g'Gᩨ>3h#lߦ:0C]ρٌ$K0*JOs0a? ĥ9>6R7Ӕ%iG/|3f߮BΞg'?bp>LM.a>y"5Uw f~r(Zևyz3@ޯgѾU< vOWTZ̭ x`iyN9\{1"R֌ gڗZ'YtytF6q.?/jIҗs֯5a̧dwR6|~_6X>xP-቉6Yit7p?-)/J}UD pVU_UOӡC)Ti?|SK;TEPÂbQc9x TWLy%Z,s#O!uO O|ΥYd?a̳ 2S swrQB퇰I 23Sl2) {2ϰ'=Av8/B~xՇX9Vu%~JSFڣ'}u#~%Iy |ϙ%'&xZbKN[y2ρ>4[S|I|'<%/vM{<̚)vM4OPX扚2:)gݒYV;_g6>2Ox)B|6y6f$m^S$.@_57+^S0SO$k/*^n 9 ׇ\+-OIym4L~2\ʎ6 /)9d2nCdH jlk3+% i[ ow{:O<<{g>w";P'&x*OV:^OhQ[93g aN٨r]>93~X&# =01wjY$L y냿쌪?`a#OgvwaR Ox,TKT.F?}O OW’9~H#Ў#}8s8'xA[>,dd1 -Ƽ ` 7ag_8vMF\R.YwK Ġ婁'y%= ' `<)-OxIc" a-D3, <5Ϝ <_Hy'ap^<$-O"8Ϡ() |MLE4f5NlS)tw]N_xbSS\P&aJk^LqDv5)T]\4jz/cE \AuѬ<@RO*S>e<53 &yS ^Q6mE>4Qz})+<$6F?)O3<|p0OI<`PDe/^*O+lOt<>MA)=Ϲ!釚AsYy9Ƭ %= K$3<*3`+DB6<3 `c*SyS\sg^Iw1j\K}H<ؼ0e} O<5meF9DQL>LD)>8O/"N:Tïzӡa'Vxb'FgSwb+Fԗ 8xJ9oR)"I xb8G'+&V)s0X7,m9{b3*P,=myI|f2 W%Ul1F\vu#)+JK"I!U"qf2GiЗN"V~Ԃ0Q'Vx"/ig:e) LTp9H3R94,y:Lqy67<+`H)L?}l ϯxOSx"U+t<Nx 9L׮M;EDS|A6}kZ+FZ fX;AfA!iHp}s8 A." QMQ+S[B~A'sFfmPچFHA7 Ogx Ocʓ TТc<[i]qW&xJ's<=_+<˂D-{5OIs^<ʄg2e] ɳSx REn^Eyqza}#3ksusؑ4бx|]b6]m6gKPBnJҪv.WT[Bh 6%;O5@-x b+DxKƶaSsl|W<'-foO%4m&\,"dVh6s򗀕61\>_ \ևxqdQyH(?X?癧Kl P48_̦ycW~m')Hd\sv 3C~_7\W\6>V~2feD/q}8O M lk%}94)8jWL5b~'<< FB}Ӹ%rS۪oFZ[amnDZFF̢}%O?T /75Oy26TQ],1TUI'Tum Oj5O,T3m-؈` ٭ҶEpw.sE(K@Z3?)O t_E}T(Oӭ%43حT O C"5O$qTOYD0y;/')Zp5J3HA"+!u[~f賩Նgpz/AyS9`-xBSk}lx~+s w{zDPkz̈M]O:w7g3j9,HHԎg=B;z]zjA˱4{\@Շy9Iڛ㔩y0Hm3r' Ԣ~$CxVOXKޖ,,dFAv>enhCqQ(ʓ)$6%(en-.uSky Z<ìe^]-<y"ϰp! ተEBɔgŪs]W)n.S'xbgH+يSO'&xV@rL?+"E%3<M!L<nye Uml橕 =*NߎS6DǓ>txbgHKxb` <2Oy}"Oo< 1We`%O9*Oa'H2p/fآ.Pb~܏u(/UE\G)H(;MJ?Fl\dž!=O[_jm ~Ex)ADQY቞'RMLgᑌz6>$Ϧ'%/YyKx"TeB6~3䥝ܟvNBng8_:ͳ$XhDBCOW/rx& I.K#)uTӺ@T/<@1S=O=gX]dzT' {GH<OOmx IG&{0ꒈ<xjޜȞGN|TiA梋\IyL4+IC1hR@X(d “x{ѕhͮ@s wyJ29և<>4$o}=U<;}8Dm,S湬O:;O*#l3Wsg# <+O^d_IQ7 QO|Լyڠ5O2<@8zo>ׇ鑄=O[ Ox&{wSUF(ա4K0zؓ)UzVAyjɒ$VD)5=O:1-=Y@*_)L?" 99$}*繤'Kxb'j;1Dj}XXrڪqRz(j9,8'&x&CAu yŀ/ QZQa^lZٵy<5m mxv[{`|O;^> y,u3Hag<]:&xb#OxtOM[Y?I?!5U|1{[y.SΓ}Th1㏕OCyYv3Ң8DS,d>š<1OljyOLg}<}II&T?xvg0ĺFgwyI )(WOK 6y:OijxBIOsl&:?VtBTk?),x^ywĤ.>#.?ՅEVN/k%|".y62OqTgqdc/wI?lymKwI1G w5<:N 4}# 2@s9ZKs[N~^r[QG59O^glНIs^fxm?,4\D?Wm0._觠Yqdzԇ9xfn=# sa =9}>ُrfo1`eoóhCGnw//q#"=:YGo= g'?"~|ٻL{jZo0CzG烇\W:˞o/=q%\}z ?w~E"/?M|Y[#b*LF3gaFܩyuT}"hɞkxm<{0W*?TUWv"a쿤ipu 6䗖./0gx,ST\0HW,O ,' <]_]i^OCf3ϝ N\w2_k-S>Wޑw_}ˤόB}l2S8!y-gx~h 7^?pg\{}tW\,^y<<ݓ<2=& o.ݯo(Μ /q1<{?MƧ/%<"Y^n[އKQl+j\% iS :ZW[^wގW^?g܃k.კ*2||S_|_.\aCe`ϪxaRl\D³?}N'xVrp<."ef\7" X]a?`<AzJdAe}Xݤ~fMs{&.~-/}۟#yfks3YS)ވ)= =뾄c [ Kǧc=g6XZbN5qTp4L?=_٣f!q _쾬$(|<6k8_5Em8H$*dcv0SO6^̸K/|u z<>ls<(}e#lqqHscb|^wnWw*HGn8pX]R{2߶7v2y?ulL _Uf+_fhr*^m/*8VuI}^YeqDp`=OF*ybT& +?}~ij7᯼c%pSx CV]R\JI a {O_y{4n˧ߍ(_Zŷ<|]=/6HgyA]OcsIWi` Tq7_}pC} Gug^gx੔'Yv6uO/QиER&)h~Ԛ.yz]R4$<˲s_@\cp4Ge Sj^IJ*5.+凛/SYI:[IIu OHtz\X19x")@x ~|!uy"(K<ΗZ">>yv3`0"O='^)&"~6p.G[_ Z [;sUӒ>;80b5'vO5C K-OUx&Sfx9ևEFsc")h"'{)O|9V*\濓x^V\MYծ0˄Yh{}h`{/³:2=?7k=Wp4e @w'Ȫe i69̵K> \!UC_߾T6<_a舓=#nХ<]O:"O$Asj4}2O5Hf'Vy?)OQ.~,L<0 3rQHi .Dmu FO9oQo~pw*y Ψ'_+7럛x* bFY] Oݻ|۾U/K>WPT7KE H󩒧$y)Ol;_Z-}hRavF!_K#f@]W* 6O )`a9y)3 flgߍ>ȦujB~xW SQc'ب럯CJ~L@ZRa"ԭXxT[ 7g'/JСVSj!] xAOhEW<řtia(lIϦҕs5.')^&e}rV &8n$O&?ﺩiY?v_ݟUi+N} ;5ytkh61p ,u n8"lϭ|O5|%YV/)@A|-~mx]|ʵW_އ=U|tg  ņ] ?|cq9+zRj@t/OBÉOW7"x2˳ݡW򫏺iJvEJ1SY BDs?X<~"U^< 12!4"2ӞcOVOT$ik18=6)Pexnsj̗| 7\338kڡ :w;Z|Q61ԍoS ؐ}R/yȰ#*Gmx\o?f|ӟk+kM/ZCAO+3nnՃ9K=H߂ ~q|">cKf?﹗AɁ?'\?Qrw].+Bo Ra?;Ծd`]c-^s9<l7#Oj߮;N͊<5 xbgOү7T[ĭTS sDgieBRK%O/qv2SUgx Maa.j1O^S .)# O<'JZL!ʹy=OF"#M3Sܘ;я16p 1'dQU7_8\_қѨ&8SW`U 2,$TҒw,"_Yz={}u^̤wMS|8KGk⼓;܋mq;H S}H^y`4m3\Đ'S5:橉'SKE}XV(ʿe!Ĵ~܌ͅ^AIO>L+fXs?m&OxFRkeϒ}dѢjb?ۿZ|RTT<%+ OlJ?'yrqmY? E mz vX.}GmPH5|͸=aRvnarSaMP /y_>K$4e_ ~]yB6ݟw%h;'? !*!m% -T\@A,5QBLXVퟷ݋y'IܡnSS9^??<#j .Y|KO{J󈥧fhҝYq(K.<l ੼?;72goӘs=zoޑ%0I%m*z_)wݳ[;(QvFlfW]Jg(cq6 ][ 71A{;‰ x//`Էaowÿt]88 {ÃxpݹȐԉhBtՏns==P(QYv;R05_ }"yU,eC19}| '\ OxAho?OCC.X D_kQ_"+o7pwM <4k\qi?tky}@Dٷ|y^ NW̏~ܰBBϘW?G:tm̞I)9sΗ!e][vCwXV2 g)%MOI٩ ('0Ї)gy*q;>ϛ/2S7vOw4v(16MG_XK5|:"~Z#Ͼ#x{F^0ƤsK&vܮpy%.("Ob<{rt'y:}@)vY0Qfya;̏rI1CsG;?_+ cGoj40u:p6FBjIx)+x?h`dUX?`CCz~J?TșѹRHyV%|ۣ4 Q:\sd+>w]¯8>;_g6-GpEpbcۯ~wb)g4W%-ך0X<>C]hpxK68eᾒ4Vyq[9VPZSB',ayʁ!oș{QkṷqMx6)xO$,prxpSQ]ػ>'7E ޏ=\~>z 0և/x)ަ K=$}3M*({yuuOo. `IK,4x~'=Vcď \{Jgv yoߊkB)<\]BQm>P0UGyH?势fka\Yrugps%aga iiY fح+7+dU4<4{? l\y8.o/zHK7{>/ij^MJ?(.fWb$B?2]|AN}&d!Ͻ6x5,p C6)+${Ǔ\Nwp?IOap KwCcxߌϯYG'BIP?h*By6W_&(&|1G?q|dvcoJX\Q~oX~w]<_2Mk&P<#sz' | O?|1|)̇_{Ixbgc^y@Qk)Z?N@w&U ~I?%2aN ` ODڬxZ}<w婽/?ax!}q#KZQـs/!ĺvYcs aXʐkH3`yn'fxj[y* [Qèp!R~S y*ŖY_ !Ϡ(a~qD4feHqyN9K Kˬ{ cMSR?Ŧ|ġU<]SܹDd>|ᖇ/̯-D\ _#ysGLTG9öp|a~yw{sw(o7ҹSߏEO#O ;C໿zZr>rG/.w#$CśQ\E"PRfꀒkiصx9s_sCUDj|2m/ݾ E7Y@Ab|[b|,2u~7eڤ3k՘k9Q&F+óUFF#քS<ԇ6'X @ 'VvٴsO;_ͯ!p_),"Qڻ5,'? g Ο,7ɂ}le ×/ :_z~x"IҌh^I ?{ s+ ~ e|amJ4XW=\3_LFa/Sx x2~~iM~wnݧ.3quW$NDM\DLHrp T~ĶU))mKMѠmrX ج2y) W:JQ<Ɠ+*nѫq?skⶋ 3Áe1?c#Oʇdg<5tbaj=v9'Yzdg~D=ٷ3t OA;r1x:MCWxj3*j_ˬ j4(?~Hq$.WzG@YrvIg ?K :iHRP'W])sZMqI(V'mt}=,cJԙxBx$I =OH]b~ECgL7lխJ--dyxVߑ")>ZupĂT/Io" QFiϡ@ţs5,=N]]5+G?W(G/~ ߊ§w]~?ycy1"O_4Z_=(/E-6_pq02Pקnŏ~]xd+j}؎ O-d$6WLv TxB혿M12E8q~GmbRlRk?DSaͮ,6+.j2HbOz" O̓tPj~4d/hUxbr O/vܕDb86)=<;w[{ #.٨(s8yUNs+VjH^i}r^pypL>\1oR*Xn L ړD+4Nx+Ҍw`ݜ0J)|8-G5sBNM~*yǷ_]#r|9wOax8@Kqz`CV ^iҀB×*xFk4\:|9xSƨL;N_'ټ*F+;#ʝI9\9g\h8Ox NR0sC|q$,T"ZHmQH`["z=aْCQ")bT&HquwWO_gM+x0?|#]oǵ}q0!<% d&I4~[rf_VJJu# mݛBcS ~|Ѷy+"^A@`d,,-sUzjW2t^) ~ԞoI 9)(_q,:3gz=Exb)2g6|d6[eRyg'{<%nIEi. G PRM[Uv>>Sjtmp !S"8Q.l M<$hv!ų*4SCsgS |9 na0./i19\H_ܿ|+xPse|$}~HSL=pJ^䯾jQ xb 4TBfER] ct:U D?2Х>fl6]\ "7:Tv6J@Q3rcN%XKdlGXanUS|4!zHx% >2q:(Ot 03^ВZ~~g\M{z34e<3OxH2ojZ$ć44=*hwOup 3"~OWR[B9!VOqS$,ҐR;_\}:̾S}߯'I <V_OxU!+e#}<'  l!_^*Qr:G"S {iuxyΩ[d,`zhib37NW:c"\"WH|Pbbv:.^/bdPylKmwqUoJq%8}w_\? ?nJHlJ"]~W>/sEE{xk[*qWP_I?|Wll/B9bz6JL69xR‹Gv&f≀Ó5) Oe>0S9^'zx4)cxjx+}8^'#?ItMyƗuw+K& 87~-'0J]U2(E9aڪ Y.& McRմ)XECr^ x #OW }lqcѐ'w \6Zh/`o>=V05g(Ha>'Qi_ <ƳZ33l]W34}^|OLxqo&dq iš=fTOx"D%8*<3^0NKgoĪVlCO4݊AXXAf@`hr|"_c aM9>5=čWHKo}v:eBq$b'3Yb~΃7pD3BtMOqUKu ^q,Ŧ"CkC174eHk/d 7Hl2A#8%6O1{ {RЇm|߹'>Td&6;hG2>a?fhߏn%x(O ߸2vS4lOPPV j邞\%Q,=ሧ֏~ZsAK:?dlzT >x"r4خȠ;Xaɗxjρ E ⅓^V2" ؂;Ih+;aAK%UCIUQc$N5 75G|X|i]44iG^O4Dl$_2NOnjUkSXx*w4礿`PYӹO iI +Ͱ$fkkc6A& }Z kL?ήSq'A85NJ(OGXWAYJOSi֙ g^ AhpBAD<˳8@OR<tth;z <K;>tUw⅗ &xxIVfy=bWaH"~Әg'՞gJq\|f}O'^:ϚwÝv,>qe{A_>r]{yrQ-C0Gt8wOBAs#OG<%1<5mKBO)\";ŋ#Pq%?xB}8@_q<5)i3w6(6e>4<a\>4g`ϰ~'xbU#'CR,k'uXoqfm|5\+WV/|@IP@[&k*/,Șs爥-l&${xr˿qpQCx!7~}3l~EN᧦ffZ4vۤ= ;P Vhsz:8, =~J*MHU7cg<ܳ_W?l8GW¾[~ Jg|rd??‡7<7e|#?߸aՓo=3'lErv ZA >$ |:,ġB#4Gc-V4P<r;(fs4<+,S _![xӆݠ޴GO/i8yo{ѳp2)ϷʜXo=*?^@pE;9 >Oo移h$jY5X2o݉/?%8z"2%[gŷg3Ƶy>4Oy !P<قIyB\5׭)-𔄧g%YI\d3k(_h9kss*L<7ё)kB#=!23$J#F% QMƆQcK|3lKؔ'<0VP%!ݥ0 Pȟ8>HH.=BB̶gCtlJU!3% ?e!̌'+[<ui!zi/33ID%I%IH5#@zu *'==)їLoaRf$3h|x9&vshhY|h:\mVr Y_#+24J9jPHTG,SgPQ:ȁ5OǸ$F^N.?_bg)% r!~9 Hp˱zx5.9w]:a+<`u~ݡ^ڟ .7\|'-@S8?Bg)mrx.O`pOR<"9jbQCQ}IiGK>4cG֖ 2o/۬\C+ akS CILaƓ?-8|tQB>?^ϺR3u3]-W47s\D Os2ȿk'?%bk~{^yB O||z*_|`g@cS0iľȇ&1GN^b@_S?Ldm7 3|yL2]Hђ63|ǦUxJv2L5F׳O, } ]RAgҊd)>L*E"."3)ͤJ}MBãS\S|{  A֟JՇld~5Iȯ"Ebu.S$< 9Rg9d3C-wC8փ>?r Sk<̢ mdl 4b^,?dzȝϓ!ãxgq8s֮]O}?FiWzs k#xOm"ܐ]@RS%oY"8WeG5܌mhl"@OL+8 "ϭq$'[9'6!n :U'[O _?n6S|]E|a~c8?aZIgy!Hے9Gґ`|Hxf`^8d-)%!鼛9xR0xV+ϼxROAm$4t<`kt$z7-?>xa(yE1.k}`ᄔ/VڄQy%>V4p>(kTJ1$C\Š: 'CIϛe+txX?7lgz~˟ϟ |{ɁegIM~f<]RiP U>ՙ7GrX^}nHg֥ G}EwXx" Q\--3i] S0u1EZa OxexjS |xB` 'X 2y ,;?3Px&~jg ϸPɊh(X (XF9i*Y 1LUCcaפҡ,jdX+R3a3rF.է+S7OWēV4hqh)<ը~ ͔./X5~Z0lkZ|Γ(Zݶ7|*BPLRP֜sWg3lq\cj>;a:$X:`31_b@+g #ܔ^zY Xʬe2JO$GAyiSH}=1'6}&cTu?ܱ'OG`9~ Oo XOw߳uYU+ό{XR}s6t-aS!~DQ[G+NΦ$=?ZQW( IJZ Pp1ϐVZ_Up@t}[i34^) xxBت~+fL3)WO_G/gP$Gm byc+b\E%I=ajϜҺ¾:s5a)RI/OS M:.#YbKқ#I6f|R>M.@ٟeQVU^/@^Jr|5dfU|z❯g1J@?W\ITx҆#IV\9C:?r>"A*/NΏh*=]H\jQ`όs!d.jL _X~I|B'@[~޺eES x&53Y!|6Z%5y眾Lu̔ 8 gȇYx|_c`ʁPj)xT3iCMXJK.j3GܜУg3!_3_gO;| |uO~/#P7n\q+ a"qK{lW/Ly4]hh[Jfњ p@DFa<'3$4'<j#ClDSiLhiy3 _wW3K7do=6`xW'_rmgFv=|`){ױ2 elBahMH6$Q =xr )V(y@׃0ΰUb#m wE)<9v&˧a=_|SrER^?|0zTB 7 *DWi[ 3T-*lg{>Diϸ~.K 1*xm&<(B+:qx\|hEszBt E>4V+_rdQI|c5Qt?=nx TP>$<y;OxBwypH@j=eׂZگh/!7:GWdA KݿƝPrI9]\>3$zvgl)Ƈ<=3HaqAӑVC8)MqY1d<+&3 +Gqjxم OWzfxNoxt|]?i SS+<>gpQ'ЃO.;P@L JD% Eކs+)n(UƘD?NRFde>HxB[!ax*p`xxsVךbt5'ftO,Q|c?, }NRf'!L+9 :K233.2Ts'931e%87__X6aD#Pda]Go8p2U4wT}y.YZ#þS'ZxvrS-]4nȲ68x7ٷ~|։Uɲ`:8%S:gFF V769^y|LM*9Bܾ?_ODxbϠ':x*b9wܛtxVR|* )~Yl6vxj$4O2 ?^qc $Yܵf.I +|wAYz% }*^\,I?öE!!Ǵ_OĴS<&sOjIIO{ϼ *ؙVQnO-Wl`2ڍ Rtx<5WzUΞ}ڍ_ޟ`ע:y['.\C“dV>ܘ->_Ҥ2ǁ:+/1!Og%xnsT4}wgOr|=)g~礤?SGy +x\Un W`1.L&?8SRB)9x6c<7Qѵ[D ׅP\>ێAT-ğ4fC N6_t~C`3![",&,ll*3aCbei S Y'9%r'j<%1A|oćrg<5$~avK|`u7݌ 释‚M~<<8ρxr❻D4^v ^O6;G;l;4=r_t:g|E{/!,IT+xP}|Ln|&ϫ)s{k^ [T[hKgN}?*eUO.VSz$ן6hY?̩p5d˦G~:0pGL0l!-Lo2 Z$|+X9HrP/)Զ6iKPQx 5yeoxxW>Nmۜ? %~7NsUi(@Y>;fO`>4ܗ !bm!~ҁL3=01A|BT  S(b 2BaԄ/x>olFE¹&9_4OI'h..sT`[Mb0\Z/~Xe;=qPFxjOUjZpOD~'X4y0<,c n?~mNlDW:`=-kCl2mˤ_TP8u_\LF툟W (U|Hx;R4)cXGp1`x'K3~npIW.!<۴ZmgWJTh/^"3 ȴn9TUӷ_/`)Ν):?aN!Q o L;|R'f`CШJ/9eRr~֐C9E9HzOE9W\+6eXb?־c7DV*έyje↎; Yx"sP>P<l Ϲi!έiAQ_d`&fA ti_VNph3as8T|tp;^/"P| "Dn;~A)B%c%y H^7S %*gKdzd G5tfbO)ֿכ}b s " xPgMew .B.:N՞ y~EqtϛZΓJgV㲑_I&>3ϰߥ@0H/C­-eH6` O5x\ՓaC.T=ڍ\zGʔܼ+l)"fk.W џ%,.%deӎ|ȋo?PTc|29·Ah=1kҭ>8d>t ґKp!2aHxw[z *kf?&;h2Wuxx_@SVPy%8vIkfBSo*$Sqv+cOAF+/)Ry`o4*sUj~z.i,a)5?58@D? [PXD7!MO-Ov=rj< /S:'8VlSJwGa{OnځGĭGmލxq& *~IvFR<]'!:oOʈg/#,<ֈIk6G uw)d:?7cxr:Azϖ}O޽[vER,6hVi|UvZm: NOllϥ;+(A(b-ƌ,"K< x>VgqOxJTxNcUY=h/2O{>h⃲^mVDvU.UX Ug?=$w3_tr._ٿ|r\[?~~Q[ BV#фF"Bz\},FMC41l++N։*S>>[FyN^ex3qۣ@ |(?9u1i_M_+4=?+6DijVO_{y iJ;n6]~bZ;-6;_ E|4U_u|ʇ]C-c-~fR?ߡ%pE8~Ĝ-=<~R?aH kfԿi+A_+>'`T)1tsrR{jOsVdV秒 ί[@a<ɚ 4’AVD^XDUG_SWf7S]>$Ίᇼ눹tiΰ46)) $V[Y2~N5?%)M<,)S3D9}“Hї<'X4!?nLY\qO;,W_M[~wd-dۼ`ILKZ_%^U(/4 %̊5 Sx=2{7aIZ:v'[ 2ٓ4 w x4WբxƠ Ux#af}qAj+%>sxʏgzML톘k W]mxʗp0<?o_gQ_0熈fK!eNU]?$+JJUjq&c^8I1x7NYu\Kĵ- CxJ4x+W#OO)t󊳻3,4'q<BBc'xjXZ4gKd;#Mӿ`7#ﱮ &xH.w)&:Qg9@q/ x~x즉-g^E^_K=~nz k!$o>rMW)mS?l)^u^5x:z^!gX@xo]t;FJcOxL]n4s+> k+{<'IޘR4؋쯆9 @/.A(~ⰅYm~ZώxSO{vn"&IߡOM'<`x OS >ps( (#Wy`ϬP&\D<7QOjT EDΟt" _t19v]>&1 uJZA?#z' 8V4U69ȕ]|'TĤ}wWnkW^|Mيgܺ|%xjy_b?PV0? ѓ1 ,6+-<OovQ<`[ 48Aߎi͊DfS]zsP3.2#2 > x(~n9Ȝ`ҵOgiIۀNYHfjϠ,Sg%9@0gKb L.K>6{ͧb8&-^>DHG_gR0<Beps}[}[n[@,O 9!0w.4=:?_;SSIe2O iOag䃔vwH;<%h *Kg<hX9<iZ)_ԐǴ[$JnXxI_ ɭRfքw7‡cN>hТXS[XBچv] V@ށ'N k s/χ/ dMN'6)cֶWHV$oQY~DOtdXma<5WxJ{8JxI-xq< xZp $x:้)kW F}>?8laj`VIeQ!_Q ;%v8Ke /Є5m<%uT$d°_ ω]H% Sf)5B;Ht󘥑yNQ <$[ORUbzx,gv+Et  OڠNV,gTFC ' y_Rp_yu*Hb or叮\ i#EDA/./( i \0tQtmD5%ʕ6Q9[G7u uWxJVDxdiy^u Ϥ8~|%mo{O"=GRWR/)p KCyJüB`(^}{iM5WkԞWOɊHSR/c4YHAx|<O'O#e-<5wk)?\.җexJOIxڙQl~{I,:2R=q *̪;&3xV]0<-mL١Q$gS +v4T_ =8̟>3'ø7v| &3؟]DR lSXmOJOYOóͪo!IN'`=4uơjQSCĚeߗӫ]} X*<DgÄ$xj )&%3d=%P55TO}gxQCH$l#Bb(>H iO-&Jp6e]SG Qe<1X˥!#3Ss;D ˇxrώ=sm`_K?k<a1z4nes53r:&A/Usǎy%)xc}+p.w>E'Cc Yx6 Vy+'& Vmn?ڣs*zYW;j*+'3p!561x\F^7CVO7iˊ0$>`AEkQ[A}[C&O[p^u[y?[<~v;wg[SgvI# ra+8}b ɼJx6[$G9[w_ fžz4V&R,S}ƕ W5Gs2AQ"Bo:x}<,hjS=:, 2}8BusIZ[O;W악ՅxקɪWJum?TMpD"aGbӘN4SsQyq)k}t:&^f.Dr-xӳ3Ǝ3k@GWn8q K$D%ދ7Xm0쌧05}.[MhbvWXrl h3ğOuFXECO_t3ߋ8ܣ\./^8dsx~BܔJzeώXBJwK_}-g߈V#oW54gA_*f~n[NᵗUtS/n*ip*rt_WŢ2X#J-U5KyxF>3$AdFZqz-O'M-<Ɠk|JO)m~<␷*po>ªZ]*nJpZ rOޛGݞV{kAD%hWkD4v'RjLQ[MLv2ݎCǁV#*ʠT2YLTAQtowq랳ނwU=9|~y~ϞW$\V>? ZJ^׼\R 18\v_TW3(xY=7 AyA9[OwCZj/C'j<7>\&e U\n )ZO9?~g=}y8!%G"zΣWl~nҁϐϼP2GM\7&YΥһy^fYP<^\{YxIp>c"駵yr}Ф9/*V?Oio$3oyj?-Ϙ`-&qu1Oq)ʐB1[zcx*Y|#)P8*֌qJՎ x>=Š*`!˓xj͓(4),&,kq@~M:H-$mEVe4gDzWUgaybm"CaO|t_lc?>޵giy6!lXgoiG DIa9L;xHMwQql&M\"Uj ՟O+׷J!7ڕg8Ʊkaϐ T>QU{wL/L;sˑ3(yگ`z3aR?CԚRBsiܦ))ziO+[hy才NY_a5,Pb9H DY:6%}p8ϡp04A}i?X ǪDUo>1 hWŘr 8H?uFWPjrͳ:3<5yFOMp#3` ӳч )kyƛhs.xbV)mn/ 1 3$A3OFח2] ~ȓ6@OR1Q~G m3'S+3No&׊ 26(|i< ~O^ҝ )厶g,'!MD鋪$*_ J23H|)-~q;OOLkWf596p${uų/䩅~Ŧy@5R٭|:A-8w0Jj2 jJpޯlSv7I~{օ6;jUj:3Xs O> u>(Jo,23S*ۜe< 3Is>OLckŌ58KibcKj(66NbԠV: JƄmB6I66&0I_N4)d3!O1O8c¬'mR>fX2S<ʹ^ % SLԆ'hPu'3w&֖9ꈨ-(=\[ =!1d\I~V?Cr}ezΡ@xҜ `zoɣ։GkN >iMgmx䎧pl„3%g~H>߯e@j_ung)^?ŏ@䯱̃乄aЅއ'T e\5=r2?NO[/ M?Bx k(pS)18(4s/Yobƻx90a$OS&U^Wyn6G'|%uKJ|CI=0+ K'5<^|Ӧ|}6 2H$ e2^q u//p3 !cՇos#ث?O<gPg3<&(-/PoY3W(hO^_'1m՘ pMEܬJhҞ!/̻cմ扚g s^HK=2}5EK<*?)DOēL.(y!?y /♧(1Qu⨊ %T8|3gqovICˀS-x._ O=$3Vf<$tXe\ݬ8cs"_3O!Mnҏq}1eVP䗴ZKّg'䇓|Oյ@yJɓ[}H=G< J_'aeyJ$h}I)LB灙ށ4Ŵ={lCm"l X$>!!kCΧj]GHXH5*!bUol10iO)iuoR (fC1j :g<Ӈ.h `#,?E!v@2 +I"'xnի ȐKU_#Fy=(C&\ s{ w*ǐVXSdNՇ5y9SEjWl[}mWҹ2(GP_djC VB/aX_?ګ/Ň~T#Ig8}tOS3a}Uw~F<}KOg@1>„}inOQ+RʒӋ2ޡ< z M1J=̗ܦ6,O0-gY;}ۂSmq3Yh?\<;zV -7\>Q֍z[Iij_|E膲%oUVi?UͶ{t<>$M(y:K1Q!^ U_o?sE5J?qL?i1xBGy[FNlFyI^zf^g?D\ɣ7pkgp݆,F~~KO)f*+OO8m;x'SZKQjx}`e-ODgtH'<UB!‹߷s:{ˀg@חbw܏\=%L7w?(P/%Y_6cLu LܯňFOAa/չ iS]39`l5p.^dؤ<˩z35uD`^]x⿎Gݷdg⟿]_x^~[sY<ڦ6 gBZGHͰVJ4K7 k% <O}*PR̓^WG, }Te$(MǠMxS'xJ? 5Ϡa(iN7{=!"e ҄BhPQE>Y;K.ǩ7xptӏKc'<1Ñ:SboK0%ݏ2O0 ҆]?T)DU΅>!VAGb |?R|LO< J<hG/}6$r$2oJ.p MZIq\U[[{`GVax,G(wآBqЬ\3;2gl Ԧ~߬>PZbI#b:[:?96 Mfʶ9ϞӇ"yS }C r:is`G؂ W1$II]~%۔ ߯ZƔaoچឧL ܯ ꍄL=9NK#ć8_u {X_}Ԛc|e礆߱S;?ߝԗÞfI#g>{QWvĖG&=Z?nynxp?p sn}6l Soď>,ɧ{xꈧX nnv綨>)K8M O/ yCg/x"{+Y6ර, yV|6֬?3|D݃OvN;O g V98׾r.z:vMAr}ٷ愣ZC0>j avFF3؛jyGBvE-6;%-xjf1I^@:َ6~S"n-))MUFMRbYkOM!O--0)o&c}Иzj PPfahīx8[Y*AZ?Q8:V?A?I#'(ɳ'oaM}P;3']2 # <&>`}i橭wv3k)[(zZ4,4|d (+OƳoħ! ߏ`o%OgԇB?~gxqe=8y?^S7J%^(WUk87'OⶻʟN-~ʅ?x]q2 8ߌ'B4"֗#xMgqp/po٘&Ԋ{e3W\Gt^?>Tx~Yϭl33689ixFdO{xr}`≮)'?*n9"q؄ `u<8l4ҩcn^'Wq=צ4+a#H)<%OMczA{l8 *.lǝƖvU$LY#=O{=#Hm,`d5"\rztEf2}MjO1'j3(ΐx^͙ψH|xڊ,v?sN|8 {V ,}PUMηMy[߄_{έr1L:WރT|px{sL*xM\O O OLPMG.OJX~-WzBO,21;e"GO]Q9ikҺsKSC/Xpcrф\x@Jak==e‡oy<^Vnx*IgWmӸ_-sGOމw➧ H=MP%x݇'vx=x.ᾛ#x)qm]w)9?O 7^O=х>#E.[\bGWo=wލwލ;O/*<y܅#'s wrۆCqcM2T mk >[hynW=,`AT˰dGu0OP'y_ڍTQx451)v4O}*Xt1ݦC/ByW(m oaLfHK$f<0c  2 >Qy!Qf,5Mm`fN 5{++MEB{u_,s<ȿD 5 d Dp>ɒh%8λ/~ie] KoZVM6eı lFf2i5ɖRLγ)C[\AyQ_xMt pXoǨϞŷ>>;XK7Oęc8rfQ 'tg:Oyے3l2aƔ~Õwp1`L9s?U0-κ χ:cNxÒ<uj_b(ӻkqNRxr'x($`;N ]~:٠ ;t?F$Ő5g_Ks ,=OV HY,Owa . u'OAAn2es3= G[պY<x&!Ϡ̢ "qv}LIRdLycL?89E͠'k\~gOt=S㹗yS]/cl&J4U%K%f-8wjKsn"g^n&1bҦ]MC/>1A}:O6$m/>P{.V3cB x@@ c;^=9w?|lˎ 3ᱍ!<,73aA|])Ќ%^qݸv\w; ǎCnF+0&Tb&M33|=LHSb 8`>-~*3O-xx!2j>],<ߴy,ɆVo0iU Lۑȶosn7JJ N;N}Vºmޣ.7LF9I>LZurnRy^'ߞ6wቖ'gZxtnjryy4=o>TM /2ZgS165<}sg0b3Oڞ0'(6^_r~fJ7ʬ;{1g o:xdgup^iGX7a#w2,23יoķc lJPWvWFk= m`,gWBF=`U_?Z9#F,Sbk0[(J)b~f(~. +*OSdtsJM3Mc> T ;}0Ն 6 Į<K gxjC<e<' >Ha'&hngލ'x}80ƕ`#C̢6岓> I CMrfn HjĠyh6bxLUD ˙"O3l)W$6mkXeXS $:GiUKcS~,\Iiq&[w{ow MO fĄUS9}7yoe4>8_ 3I]Q=O<7D7AmBDCw!`>7A{O݄:~o1 %UVo' <mYC-OV;Nk\n(RRޔ:M&TkcQ,eGw&wG~)'Dsͱݛa=V-Д)l'e!O3\Bxo!ԗ">V~kXp^d kw@SP͸]sx -yOf!p'N+\:Ub3+[[Qq5M|,xyx:㉂g)Ex. m[Wu[HP$U"Ϛ3&Ų0Cr^"G?"sd3?  OԂH}y)=cuV-B][_(ηEN#HXQ˲)!Bs8,?)qi΋`jB*$x(4$ޥnyG>  B*u oAi/ؚh0AY!QH{65.0_iG0 6 B; = d^}߉\q~Q?r-4/9oL|0sI{=TkIdt:(ɚYz[xȳ؏TW _ï/ Jhv q`3gP:SBjA'01O~T uھ6!b{#9l%[v?W&}%g$SďmX["uGSсVYqC!C4.&\2>i= .A8OB ٥b"|m¦@xd})y Y?PMqC`18zQ^bFC̰< MR?7oHXX?>XbB^*ևs[;sAi F&3¢yꪌ;f~8&N]=C^ iژIt#)OM4(s{̗5tdX-ke|GsexEV( ^gosn=lsFdjb"y1lɭ6h`l6u6FgB>?H1ԯO{>/RpxjHq¥i*P S{ y灏?g~%Z!}^NH;XS*ڣtymF%}6 uvB.tx<*򠟡l8d}Y;~ g7aEY/wv$YY?c#VcI@T:t ??_HkL:uo*vG]WflD֗P0sGc&e4 + 09%ma._Ӏ?$>=s {-F'NJ[q3"Oa1fVh, >]#௾~v1Lf4,MIg]!OA9mAmrީ)fpz(:UuPV`*zzg&< Z?Cփk؅ _]9y6]!nx +{^0Ss@mP;Fol;5fVRTׅ]'lcWJɯ%†ђ.慹 lNuOE;fxx_`.W7 `@zCT-̛X3t}1iȑϿ .oy~_gy젴_)X@1}y3IA]3gO)y)c^;ϓ{0&XOk8OngS}%l_xiTn'I`QQۯx:C~JeF}Qr"l: J&MS35oPB>^}Pn iZ/x 62OPp<5aO.'癳gD-gV6&y"' g78"7>- wCShy6q4)o @z4T#Jvz+u Z?yzEGO"?ĥ_x3a-W2̛kQCUR3*eIt;${,Ŝ^W&Pal+] 7zxku/!7T~$75nxJ)y>_t@_ALJĠb c@~ob^?= +Ь/0C5X*ŒNh+xդy{.}JBXV+,j[SjJ/gtmʚgo* QP{5^p-ڻ߽jW+vW U쟙ylVzR@+n99$|:|~nvw<űxE9c~c}7e5vfr@⌗a/i+{7[_–b-MMSc%^rϡbi},[x3˯6|Wx%_D<y b:GM %h9*̉RҘ=ڨ* jڎsAa&!1]7Lߠy:6hv.cz^p w1v.+~)O%8SLboR62-.ܹgɃ?c%O7Њ|A0ʴhsv4y~k(d Y_`>12!ܭ/g/wrJ1`x$'b4RZ|^$_-_smOc\'GG5'_Wʵm&h y *H9`mdSjߋ']L|q\Do~?[Ǐފg0'+S$ byF\xMh1~ Teߏ}x~oʠW4W㖏}? ~{)x%U ߮AS8XGaOy*frj3ɾټ婣?B?2ٛ=`nK+nZ;㹍zҹKj``A5/> ?{~sN$/L;ZVF<[+ٯFhBܧ̹4@ARߊHlVE0J={w]7 ^x^2 +iytS \N:OȘ3ٚ %R|3/ţ>Qt_W]Z#T'Ұ?zl"q<5CR VA} Շ7W~{OTU潗axnS xqVrr?&Z4<'J]*~(Bq}j~O(?󪏱 H1vo$gZWd}oHx叚 vf"%) 7"q Zx׺vvn&T~̼0b7 xVr0)OL #ZZ<5S o d0UͱgM E CF?>t7kgv=`;T ϡQW:D;pSp#W„+}{v<8lWv;ɳ9vk9?|hNyU>UrxܹBڻOߜlCDfR?H<~`Pb Br_zxJeU[$-[8YW]IU8 ؆e1NMf4{zgp >pivރ߉N:^Iz"=OZɳӺ f/'.Ѵ#o WyϹONFdg5OIޮҮ)ky*kaZ|Ak:&y0Yʳⶆq-+x "}ݧW?0L7!.Xst Z;)u:0H<^P"[a'|{I,P+p%'ُ§]qXȹruo?W~/|'{3['9 cO{ gpYe4Gȕuo=7|^h^O~f{sVv&b5~/aT9Ӊ4쌥9XX* <.,Ĉӆ5ɃC|<~^ͮkyΝS gOxGX. \wS꬝1_y=YxjDd<ևOч~: !SoSoup\.Lp.\8-8xPAʼn }?n o ~Y_L?YFI{@pp5xeRpre)A YP}gx]x8~c}U<7˗kAUmE7OsF쉧V%a;$P,yYLN&tO84[Igz-I[Zg<ʳLT_z<-Lӗg!OnЇU<>'C3.TgOKxk?ڏcTg[xʈ<^+ ;D YS :9F7h)L?.Q$&w\x#I≤XS}K;ڶ݉;'S&yH{o'zךg<<ڵԅ<#OYSy7(vē<%LH,Z˿x{j}MZ_{I#BSg_lؓ<UU5OυxmCJyr<7E%WY>?S Oa<"?=UIW-U1+KywOF":ˇ8'xX=WR8ԇ$:?L(\{B\_ ME*&`SrEωY&.Ҁ,tD?a2nC:f<_V`<>|y]'ޔV/Ӈrksi:"dVa7,7ڏޑ'8LxkOA5+ٰx_5u<)yQ3.b,^vK+ƛev}̇!Ϭ*xXxNá Pa_0Bٿ^DQ~nP0'**.ج>d^?-xJP9V<7ls?HNDSsr{,Ol,7-Osii!ko?Pcct#H<='y#^jSM[/g띬/(UWF?{> {&}`YLi#1ںy5O禴^YTxK3)Ow]S$DFi>Gx}_цg77@Brԇg
}r`Cx j1Z7=y>TF\YL(چ ]4碮5N&!|Hkb\e h3Plx6P.IuZ l*x.Ї'es~XʳJ^s`䢗L; k5OuoUۈYofyj|]3xv $uI s'}Xx"R ;P?r5VmtQa򰶓?' O;3.s~}I壯-<4҇'ߝgLFaU?Xh%Oӕ@7[_ sbHDcDFzpX~#!ql6$wHy*<Is+TCb2S=-(IAR;xJa~ta%W:3ϐ><a'DS}Co剂0/O,ͣ.sPk~AA\Pu"̝KrY3wyp3H?!OY_G0==e~xb<؞'x}:2B#_5O fjMZeΙ? &SS'݋>I N?Q:.T?*dl<ηAd%O/s;0<Ĉyyn5ϓ2O'x~rI*Hb:`<[Н=n1`'O<\}Ķd@?OH2mvDu5SJsUZIdAЇ< nH yr{Sw)g_lzP6Dyo+kpGzSSO.nK'Xt2M)i[ۯ>)A&EnM}daIGwcG1{YYLE3{y<)}/» ҪoL;h5 ۮȣrȎnU<lz?cDF<;}؁@Zȳy 3 8,~\X園MWY&?<`RݥyAr\|fɽ̂r4M|?Bj rFU|N ̧IW<ɧxIbUf9Nd<H?e~(asa.ēerJDyx2I|}bUS  *O2.ә= s] e70!M)O<5 hyf} J23rG}#d{<ԜUQ-Ϡyjbך'T Gז,gókT]P+xb63[~=cC S؎D/<1!a!OBѾD橭>T<_F O)yJScs<Kg"լg׭9y`%a5Oc5OڤpG*+!mU$h1xB;wvryu8L)O)xJ˓/rLu'@}':|IsstbWJs1S|g[Q' gquyS d%JO'Q! 'xBbn:CԇII?lWn? }$7.= kSK!GQ<wGoNs]S Y3Tyj3Aw}ma89Kfx&hӮ/>pN"L?`bĀ牖gd< YDÓtxeB;S}l׈@ԹuTA/Ly=!L4:5[I^ޏoJ+4954D1BIXZBAtz#ʥ:JRԂgY%<ꃤdfĆ'S9ҎP6ĹaE;>~!i{!Oclvxi8)ľj!d OY_󔤟T1<`{AefjO)VbLyRDͳH#}BY3f1ޮmXL?CS_/N/)CחƳ}f8mJy2txP'jĄ~Jc0NyB5bKUa<+!)S` O7ko$`R< m9z˓˯ ~ڟ+x w'%w`/<<}fv9g5yā2(RcRCȸCxF%s<_/d"٤)rcb\!QQ N 41[9OPxl:&'Iې>h2mRI`d{@;8=O$ R OX7)~jI͉`S<$C$đᆭBLDgR Rb_? yEHMXxB궎}$#0% m-Oه[ydKyb9O)xlyF?9ބ|i4r~,8Y,YɿTy:5y^xj9OSD3e=}P܍ 43TCFI,O5<@3j} y~><7iJ~~T,Ls0SLopeh!$)yxJ[^L2I>hNOisЦӇbCkl/Xg<^> b_ #(MBpO 裗g)BYxwy,tMևC fxt(ʓԭ9P {'˟>0V?<}}-NU< )pȳT`=Oћ LtFrC| hz$b\\+<}jMv͓bw/\M4fiEesT̖ۚjALyGiG`h=nxJ^]}Ӈ VlҸ6 }B Uyixbg`=GOdطG Z}3O;9yW}n'MYgzdOrKfX3kZ<1}.ybg4$xU,OyܽMϵ]rum`EqwCۑ (|I$!BJc#BF!@L@0Xrt1xg_γVպcuZUO^?3x0q>~mscz'ߔ޿ϯ/]'uA@~X eZ-8'ޗ0alz?wmFã;My]<:o8iT & #/v%8k z(:zhxB߀HڬsiMVT+z(0 3Q]n O8R}[sG^rWdi~]˰մ@M=dZ)OωwƫOC^6 B|K%_dƓyFD%LdpB&!]l6{A&_am&Cٴ\lMw}V_J_4Ϭ:1&& 5J ?312տAJ35Uds'l_1|WQ{ByW{L`g6vdgЃ'>/i'}rb'U G thߟqI`_N>ߌ+;YL y>)ٞ}zLH<ĖglxB|q幞S}9Or!w)_(/<WVY }oO=yd=^x׮CӔ{F=O}V3!.ߣ}jOg҃3{;}=$Zށ^ʱi}Z g}ώ'2O_9ϤO5>bKxB?2<"_\ aqm?=3)]5D۫y/@#;ˁ6N/Цz2+9%Ryꉵצ Èឧjy'OzCBS{{#ϙ> WI=R}6Og<:5V6-pZdT..|=Z '=O\'<]s5 (OxZ6^>UH `qSN/1:`onP\(FkQuJ/rńTZɼRbe?Z*r f0طhx}&rd}?=VQoy&c^Y!ӭ&j s[1m)O`"kJXY3x8}Lc}(xV{¯GOZK9O<ިzRQ;iOy4OϏk8vhsH9]vBfr]IRKjfwQY}Hְn2Kq/=@𴎧A@*& Dsy_h%by_6J'=<$Vx3=X^Syc(ֿ<oy~,{6?6A1/c)a#XL2ˇVף-,ұtmy.Ҷ,v'_ 8O1iE5i=Oc sY2~QJ4bݢG0j}B>KߴLe̘Hv'4OGm5Oy'_xZ$Ot-C<}<[whSsEP&Rۊp?']y{(N*I9]pfP6o9IdFIO2˝D|t"-')tOk34L&҂x'OD{DM7xhAy$Ot`9p%MX\So=ϒ1Ay?}$wĀJ*xn#x|' { nR<_7#y#%e'ѥ1rgc!O(j=d$2Oۤj3i-~'FDS^91id^geKm%OXɤO6@nPD$@oԿ퀾'd҄1}'JE(z@HS^I=uQxiB熧o:Eks~_g 9@.N|c-%'"֭αK1R5YzJܜlÖtl!po!Eynͮ>i<-ϭy<<}<%> <ػx+;1gAgWu,rH%xpPy|'<'p@iy~`&^9݄: [i5yO4']TODʙG-mRw1wjAQէvVkaOS|cH-<;'7ѿ~ON[\ '돐{<{t;2@lm0CU?“l³oz%;FG'!|nV[}wo.O+& !m!G~͵ۚovm43'g`V6K<ӥpV2(sPS3_=u-s;`/݁-3Qq4%gVtֵ63 ̮CucpuuJ $H_ xJa<9e M ~Bx4+K0<H/^191dF(ϔ. [}l]s~OW<-&ԱfCu(+z_фdzaޯTJ:I`퐧'O:'h6p=}0>hs}Z; 5R xâMx.$M*4rP^q=L♾<Og/0fRڟ2;/:=xM`a]mېg^;IB#|ĄV)_D ΖOhh⹖>.ߍAb=7ft48Ny"kSt> OL'^-w]/깒C[k `ӚJ4K~Kڳج+,:c~Pv<_:Qnm' kQuP{RLz8,?IUCim;Y2T%1mhV7Nʖǫ_zlm~W {0'/-x" K+-O+sV'<}(˶OT6Y5W {`215<]_&U<: Ӟ':~CV$'<9C䉷t/zxOyx/W'H󜗑evv ^ pMAe>GsU7ȭ ɟ*<;ϼ;jcē׌@qx:g͡>C/=Ox7˧ݸDgfSS{Pk=[y%vV_ 2+1/&*qKv?n[ MFh'Q*0mjY䙃9i6?]X)1\mks`v3)OS->_/ϧ]L<i3J_qқ>.ӣ>K&"9tk^Tɳ6c{=~# N )8G۰yDU%5l-z5&]yg)[xb3x:ӧ\8&z8ȓ/B'0Og OD}Ϳ[dAE!O' (h}D 3Ճ/`hMRSr#y,xZ9ܩֳfOQ&6U IwRi=}HC y '\/$ܣߊ'OƶA*O-)mBD%n>2l?J,U\SE|b:Fz }6"4ONM6YU+OC YO<Ϭ|sy4=~R5J=̳«琥3\1Nxofu!5z'N 'ڃ2xB@<OJ #RI<,Ƚyy/%xڌg`:`<'Վg~?nAcFOmGz#=S,PEӻs\uLeSȎ:&LxaDwxͤd(Dx34[pWYRUOi>܂']<xmiBϐe#i{3$yJpscnƁXγ7.[x'DN“lAFjx|ۿ[*|*d^qiF.5o?Zu)\`-J#`-|dd8c!%^˳phRӐ7]9k|g,*5yφ0Id.rwms*ICHcW=r<ϺڜW|9ny3y9v<1ig)p! S/G3apS<M-YxQ2gҧ`xItU/s&z"}?gIISN@߈>I[Cӵ>}O;pD >mv 0bR%uYlC&Е!zIL߹dz1uγ_:v<>gP)gn8ܱ_Äڱ#3~=@gAဵInݹr?|>CNlIy.@N(V#;zWyz?_zsxk>9yCJ֯57ztg=̯r3\ -6< `_|ݯQgh/!YkE AL0߈ɀ}WaiU(mN-wN5p9BĂ;Q?_{vԐ؟4Y9M+<[z-h!Oԁ6Sr&ɻ5vF_x7  /sP?H-j0MP V{j݆gS7=ϴmzL"ODe=<>jo^+lIzg#z>y,so[8$HӇyDj}?턧MaR3ϹI_ɵɯ}KY4/`_C[ݭKMIH`4O<-\闙>Oyr=;уD'Aykؑװ#ODdUp+<9V˔gXߞ}s1OpA3?m4C¸ڊ'á>+ini<|ALJqY_jTKOy^2P(\^p+&G=Cgb!`!O_<- QbzHMg(OxZ O/o{5$ yruD)IջkH ~/Ϸs-l߷PKyzIF΄ĄȪÛx湕gZq=(Ox.G_k=f9 >.VÀq!mW`;sɿ휧rOj'Γ 0kUbeA_:S#e PܿOLxt>Z j*rr_qj^Gݮ;[#zn?GAړě"6z-_a-[[O硁VngƒuNv a` lBam<1;<9XE9O)O[s^%kf}zܰyi#'>S[x!Ϣϓ*Mx:p-;dƵk yr-pus4q2c {ΐ0g=NL]0οyBigC'|y=Ϳ4gSӇ<1I' G}:X8Y\wR8j6 ivsOGу]ҡ1ҫGo}CyZٖU*噺<WkX%'ϝL"4m쒢XO'<n|}Ft]Wa˓o#OC<-HGq4Km\<ʀ%yZspbeQx ƢO\o3hzt3[z`<6hJ7W-3+4`V?'J.9t=sODayLe_-O<ĉ>ixC6$Dy!,L)=It3a:'=Կ`rx%c8ie?r!\ s=,õT<(ϱ[}B6K"K~r'jd!ϐcrʳ|yĥثҙ=zcPPOhV>7z8z<>ox9ύ{/\_2[fx2}"֪X>`sy*Jl&x)CE.L I>Ot jkG2Ouv6`]/Ӣ+O-<ӊ'2(GSy.w<;>V`/2}aO&'NxOVb4  x nt*%A ϸdςE}֠tO|+zfg<鄴{<XՔC9@YCw0Ӄys;z i;Ks/ǖ;OgMLڟSS'g*a@P`'h텧su˷p]}/UGz9`zPf<߯ub3?xBGDYˁK뵓wcY>Q?WM=Cg̭}rLń4wbaѧ }V{Sg=4EӫDWX,_\#xR8.oĀ']-SU(o&ѭUMӗQٿK;}3؃tѥOFJ/$F- wStw_ן[<ӎbT]t+rk+/' 93t&̴Z5} 2?SXwy,V -^HK:r\ E[՞35S>p}`GYmB:$EO%V4CYg!xziJ?uK9O {5OgU(lʼnOFi(,xBDy:Y<ʀD*k S40. o`a3Id^zi'g҃Aտy'O@I^ KǫO+$+smY{歋uAFyk%C,Fӓ<1Ӧhc}_ ?vǵ]L!f{b}r~ϳr7[<9OE ecg} CNJx53#$VG(2:A<=O5`9Z= 7_e*PViqK;𴺌+Eų͎JI=ŵ\ { MgVhZV& }?}SaӉYYvd៍r7bE%xȿ܇t$DUɯonOq9&Obq[ouMQϗAi}&"ÛxR}c9҂^iE5kgz9nŞ+=ûg2K+XZomyijy`JyCI[_e `C{i#Ŀ t Oh} ^k)? 27ᵜUBa_yCZOcN?s}`Y@GvHs_w'ז't]"{Y0O;ӊ#<\STTW"ߐӃiE<׎El֟REtO >=eHphbJ “KXnT '<~"aX,IQ%jE-O*mC;S'ט=dshzQ#ήX)ms73yECeJ5Du|0|?&<1J~'@Lwz7) '_o1O1;CB/cm/G'w[dMf]=ި9=SLzL0O<}:@CHԿbOnytaLig[珋{#Gy6"Ul6Է' =ӧ } tXJ'.w{8²CJ́BOto9\wTL#R`ߟP;u ;r>h;yC5.n'&S|}?7iWA;#M%NWx:dy cuEp!\ÃasyכO?Ox)\̢O/Q[n6PJ|xD Wh5nܰS5s' :Í#U(sC{aW;_EDɹ>OA5O/~^rR,_fyi~/VrcC.q祇T~F5h7xruى 剎grOO%&lgXB <tzLzErJ|,F\Qr*Bb0[3S2~5RR Cn2?pwγnz0{U!=@X~ϜYV9eWX0&hJLOpHECc'܌'y pM #?yZ?%fLmyk'th=7O+:*w8NλzKxR,4!˅rD{Sv5Y2FȥslC^VϯsAK9H9)j{„g,-,; Eadz+09xNyN34< ]1m9cTe#RN~pU& /<'1O9\ OVV+aU8~͋5ִ4a邧#t'4Ox'dKD1v4Of4f~L隧u<"5F^Չe5.>T}@ BLO//cP'<ޢJyM# h Jpyi8Ƙ2j\$23/ƿr/8~vN ې/FlVO zp8wx|0Βg.e>}f1e%N\2f=8VdzWO}z?|i\u=!O>Q-zhxZ96'>yts'ʑ+>M[3T-V@Ǖ4Q}z/ͳ:#<@Dz` .Dj C ' U{^ϐbSGQUy[YyzY/z}rmyXS^i&\qNAajgfj7ңQw֞sT<ӆU1!u]'/P#@Cl3iAurL:)'㙏{zb7#.qI$墡<9?^յ? zP<(T<}3`$gw9,^ rd_-Ϡvhv8L_{%y:2V3 w<ῳ;;)KMg<=k_NUR^@m3aB`[I췼Vs<ǚmmyPߠ-Bxn xb҃KL%L{oxm=}v/zpmN| !O>)f<nLCVCj!4Crxn.MP(z- QU]ֻ ! >Ep6ػ]kf5/l{TMA41+;Y$LxQ\}V0_tѰSIz}ڨ]f9@V9"j̿eM&<頩jij+e;=ņ'fq(\RS ]փ.׉ҧ{KQsbq>eH1J)OD{xJ\!͹gm5Id7PS_>qF,VTxz/ϴzh83 >Ay@tN y;~xn7?,Pһf4<ɖpPj4+wzJjOփ{, L) *ZY#2: 6 ~yHUb7Õɬr'O49@Î/KӋV0:I\է50Ls@wU0QjPF| CHlx/< zX9JR=KLspߜ2\{= Zj7xY6KI{Lޥ_mXXJ Eõk-")RӡiYXBJ 5b\wqMÆguHgLO9D ?M8:t8*&yxH ЩѺ*QmM3;qH5r15LS#{džIؿ$m5oaYL5x$MA! =փѥl*j֖ kNojó뒨6s˶9&LVH*x;c)8|Ş;O_k9x"6#RqOLqsݳ? }ڄ'BoEv,8 󔪆<O' <)y }"Dɪ_3?pMgAz,87DrT-R:x:oM^(,S_%P@'ybȿO*`%i<Z6i"-ĵ`f1zJ!3=<#<3_*81R6TgFC1aLO'%D5#uȟ/{a$bΛFa$“4 '<*qVۃ'r.* $Me4 DT|'$ζȂVCBjnxlDG3m YĤOa}hSYm, ͜hsMQ2<;$,R̿[|~c\zW/ Lfa#+QM&6 Sr:b<)SԪ*ͧ@>uwڃ;A[o%kfxBFn yAN.3Il<C#<=i{T7́>m0+U!wi'gz Omz)wƦUՋ-q7=$~:tAjڧ\)2T6fnSZʠ7q5?upRC&GIfdϢfXrV$|O26fQ_qD"~ѫcϠ"H+ߧH%9Ic%PX<ݜ.\'"AVi'' |{(3j.0"$xON#<]9 ;ժ\[mA1CdSK{egzKx|5M4E7V+*G\;bT}a}'Ahv3?xͿF2LAj9OPFγ`˱dʾC,.T뎘2߮^`[vhɁn d *b"Z/hZSի 9r]T5:N=@Xo +Q'!CgdY`lDOUM$PȀ4I"(*rgا3_IB4CƓbO ǯ%U&Ο_OJxm(!˾3Y}J ;A4RkOwF'y)ΰҫsL:Hg> rpƠHi0Rj~"<)q_n*iR<ei9_tV/Sb@@(+g JS->!S}?i6抪1b<O""#`OOrLOOG鯷DM&Vz}{h L'\7VCT/SڋXuuf-l@tƓuf%\?bW'4)^ O(jv~LqOFO+/ڃ_l)ƟIdv,r( ?NO )K2ˏ}$ϷC%{XJ/-j`_lW.N*9T1uyt8Mtϟ$3!wIH 4=≮'D~Q3kGb5MED}rܰTCy9<]{L{0 ӱۥLXxIڃ'n\Oxi/y6Bx:<C;<_PAEB }8]"8mZ Ix괚RbUW ˆ]e,<'<ےȌb<{I}Fzl::xFqƊ!!,ò>`dŮYl lďd:_'z/Kmgzx]2s.!haLa$؍'.LΘTۄ@&[TG+oq*>X݇~`cbO͸w OUl Q3s ]#X5UCX1X֏ ]s531mS:-xˣLG+u!mLg5$LUgZT<bڎїMf\(;o {hjB1gB[i|,yAR }s lp~8`9Va0V `E?cY1L籛k;cۧm lZc_o4$o=4k#sxSj~,w4J#vc 'f'-dkO_ۧcVW+ Κ}:!5xBP'JLf"26 .j}`")sGd"#0>VA&=3REXC4ᩝvF5X@݈{7]戲쌙3E8u_ǯ-lXg[0cǃӸ{$~:zfw=I+ H (_Ǭb Ff0d>C1 +`vSxbߞ-z bezz=J;dTw~UgQp8yX5fق 0b(<5{QSQ`O=H;mL3)[>m}&1{O-}sv|a(j@OR$mX9Yh]`/**66Ȼ>ȸ#sxVVLFmDPOxZ3np չ07ZΨ gKU7s~'y`{مYs}o[{k|z%D`r 3 0- Yg/*+g?q8p>-ŷ&ه'%m>e0SY-2Ϝçkh~sO(Tv/;fr Ξ]opQ^A i$^r gКvJcQk@ V=U,1ص g`״ iDCO/N$ǘCIj~[`ļ!˰ߡ9lcq*B|EX| pTKڣj{`&0^!DTLE{%hJ/@P?^}^kan .8!zK>4؆} fǓ8<mj ==vnK/\#`.7fcش u*hj^h\DlY?OPW1|'x_p!Ê:=SSûA[R{$f )ʳ r .†͠mȹ`f8Cz: nyT ;O6tg'xbsg@C n{]|3wIF[/g D0:{iY:``>kx(+`ٍ\~ch}C:aBOVVYj$%^䄓1D ~+pJ IYX& 38`;~鹸{S|vc"yӝŲ&yU3: {QekSq  _ݭSgO4xbޚm:g~2 /!yfΜ=&[d]D2ոV>|gX! rQ f#z\(T{U$댜O-<)\ ԐQ<b"y~"/>t. kbA0~!9nZA=gh*<{0SǻdMEGߗnONЪBeRMU9 /pv,Oe[w?glEks@ (l֤;x.|yOƁA; hWC9lz?0&{b>!bdl׎Bg) R a){j'Ycf >3{pő&O"<ٶzŢh"dGmޝkZW"F`ΠOՔeGK.ۜ3{VFt!Tyq?K şۀgz\{F;/{7}Ong)GO!@M#)m}Z?0LW,k?U|祦"C|H_IS_R3f}.xvGzx2LL?&`6$OZp YTF9iT۱͊K_Y_dM˞ \uפ84$X<ݢɂp`{[V޷2$*M$)S8t59Z%b-s/pYxEg S˻Bj9؇?}^9v! .9x;p||,r~5WәڦȰ%j<]\M'GњMON&>j$R8QtrN7DwR+)Sx48pM)}t0Ba,k%Dh^/Yy>\e4ⴺ?TRȖJY=<#uԅߜ?f 9=>Cr:j(mxun>WVQRj?Jib<)30Gg(V[g:"SkT \Eb o>TmpAJc4%-T!i ip5KqEl]f]߃jv 9\6.ه$$z+j%Hga IyWj:i4gq:RyoN\}~t'gK?-kO;IK:o{׶TQG|_>† QYnIVD>$3xjjvP%+'gا7w&Q{g3W}8x粴8'<{hI9D p5RnW@a5 _7~+*2H8iR62,UsGw<#)12|D t!Y>%|ql_G/߼ȱO˨$- t(~.:e]l83p!>;]B?CN[gZݞ//4<.]B$UwFXW8o6{PEIYySeVJβ^AxKIsK{&ʰ}F'sCHlMhkPMX`fyε`pP SÝxFfք6_/]/(Qdr¬߉LJ/@<UN)n(/e^GHqKq| R67,0Khz;hzE>9QoMOP[)h<{eHg& x/lج(dDEǫtOD@>a1 # ] ,ۼ|ri4 ?BRpQGHV䭞Bf  g](R4gn繑>'為y 9~Exxz,³X6oMJϯdx޻йI|AdXOSQS{pFAg6@KQba==U И-+ M췵64;D2ԍ${_/Έ2ݞxt 5ؾ=YXح?,S}vS+2@f(bFyBN0l Iv2w$-4zu [~ŊC`{HDq5k6b['AF%=)Vs'5ش1J=X= )_x-8~nzαG ݆o^d*_+X4 .8ⴿ3\ngPYzrFн"W'\DZh B-ꜣ &1\\δeIy^jOyzXCX֝8|AK~ova>WoNN޿41r? M <1JYD\{0qfLQ6xMf:FNJ ^U.@Ifm6b< 8~_l*ɏͷ}qP/Y6PvI\~,>]5MaUJTqx9acX>ڥ9Xע u>}u#ίGZ}lnKE5~LI| <3)U(A ޟ_z1: f$^=zyM'xXԊYjgf.V҃UĨobTP_$>*p.JFPX3ZxNzY^:oo\Njs/j{4rǫ[&yD҃:`nquW`4;Xx^/i;8W584;->ݎ?m0yHlc8Q3<Nr?b jzq5]. ~mۋS(D;|u feEa)J{_ajAuD-VV۟ 3UXi^b&'\$1HRX?۳xhO;сްl{{b5ؾN!R-<+U,oIcC٣op|_u;{s(siFB|$S^M sEZsz쉩Zhz2 ~RpjV0ʼF#ye]:*9:md# ](=jy;²O#a4VH~vWO[L]廌d߽oy8r{~ý>V\_:1q/RnYRCIɔ9E\pT{`f-Nt޷fb@͗$27~DRٱHA[c0*7)9rH T jׇtB:xVR.*ꎧF+H+JOU1{9٩jT-dM!޵Kf?gw]Y<@Zv!UdH;Z<tp^pcEشY˪v}J<{cphnGrJ"i!Te=:VB$Db n;_xݖFQ'ϴ12rzl/' ;GFUE4Nqk]`U(V۫O8)WB!xhSq8q w^uӸt  xe^c_TӯARw5hPexJHIkid<ֱv᪋LH,8u^k5]WQbaˬKd0|hL=vLTb|)# z/aݓsoF繥t*ڂ =̣dŨԩHm_( T=ƞ 0{O*.#<4 JBI=@M~8t;}] xHvA12iGxX6M|8y2FIiԕ5I.x'_r,Nl![5QMhШ=nR pLUh1r=yHgjiOGKB.u<<)sA!?;yCx4)캛 鮥!Fչ9|h{vOtmo 'q~CpE=t^T/Soqg׏D9L?6\/1.>\Dd9OMjkG,]wmN$cx/@>P+PST?I~ܶܫU'of?".H !_NHLC2/- >6:'v%6,5893xn}*E๴136Μg9f?bd| -)Xj[w&2ڏavK 3 (E"a/Ϻ77CPafQ@~ߨP$geƷOowfͺZ*Xv[x~ JS@\<吺2 N³'|[g==Hb!<}QmFw^I(ch|:~!;N;X 6Zt"[ڥҥW䑉 lKPZDͷ/&||jW&$^9%=X'O t<[U[(f4Vu>yA2%U%Dfg[Jw5xn'%a40Bv{ԶY|dgгJ["y.x5gT^%ظsza~&x0JZf_DԣF;dDR.d|OE05M|AKLtO18MOՅj$ӣ F y)XIRbxx%Ġ?9AM4 1S\~^jA.!Ss0~WB!^a+|LSV (5gO!pb q`E }{depH{naN_}}'?DY%"2I*Tjdn,sjnrJ<)ye5 Drf {&AdF)zEbxR\E.DUGԕLé<9ӊVX7Lןj՜ȶdlOφaWZo#o.Ѝ.[vTp!E=zTWTF"Wng<:`1&WYߠztHy,C\BMz4} ?5{1PE }DZ#/vEx-ܰgJxdtWDT y`)]H.(j- OK'R[Q aV-!mea.̭;;>ڮd4wۮr^?GZO4j!*B>jx.lI T`禕8hYC4я=55<{ O㑕k Kqr<[%Ewwʓc{ )kUw1M9!3W⠝M * MFZi6in-pH1x%>.eϬEٞc%-w \/Xku[5#1KkOE$ HgH&/ceJϫ!zT:WCn rÍW) S<Yav] ~w!l[Y/Nl WYy$wy`fjS09Mv۲ tO֦1y:N2JA-a%=+h b쓌rP06.k Ѳ| W(u+atەsSmUEKBqH6ɪDc–ոmsxfaFL #X;5XIXš9߉֌ȁK_#RC'#h²{IGfb*3oM% O~( 8`x| Tp!ƓAevn[]9~¢䏬lՕYig1޵z3^,*X86Gp$6IlēxrvNb2[ ܵ8etafNә4~؃=lߩ4zOnDb3y7L1<>IQlXe8x#S==%?YYiN أ=sv"YHmu9I9*POR&yVAbiJ88 Z%x& #X Sp^%7pacv3/ .fT!_)ē pI+) TW0ŸkIc(W݃>`>\x8^') Z;t<\r`ِAd p?Z`aKO7;볺O={샿8 gL5_ϟٱ^aJhECᙸD. '+.T OΎvwߦis7~0 |xnG^}Qбs\?11gi/wUǔtx# ?~/9@“3v IRk<8Y2hցGIZV6Y|AMx,t}NLx}_cz i|A<+GZxxӾogGS'ޱ X*O]_kmpn*05' Kg12:(_'p?&gji+@؅k 1SŢ2agqu._ナ]񸃧hIN"2S*'W~8[W~Ƿk}}lށ}>~y?lj7'GϢEcی(^TD P$v}mw}اc2*ljEX<9c2OB9EZgrB7l*<jm!!jͯ($xԋgMq-Stm̡ ]VetM sPbpTgקj! Oq=>s .Kt>yj_g:3e_'6g,k[OÒh_|)xa< ^s-N< ku]5W.|~eС"R0,dmk:TZo)O3]T8 ҡx4N>`X z%Ŋ[fv2pB  $.k]2مw|/&ĒW pSI4jE͸l5-c+UL^v%]pmx/4onk.tEu|ߛǧO߅9qecq17&Kxxj :e!)w7WN+<9SPPs0>ن9xW VᰉŠCջ}s(|*yX?S= V*cا xEkG=ƧƿS]eRhsvB>ތ#ӸH|^ )/FӴk]M﮲O=~ XdL5#<Zepg'!DIC]#fm\G=DNv!ORx"S낖/^ˮ!ʹ[uB)-3ᙱC0kZwr-Ƨ,ʯpSRL_7#>'xlUEDxN|?9\߉28iK kxpy|_ampÚV(xߝܼ3Eƒ/uJcT} 7]CWN05 7^)X(%5%,֕jr!ӔC3S(34yMN,3J-l5xgpm{ =\Iv)TD3m:{wFc%j+B>ٌٲ3_o}w.|/Naޯ~._5\\4;AȟX c⡭0m{,xMfAn~09(IDEɒZ{3sWY>=Hūǡz̛>_',r/ۜhCg%,a4Gld*8CQ_ |Ѫ':VY-#=j=6N+: Ӻ*R|Sb}.1E|Ɇ`6= 10^mC<{Kj!}r9^y?~sAsaośgөMDgȭhx:lG>۷] ^} )$~p%΍3$}^_)__ē :8͆ |맸nş1!<])o$?!h“]<$Ó_B{&yNPxr]F׶x@$@Bs!ȠI|n n#fVlxrz=a 1.!f9؛&z |>MWخ}R#_?kr3œK+4fgugjOh1.=Wf/{]<elrcg'r#0›7 C&D@̯ OG2R ݈dA >g>\d}LYF+rSl0nAw.^᜗GZdޓhy5X9Yg^ߕ땼J<$'( )Rӊx8luhp‷`+,,nK7FgwO3#"Rq\p"lӰ2<ۏy|h+~}iO2lvEо̶NDj .;K EOx9E*jH2`W<ƄT C6;>-“#sE*}76g$췔3rgMgH9*j<~$'#'I cKTmT,T']4DRWgDl~o9\~RRE8\YYR~=[# vP7^-Y=Sgn7;K5bZ;ɡ2 hDZbOHֿ63qu<<~t'pR޵ro}-G]\d"'5ۯ[xw^kIfQ_PprS?ܹO]֌∹:|wH}+w%Ӟڧ3=DVҏSLF%i3eI\3fO(Ui*eÞ_1rSAkgA$x"' l/b0} w86YZ~g'vt>}B5F2V/H< OV+@H?܁__bUy: ,)c5>̬ e]Ü.DtfN5b=xIKNh"#<&'š$Aœ<92D."e5CcECCLa$#6h 5naۄҗK粵OtA2nHZDj"{0_`!*L0ΟO>MY(U_n|cjsS'ۥ+C[^8Ë]) K^'])8,g2=OѨqW sZӚIf{t|ug *ߣ;3UR',DrxV Ns{冭]@'zDDc@s1 ]")x* o̜'ҏiAf`)_牢C%2Y#w5cS"*; Ɇ޳O8mZzݹW~U5E9{~io xaxeaUgDBIl22V>]<;{R#G^L$WI-یj<Nm [|ڷ5uU;@5<ێmAZC2dhgpxy}xO H{̯,< \hzWognGsKgb~P_'eDOX Dvn VTVo~X޽h%kq~I(OC8D}]N{HQ4=9/nnv죠  iQ,_>vu<rxTge`[igvi%Mal;d=Dxr)ݺQ1Bqpv' ۋ(No/Y7꒸`"T =On'ηRTT|Zڃ9) 'tDOvlyl '\r8P t+]t7~E5vhn8C-^ DzԤ$xZJو2T%/wc摥f¤ogg /ǫw7b ֲOHdc,AmAN1l8ω$ʂVthNmo]7vz+P l'|OYY5ڰhmf_r.;Az<[)#Vk,$(耯 wNP8~f чD3`k-RkoDIX6= >O%llxsI4rs$mYbO/<=>]6FP&?p~I@Ǫ{1H{9XȮ- d( !ҳ[ϯlaw~q(2k8}BN>5"H OvV,ɸIν넥b" oJ?z~մOѨNm#M´|]ۂ{RRU2 [fiy+Ihi$eMktl$[:$:1  3rqsIAmas>B)\ %p7Hv&i/"öA^S<)&_rͮ{ Zg3ȴ9-c&~SC%qZYL\uPq+;xW1Y16v|DQjsS/xthkC|.]ϕp`z'KC-9z+1:Ah# bFÄ.*RBmŅyTJ`&f?Yfjn|r ϖێjXMa=<ٟ}~SN>3xRg~$6 k7Y!s\b5w!b#7L^⎞,sγG@ rrT N3`&2TW>I9$*XW/vuhl54r+J4x`M@4mCT"M/jp׮?S,։_E:ew$33'؅?J j|`p~yuùs8(<|1w1@> r ȕKvdϷ8`% bV1s+ 6ukZZ_%_AYu!,} mO^>u iVS?lp\[[#s2',I`߶woM Rg*a]}T.kEH{ o~l\1?.^U,J)pnpbW,im@Iy/n1k||?sĨ`,57wꞲZzȃ_B z~dGb$Lӊ[vMB#lHvL¿E(d@ɧ_D4U.^|j\4g v@$ -l \&4ӗ0q~N~GOg(QKavRJ#| *DzɊ䓢;*'imd 'UY60=<"BbU ;F E?Z !ޏbi-6-ey46dE%s9Guׯ߻/x 6ZX?(U3x5ᕧ!5xn)bLXm % ŴBC1xdxVC %DXfʤZZlr,ĵdF4a{|/G׬Eˏ-wqp|!Ɠ 1,G<38{4Exېw1;<gl(x6d:I{!oUoyxHK?(Ax DnJa([Q[zzO_[MNvCtw.|OF.>HlzWicƠ\uWa.OF1кǿo!O2-2 MdLs {q^}73C{#Sw*IOfJ<]Y[֍W FQ(RN8Z%'_-Smntkל&GZr{j߸Hy*{&oztm,$s*sp ل7?JcɗhR_d(E뱥 9_L~ϚO-f;dC;;2Nj'b<9I6O+Q3\\!}dmo[ idȥw$mC.Kᙶ&mvI/D"'? \ ~4$/C]<'oW ]ŲSx&/$Sg|1uBe`I툥PR-Ųyܬj7>uhOF!؀cF,MLpC^4SC8jLF|R-</;׾\_cd|Z#reD>E]Wc/V>T$27UIFߺÁ֧vOOjtWrΪ-GtR94nŧ~xh~xnm_ q!hՒ?_OmL0e65uI..C(?iDx ?x{-vM𬁋ӗéki ,{RJY7 '*. A>C*Lhy< hj'Յ͟%qА).dU4a' J&7'̓Oލg'qبJjPoU 8xT!;e Uҩۜ [dyȑ~d,,IZ!i?٦Ifm4F9?|?x9\;/OŔ:NV|/\-Jʤ2[5!|Fl.8H־bg5wr/6֋%KxyU 9x"³.J?'.[䁋䳴ȴgNjda[_.W%5:ڷV_Y@}PP?Ӿ'³O#]tI7Hdxe.s_Rg?te"hK.˹:Z_ _zob5BAS2: F&mD=P*REy}ezp:<f vndg5`|y0.n`#+KaVé,ó=fzF8w/ZS̕p|+p4r"Q>"<}yj|G=V]5mA ͊!|ux@PK"f" L 6lOvpe(d P>O*g֘ox&).;;OFtJI(;XT@ٺc,l^UN2\,85(IDz,w`OnI$<*œC ?? \ގ/ġyC^!,Oi[,lfx6vxsi jPr0;fvLK ԁG^y||o3W6 vP봅T OT:tp!P\_u?sR9O㴃x $z|mCOɱa.@1N7|S˃56WVEhyV,pMgP"c"VH]+;G'.ڇTLI[P`S}|_hl^SV&y_y]re¦ē3zWHp3 !&puztU ^"+ lh۴n'進@9cϿKUmv}PFJڊ7e5D 鏥06Y'zK3g*<})H[4Oʪ0 ^/f [9ϝSUb ف>B1le eUV~TDJ+xxjM6y|XTHjfN5M6rXReKn(spZ“-=]qڗ$tI~h/iB -&*zHuL>c'g4/Z0oɾ.Th80g(]SzrιRCOJ2H;,tI.S^葮ӌ wg&PnI CH٢ݷ\N,> c/eř'eaV|WJ^\yH܌5*Mh~W :~U_'_;{Xm 5v?y i}cS<ISaiմd_%6]g2\5B>r42ީ _6k>¹0l̢Ux:·#!۾k J&8%Axٮ_'amaC }߻n OD63J]1_49u ekilv<~+8(ںDїx >x.<:Yp2;fߤiD:߁ee^RTp+ 5պl%:YSF>f; 9eh˾wW8=_*κ׮5] |hoh'I䓰ȃrƓ<٘еlBi֣f3͘4?!Bc3EC/M4߀M}Kf{J4pX"'b7cߚ?7ƓcPGi_'ؑ#M·}DJS rבl$OGHߓfgR}jd'OxF[?!c"ainsI\g&T˓?^96LHĠKVSv||׳ry\ߝ6I30$sBb/3+D 6M!ĥJ;& ۺTtpxflf&x&PFpI91+G_j-7݋ʟTb yPY,3 _~GfpQpHv۹gpbzt]dhdF[]1 O1gJ 8ǗZ`tp.9\rA@U_] .|LEͥI.!{,Rl7 ?<'oGg3& ,On!b< MT1V@DthR%v#0ތ_9Z|t,֭/9cy= ۓe]!cV@5\ᙓq{_eӮ/$<:w!م;4:uaIH;8d}`-L=#j59`,"!+a͞Ʋ,.TϸQ͎~dWuOઇpcQGɠ[h2Խ̶3g4+OA#6} Xڇ S8A]Lea9Ƶd~b,"i!<Sx.Ō(M 2"-LppoWfm Y(]˛㩉t`uC tN,?&@ksp3 i'Bզ]O)$JҶ>A{OZN=x3 X蠳П3zvǧ5PEOWQfwVB?@/xeÞ|.GcKO?&Zqy<{?|ΟD,7ono_Oؽ#\$F^qVS}:<[ٚStm_ μNj+X6S qbaY+ 0UFpe=(>|{ґ<n2d`m=9eEڍPx`gt 7oBe'lʺm#I<ɋ-0 ۲RlOQ׍GPEiJgOUR+a|LOa"Zh'< 8tcZ!g{j#B,p\_α$g_Ċ!tv6L%-^r4xd$wz+z$>O]W!!9E|b&U8֒cT*AQ)~ uG$=R ON<۰ұEfK7> ³3WR_x`OR45޵a^'<MF'w\"x7\-ij~/w1lIGsWHj9ݚ#$K >SH&']w{Z0I-`5*̮_фAb%xjJ`|!K5?I^'ST 6ȾYaw^{Q *hdA-gr&N4yAⳁ_2a@qU~' *: I?CJ]YIO9vo }qD*Y0<9B/sxU8qܳ^[`؁0Z"BjOW(i&/OX_ I9G4/#Njg?t|{'t04GcLӷoچ -;OY O!=J022޵ ?^'b2ůBGzi~E"d/3x*h&c. فU櫳qP<<#LjV{_\]O_iBBfSqW޹ _<)ē  ͽOOșF-8r\sm+& OP+ (4ձu'%}t/݋ժ;RY?d4m_"4V`yO.ntMnexV9Ɖ|RxOz{]cNBLֿ220ӉO ~n ۯ,g|GB6#A-ʫW8< QUX*y 9ӚyVUu# fjr)a- e#"8 ;϶Z/t:8ֶ"L c/ؤ ]`%es[]2>pցh ˽4i"<-2!}a& u q}*/]0?O2QLȍk?S2&{>H2]3}$ p w+yTJ/ b`gC=tg€h<͸>.sn0?mA@_O=~ (?c2 _ H6{Df%s&K3xaz12cp;xб)D@z>o%Z>)i:Ii/d0|'l/,-ǡcC?a<@ nF4dM'I<<$ahH'.9mB\|FL eRpq3!<^EhR3ž<%^ %b*zE,z9C-btwK(ag6 cxTV 7,u?)^;DL4.h:gWLy++Sv_װD9afo;@*O lsuO OGկ rJ2^u$leڈx64i6NI1;ǛwƍY+8x;Y7#B-.̆.m[#Hbf!C1tϱ_xX7ݰ'ҿA|F` 12ų.y_ӯGnΦW]9q@0ҿ㉽U( UO>}K$xZ8'"P`gf:EA>O" mٍ> i6uEÒWjn 9jN/F8INMiF <kdzL~Q`xgMaڨˑ3Sœ04UfY{Oܼ'<&)VPME/<#=05`V`H 9yPx1ed^W^&eߜ~jsLiMr J#Ěav' zKt#az._|J p]WJ[ͲE81FPx%H^et|zY $#'0 O'4Z&xBMA6x s:<IaHvI 9aJF(mA4oMN%xR\h,:sS8 W$N fRSga/nM.NOтDs t 7m:EswGC6`;DYξ>'yJw4p"hOTR2 `$l*#ʶM O8vlvaߊv9$\C٨Kw2xBN-H>r#{1e~ ;"HI¾%لR_ {Txvt@I~^!q )sacnʀx#}YRf f8 :39ҖSʂfq'Ϫͧ> |w55ź\_2'S<)_$*<6i>?4z5! OZ~!ki=H2 WgNH˃ sxI.G+prc3іǓaj$226OG @ }*a9]u8k^Sʪ|F#LUAC 8H\7>ݙd/ݕtxN6aɆu iI83x]Nq#(kHֽO#4;ɁuxRV>x>yO|‘{5Ó%$ST3^CްqH y`}wto|;d>|hO2x7,J A77&Jv.ԡ P!Uwc/"ȤpO.O6Q9kGTtѐvf.ϯ֣EXrEɁTsE]yeDK/o+ хeQo-~cUYfc"‡ouʲע:24GBHkExz0kfx׬5T.qՃ{ iB T>gȧ_ q/`{oj[%OxVc!$*&xROxf˒ JIWLj-,h5Mcz! xB%ceW03 Q _Ffp$Ml'يǚʤ3C&ڳ=$pgW!Pv353CclNvS(}͓>%wSOm,0Q?=%oi֪؇xI+lА#_P[<[jmflu}+hab=eCIx? 9MYT:KlG}P9 B:&5^qq@S|Hed89$8I͜6*MJ' _7cQxÓbr!)[A`yVTQpVLmRXt*³paU$&:'7٪+m'ehNH |BMO?y ,Pџ!JťI O։u܁$' Os`q/t5AOR)+'3Ldg4$XIг!_|v}ۥ3/`  XigtБPdЖo ;A}cRyYS86x:|U8lgV7.~J,>ߐSȾ1âO4G?}' 3XIP;CƐᥜ3AY;ے*@uxRG5=E$Mwk9oLKHmEx-5d7+b|J ]K0J`;PG C~b:Kk:8Hlt{۰kl*Q mU;}NJi7lsgnk^Y;0''ekw]7_dA:@uI<|C0M NF={]?71Q+B7/;6*45IS&0]B r{,]y ~e w.ę?S3 pZhB1 *qi O Pɇ순YR详` >l&U 2&Culr-G 8o^CI|G=m-TⵑlnOy2p/ݑI̦<6!?N`s<LM^(!DAO[z߱dIu/;`@% =g HCJz;'5 eUNiPr8(91;PTZD*1=m _Ok:Rؑ2}'uH6.!O=Of`q%tMSָ̏kɌe'J*c+UMcl'Bqh?=+{xR~!FtB#wk$Y%dpN|\bcOU(ExÓ |zN' qgӤ:9| ~Aބ*Y<o،O`儈F 5FxrQ4$Q&A/p֓pӅ1:c$Qg+<9Wڐbx*4Sϴ3Vt/J>u۲ -Bw b|Fx#L3MԀ^H=g%y m|'/s8拵}AW F2aǓ 4VQc Ud=Odz@.r'Im]^ Eg~1ހj}䙙M+7MG:v-REԉ៎|tA_Ȑb.A;+_2yEp -V]S M͙S'@"opQ^GwAY viR5\z":98V4TXP $*ۈAMUt-ҷF̬`uaң'l+/6'"#{o! KVoos 14m*M\d{O"n}C.~֙*N*!O>@k/AuKՇ2us5kq6tfWS%[E)I }br/5, 1EJo/>_8{iGRr\@"@i/VœY gt(!R/t& &[ANZfz3ڻr~OJ O>_L3>$Ɍ,)T0OfQ4LfU"ÌCu1j|Tp&Dti"fir="B#'Wt2;MaSRW܋a;;wOᅨN5x&xCp(fgqJ[s[u6L9^x3W_"'bSaecSM]Cy2rc'zz wp!nG&S̥gM-,t3 [}̕2tx&AEH2jx 1 L5<; lJpQ˵qxt'OUmGOxcwGqgvz,r NDU~쿖Vp+06җ˒1k>UjAJYŐ)3|ڬ|xzYg›/^N "^ OՁؑy.&AMPx^(3`P5YBE;}S%%"acDfI'Ig=w_n-0mx8$R25:,<6>ss 00#u ؄Z~J{]ޤ­CS8n ~D|5ŷɧc3@_ &c;57Z$=}cx yUxx>8q&)`*>/I顴*&'\=p?1B+ZʬœU4N>thno9|^\pHIh/z0wd"(k4nY/= 3AOE!8y%N8jE1$a֟I~7BS{wb~ ,;_w| sYϞǁq /X}U'Q<;I7`"<3̳O*'jZ!٘*ۭѻ؅؈z vz„|~U8`47Z%'Ƀӷ=;*yKgm_<+ `Gs\+$'=$Ouj 2 sT)' ӫ4d@ZdzV4h "xQo"uh@aˠ;FCUa~aI-\D hTApFI(H3 %ۜ_O]w=w]%pws]txxz85ٷ J(Ez-+_1nR'lCWnMIDx z(f6kcv:$~਍8~/'N_æ0<]wRcimT{6-5M|8^hT<ߛSxj[uLb֎`AXaCŐt?or*uB_zf4=JBG<Mebo8_Ex"/hȅLsrQ D&n #iڂ۩hK&1;\&ub=ɹ`>iO2Q_#;u&fvdbh"C;03o.w}-ZԬvxO?F`=p3#``Cg-sY[BL$A:HV3IMiiڶl &s 8~-|Z b-h*;lW쩻Fm9+i<)g(խ䜥Lnm?x^SvV0?! c8'e\2r/q BqMg@ECڋBQ@/xfj)YpmyĒ|^^tl7`~h*NJc_)Yux q>A5C6yC+]@ $ } z*<3xGV_I C_,4S9lFڢp~F r^mͰ, <܆ߛw}YFvͷzF|Ѭ&i@(w(`^,cdvafYy{\'Dž|XmxxWqVˇsCQ)i ӑ4$;>Q阉OsUwp'@F3ٲhd+khێ]^bڍtMز+?^%"x> /3&w.3_.agﶺ^ >~3&UD=-'Ӌ3 =;0O=70U6Q{1Bɫ6#l/)*շ׺sʵ _D%l {n6CO*<v:4xv7e`ӃuT8ruqGa$g*7{1(j-Yh"۵xj*?QH2(箹/wW_E d6S8-ӷg(eQ2D8Wq8E:a Mf1Y 3)j>'OrʚDWGP#/}5Z|''5_ja=YH7V]{mW,QGFzdj>A0e(Fut \%<#GơZH{:JkgN9P{jip> hW֧8b'\'D@ќ˿٢'] I1*J_;i#i M|ht$Q5%ejw>w&xB8ɼIIyxµ1wk^khMmfZ|C{_m'C-_+-ʛ⣷@> 3ZL9ǭxD|E>(jC$ Ta _{\3]F_UsIĥ-ݮ # R5X⒡CJLouʃORcnAYKK[|9J]d2 AKYgxy c|.0x_Ϸ}7Z7o ^jhX' Vd[D-[B&x}]w1тS뙘#mц S^]N~ҕOf~ <B`L~cM0S9O̘=} !%IJb_0w!df<;Rlڴy4әd B&\JPb1;, Rg^!X|J$狿,xo7ͭj/?q19O<Ymxs\㗿^v1l_loe[}{z[<frT! LUӖ< "(n^],+PX%;KIBκ{mj@BfCA: #UX?Wز $ghOO}<$GpӪVl]5-tn5X]LS|H=YޕO*WR$kw=%D|DFW͈/| 21s0j_u/Z H.nF7d+ץenN 3Tl Ƴ~ Xgf/w-ڨ;CIDӤF:\p5vLKyxR>uT=6@ y}sxE"FH; |, YۛO#hR健̸ibzD\8oS'5W&.OMҢ tM?+&>0N$/ys/ #alJXǤwub"rEaUÿ!\lojoe4¿*0hr~7fg[q9i\@RO6٢(~glk?r{V٦7ksmԜgOo|]k-oOsn^x~%}=q.} ϲS!4E,Hrͧ nG/,\#B_MC7u J}zᎧYihAqCҁDy ?ѻ;.Ҳ$M&A/i#elk,[]Q9yk'$Oؾy/nnL`:HRȑc7!I뿅Y= C6Ԃ^ _a&7[ŇNjßx{mģ9T e P>&\Y[V &f+xkv߮l-9>^G#k`W2 ^Hx'&Al)Pŵ; 5J?׌U,Y_8O ~nb ObW0O?\8ڧЎ;s{q 7Ϩ 扊OXIzjۈS~VPSErwRĄ53} \P|aü=߆e|ө`AS<ң+ G^a*G2C\c_nz |j"exAm9 )n)s]Eeg{tHKwL3ݰ@ iIG+y+/5MM Ӷ*JNf"lܢB}?sN))Ob_q| 'Ԁ8֢};:Y.!LQ=dx5 ޅw]!H7 w-O>8َW|f9O'xԳ ϟ~ V*M46 OZcld;up'>?>rLi E | 9 Gam;G4 ظoƞ;HNUI,OU9AJt ~Ub 4у#-*iGRSIRS;B{M.Ih?mlNT$'S "Co=Oފ_ NleЫsuB|ݻ? דl 4DЧ;5T '(kx6tiSDQ}Cxcy?QVXxES`P⟽?8vm1x3)<~ n}hxjM㖱\?v3^f }z2!ԦE̿ e9[>?L%ӵ@{o~o۰y\Rא 3ZP_a^Ҝ\p(njzowws<'.sxخ!~&ÆoYT')hir3.ߡwP'o #O} oGu:c]q CO$z`ޫ9}+6&Cl%0tܾqS/wwݍǞb9ʦ +O'bGB΄ѧ_@Im] D9O޶_ oŃW䩰dR4LksVb|*?_U<Q7yrbH^rMO>[ZHbs8$ZhuLZY ;E8Ͽ_|_;7'/lg¿/a"1Ä}f:{cӣkyI|/Sg' 4PKڒ'ӧtNEXC%AM 囱BZ-IҤ%;̶,?xϪHq?Ұ<OW'0qvk;`/$;[h6nS,MƞeSɮ]]'h|׎L}0; H9*ܡt8\w-FaIL R9l]`ۏP}SH$5/ow; _/N+iǑ7}/ 9FD`zygp7^v9xc_;Oo/܄z;~^O>OIx*3W4>N5W<e0I޿ 7>7B7E}mLON-xe끵7R=4ʇN{+މ{y]_ŠR^_zw5I-OER=AJ=t z[+n9wuE={DLx?[ ~}~>}+14koCx W3_>|'kPX=v\&%_}zc!~GȀ؟y|_mue+?S_G%gq,>v;)qEp_Vs=RZ<?w ^78 yOþ3 $5oWRgb#$쏤Y/v~lŽGZy1"8!N;)g r2`?R\2ӥlG 7%}nYh.aKrbwM]S0yw=z/?p#iP<'Os7c?.d<GbSx]} n+m3"hFkPo;#xX\˚ϼr'K^o|WKͧSzWop?OaOh6`էO3( a0^]~/߇[*|-x)\{jSnloOޏ7{wt/SÉAx5R1)a#ny'/dОB&nnQc_}nx}v|sfY Oqޛz]Ji_f <='?,/3owixsq=0P)(oO5ыVw3o86_9K'axC 5x3 OX/L,/*|i]82O_߽zP/gGk[I}ZJZ}u2Clk(m"4ӽņ<SeX3/z<}{vq0\rAIeg<]l~mڋbP[Вf0U&MSC%HgzW!P}ψOy*8(Ht (O<)A^o"| /x 'b+]S ?_w]}K|!~̊g,*רWxN?}C_{' EgpU뀩0'p{?1ֻ dpӥlAâY™6<(܋,^{+^ nyxv͏><0^^yWp=i7> ³ڗW\v8Q Ϩķ|!'ٍ\8?9o?O  {5n59(m5uOS;~.Z ֪9*B-O:oNFFc| q[:qG>9&kϟ%Fe}|!~gqSyކ4~M8{Η&9q#oXSOPޥb³<5Lg$^ſ=U5'mĹѺf>ɖJ5 gDl'\_q X}zT =4K ߵu O[7u'pi=9'ogo'pY~#x\ss=4mo T_R|ӝpI8/gUɛ3!x44x/]*Riw} ^{^ n:n58u=8={oĥSq7Dy2}FB^?43Ӄ \AuKդ]?wKnĝ' Ix r~r' ?} > yo.<C { -CmYci@|+IW_b|xt§oĻ>_Yi6;4z/_t'<}jcyӵ/÷ _s ^x;nƇO>s`x6{\pj_bpO“ό.@0zɼҧMo^a>I6'odRқkkqn=­y))œp<z,=+H&ޮ'}yxMx<< xZy< s#x<^M.&x :"Yr7nǫ5ۋ #߉O5(zs$A闏ŏ,7~4 )H?!)DQVٛ6n'd:$xY =؈<V3l/f۶˝&y\q%vgX7Zy[Y&y.0OGDx} U۟Ss:N}.J #욫[m≴, {y7KS<|M0TaBcYaW}N!,$O>]k&ySއ_z\3= %<}tyጧȨ!Ue4 ^ChK"e@&9ETyl%c̰@'=O 1uzдvg!œxqt)_}N؎&L>ß46 $OĿ\\'B O%su &!03MIZ< !ٝ^/5?Wgzd']Iܬ]]r>\PNNaa'F\-x <ϕ߮X.G9,GaS~'b TyTt^AyB[ўֿ _d['؃SO:OMNA3\rL: 4Kxbgǿ>< M/!w~8;yJ Ox$OSs2S/S~_8zџ^\6z穁H>zy qaщ1{B0Ob.̒F_ӭd[J51}f# ODʓ%J]範&<|x _Zt>V|;3wd4&kO)p򩭼8(^0_p8ܜ+ UaEg.Hy̎"eʳG|Lj?!:^IDyA,\ʎs#*OLHD,x"C3S>8\j>!G!= ) Oi><}& pjJxf'fx"קl)Ltɞ<PW9)eX٣=xr=8'>!=x<ЂAy1=}JB;sJvgG Oi"}iCn9>Oj'81 sʿJ}ca)0&FvBǓsHx"O45OhVy}TSC<< 4#k}fiOÉ)G'u|nl\j? FGIͶ1rؕp233<$kyz%/M;!YHϥ]}f-O.Lx*略4Yfӎ mry}z=+<7& Ss}\j OS2]vDgqGTD_˳}J^2lY]xZ>xT<(g m$aԐJ\ϜٞTP2IDwEisIeX:XDnBC2|1_"+~^Ċ"'D:3)L8>AҔ@!ɋ&FIK-*7l2SdJ:*=gͳC'-L0OcI<ݻG}alQZl4wz<h.Ͼr{>yLxvP$o$cgm<1Oz:::Uz~< ٗg1$oG>'Zk=DU|h_ub&_%ϘByJ1H-?&]T,)RQJ& Ϙx Z'rf|4ϗf)2x> 4=ugOpyz0Ǖ6)4pf#E$dzF`}S 0)Lg̚z1YӬxקy Z<+=~Ry= Ѕ|SKBs^_+xf'C\0I/ Ey gZ޿r}ɓ /ʳ}"'O^3!<`zxV宥Ȁ% <0spVS/Fy^}Zw܈w:|:]fŠF#j+@ciy.;\{_εv@5Z H]}6TyQJ%繃XxhtzQ>Orcp>ŕԎDYktU]`τQ=z.jA#OxL%AyڿQB|tA9_O5zh]X+svlk :bu"BSp⟚ױN ^ ;e<_Y /Î~UnBS |B\!ssgǿJ "T;d<ݑrQwg/CdPusjQ'z(NYWtwUx$qY6Z?I=SVT̥JLwg%OqL_>#W 3s3tlNd69<] 9<]|r<(xz!}$`\,Nۈ҃,s Ij6_uOmnȯJi4pt[&i&[" bX/״XFt%LcHS=/I{z삧Nb=ptyyS'-ϾK1(O]xM rG<rX)OXE7.+I ns0' oB.q"-y+PM3vS-Į Bh|+%>XkD j$ BHy<9A%Oyr=Fh+Yaу֏=Z/h$OO g_yk!!E5AKKKW&jd3\Hz8=|8QS{<3!$Z}onrܡ&zz_L!ן2<5A@nob lΓοz#O)yfBpLc< ˫}_pU!+)I$T%FR{|Ц!qASXX7N7H=sb=Y#eF:< *rO['u @NvĿ&yҔ9=Γsz Լb(g~6jM쿪<ߍg*˕ "I|9e"YJU,^\l~'6>:T?I'̍˅|: ph@N%`T r`<-M+R5ZeČdEb 41“C%)OX)eIԔ0}U ƓSó1 VRSr}O0s5S5bc<9H}:O :)%OyJɓo'2Hyz'Ճ a-|.O8 ݲ]oHL$I?QI+O 'xHS<~2[ ߫lz(؟T;5o'YͪjsZ%T]^ke5WR<;z t $-CK$뮨y^eO[ 4KR%*>IVJÜ<;/˓reAkݼ>FV-ޥ'|幜m&<+Ots)4AˣlB5O NR)kx-'ַuyJųo$ʓVڿB&x"A㉜'xjSJ=P 2Z9IIDBtua9?D.0]j]4H, $b ㉜"~'|N q4.OSNz+x:OكmxzS)glCkV6RHS _4׃ݥD1O_(gxFL/,e$xJSiLܿR= '<>aP|'y6B/YSZ<]l_` JFs~*plql+p -4PƟjj8=rEf'*\g*3D4 l'W.$4$TR`ܿ\v̕BȂ$G%zyb OW!x>3<]$Oak2`tY>7Ub -=%QdJ |LG<%,_;]{<{|Q[Gq;m#珬%xf}+l=x<.OQxR6=ZYdRtOzn0v))O0Fwc&Jfݸ:Kד6W9QqXw͊3VvD@wmXbLf8OR}W)SXȓ[,ɖx;M <S<'wI+><z؏ӧ{{S:Ó;Drnj=兵|Th+9l}y_ND9yb-iTc<x"OS}jQS><(=a9Hx % D%OO6Sxr=;/]T~<|VX=L?$ xjS uy_z[xfAGҔN[Knsmu ~>b>vb'oJxhgUv&b`8=).{Ęx8ZO/Y?3hF"B}zX3.;hHJ񌇽;X_cj<> Cz"zgݥvKQShktS 2aON(9ReMqySBK&۰iYW"h~͙:]lWm<ݏ/ >Ԯ<i37b!扐Tiۮ!K\bUy6*e"2bwx;(O;V-OY@I鯂<xYߚd5 LxBln(<3ō="5k7϶ vPl'IqoPr*,p] t[ȓkc¿/vm$Tyi/#`υ顗!yZ !!du(+vN.ʜ աT˛amn.|m$6P4UcޢŸ|ƌ.O .O$x,0OИ}x)&<-]Ov@LҜ;֧HroBدͦW儭gxbĿ~&wS<%,>XIa\(lqG~h ]l3$%I[@{Wj71m06,ܡ@Ã=\ԶZSNEyjSbV$HQHy"fWs-_5~|F!㩖}"m"ϸFO'8O0)m`S)'LقM!^uym&y$z<6N'Cs~|3qS^u+ KhCg|`a=)l PHyF=L4AUMw2&2mL`81'0]wk @")iCYkڄ"%=ثx.83;O-OiBQ6o?Ik޿O/GO 2S5ߥ?Tlk8Qmj? TS<rI8.O3b>Ux[ 8g<Ǔ롹 OW}S;z9bgk?:<~OTFy8 r_z?D/iVxsS~zQwKCeOo@)bYք|E3}ސh;Y匮8O<6NUj=l/$EgX*?9e +?ĠĪi<Fzzv^>4'ʮOE(gwG}ShoyEP&YlUd}aYasp~!?&~vMz\=1IDrp@_ۅgZ4qV7W縝*͑ KmU|DbFQ;_Wv;Mq2]FhI9rYc̿ۢ2]Kk OY}~-Syb-OMk5<֛Ge;}cƦxj3ѧ8z8pS_=i+}$Ix%Ow Hyz>Rӏ=8xJ O_!D-Oc?[ gnˌ>0='4}!Ggx`ziA\SO2̳ 3{`P'. U5nl98O S9Osd6㭝$IlyRmqOQk} {E<3=LɜNH੻Oxbg\$ lڿOMx6 [S Ob3磨I)`ǿD/(O_vaT# 6$;,xϫ{C6aKh>FtW]|\ f4kV3<p엜'./O5P \B%O !C z`<xJÓ7<<13'BV¢Sc{<<v2rkrkL X_<$ 'C>)O<%[.[SNOj%`*D4ULzNtKc%̿Jቌ'R"D[N 9ow%X&ؐqPUAmJ,a0{6,1U@li ڏ>Ox0O҂.:o)=YkgyJӯV Ly֮zpW$O_<# Cمh燎ݨZ3= \ sLaE#Z!ѽ&y5>ϡ/JHn֯:_?OuBc2FqY䗜HICx<hg!%ۉHL<ǦRGq'ݖ޵<'zOb2aL`4ų-xFfk#<+Y!9ajdۻO:w /+õFmJNm+)R,>90cG{-B;m?wg.iJ]ha<`nWz$wy;I@/ꡤ'’⒑C;-O <%鋆0,0͓N!x y0=`P0mSW=j>͵FȢ\Bv{0?^%<%\#}^r\͓ a/O3ڟSztML4TM3</F ɉk=}DYwy9Oy񗖌_C6$Ys,$_Dl_ha>.T&Z6M1lONGYaq/<;j\ $OL>n}Ӥx\x<+xƗw`׿Xwx.xudvCs'<VXORkDIR _aMHxٝ32c.Gc<-ngzX`>}#=x&?/nXOLT3fy" ؟89 "<-zIOWϱ:6.>Ov(z=Q%OmA:Zl^E7yj2C44Y7M'9<Vu R[xFr%Qxb<{ QS]W"m9M""|W1E,W!ڪ_^aͮB3ox Op;$`ቆ'fxR+"ix6KEnkϓf$&bb;OUmAϚ$+ɡz`<57]xb$ѰC#ᩋDSD'y!IN%kx61o_iyfzpd³CsYCX}< _ Ot\tǧihb2\#Om[\=vmM.'>l~=~7t 2SSz,Yx<wyڜ̿z3$t]eyA/)Kz&^[yO@_B O )OiHb-};<ǎF'u|}<ӻWgz${옌z{@5uO=c/'~ēIyOhs_f$csY3<հ<V^MBXj,jTJL7x'$I[1* )3L/"Sp` x/~/zXxc|= =Os,\.5QȘYgZ/<-43oVrtE OOC{R< Skb=71>ЧnϿ,/ dO.^} bO yzDZNP@hsjMbsFl<-xE)g<=j@G4ͪ_kGNB{Zgy= /'h΃y4*=}Oj@4ͭ*'zVWybs^kOaovn\K+Oh9,爻hbs[[=לo-EğqDpD^(t/&\oR;rn.syM~A?3B/R`?'׃}οҵO̦/as/<~Dey|FEI$/z;= yw o,BbS1҃%}*Mũ>\u_"74~_u6Y uF"0V"Ͽ+i6bwZUSYhC$?RtuK^X[Lxk:cMIyc{;4ϪʓoI =3}"}QQۗN[j2(O,Sy`zHw_حNwቯvhh8u;;|gb{7yk[<'ܿ0C E]G`MD\O0`m>xĿ;>N˯q`C?O2 O_'ك)O^6|.Γx)s}*+OhĿbˇeS<;=ǢO5~=<)?3Kſ,Lk5/q+ ?J O3Aڟ4o/4OlxQՃA)g\XByITqxM;i /BFZ=@o#O<C.'!=cg{dER+P&ɺ td] ^ԜRvHd_-\S*~*!GEq_F"9OVȂq˳]w,ҔLqBN'i }m](O+-g!ύfg +OKLqy8z-Utwmq3O<}O/Qa\d$:R{x}JH!OZE$oӰI8<=R>u^psHos_Ɗk4Lx6z=+ceKq<~-8gu TlX2?uk@_چ"+׶wiOnTYC}1"/I&։ޟ O1j^[=LzπgYFPZj1OjJ>=Z ypA\yi5v= /scoL8ԀsRDsȳK e ?h(pr}Ĕ_9֫(mҝ`t^%It7]o|-1S+_꣠=V$)Z *OXd} Oj}#7-OLgxgB*Sk\dg9r%`<Ox&}ZiZ*ͬ5,~฼Hֿ| +Rr@:=(B0RO<})i'(V`ӗOqD<-VN/3_(g%Wl*^|sgf2ӷۉ1f8ɂ\wOLFY2X~t1)4l.M5O/w^@I>SZӢ[me>U:~3v*уiҿly: C3_}A,#03FÔ><2O/ӌ5])Ϫ2D@yO\#=@(lg<< :&Ojyz@Ox:!e;2R8`m'Mxj}_yW!ZZgeNBQm'?xx'XT wUz )Oi>릂'>ϡxZH{s_+yp'p''g>.œV떓wy*&ۺϞ'Wo*Iy6#}~~v@w'lxijnw7z(NT53sWIǓ8hzjy3t?u%>OH j3 xr%J̩Tghi2+O,H]sx3c˛=OTϵ- Oq=h}.M4<Bióܶ]GGn oD@^<$9ˣ*\^|Ǔ\Fyysfs8#6AtOA$@kZire/EyzNҏ`ƿ O?iH"aXIgg)L$P03(-~j"xf=R lx+E>٭fg<˯'gUx'^@zFOL4DS퐧 }t2Rs +=Ot!E$mKXAgXA~R1cO9 N^RZx֟GS<=ךjxJ-OϞ'X6ʳ-krRmS-fZv[}bs]a<9E E:'y_~]hRRHx>zhyb3EWV#[}bS/v 3}Bz&ύTz3pBOxbq&A<><׏Wxn<CM+E4O&f|g-HiC(;.Ӊ&TB FnK/;bs N3ᙌe#į(OZ̿va<7 Wffz`}MAJNւv/M;RZifZhkcv(t֊>*_ WlM{F yZgk2>u(x^וkx"rFx.l<-hx@j ʓ\æ3y9O=Πx'Nxb d|24xو<8qRz,^ruV亯\wyjsAó0J,zx6hy.:>Vz;[*6k-_n8Q=]y<kt\Oq/bSt a1/q;ng@ٟity?Gh8|3a)C5U&' .u$])ɣmT˔ *2/ /E]`y@Pw OON7'׃yzwbVX并qWk+O_qMyޡ!,LWJI$O~2#uq%\^&(bąp}wܦKp83ryH/E7 6TGh`bD*<;=D{ǭzFƊOpSڿ{~?g(Z}g- :y ܯ\"3%ω;/y=x`tg2 }6CR Ig}s.xDLy4^ѽ߄#{,fYՂ[cW?pR'e,gϽQGzrN2wOy{cZwTǹ>z}%jiWyR=Tz`$Ze7|KgtXxL1XӁz~1,Y+`)Kʐ4o3KV)J+ٯxz<->˜t0sCyzGyuN _&0韚j'O{)P韠:&9Q-O+g;}\7434O/A_xpau<=+<4p)Ot/phB/+ǬZSLW`-r Oqz&ڟ" Oic=b<= څ.yJ<=|$M/zy&[ DSˈe0> W]sĀɖdקz~"gXY,3dmH z(v3_3!wt/g^ʍOh^f<ÓuO/隧c=;}9Z ,<gi7.xؿ=Jrv|!OWoxڄQ\y5d'ÉKW}zyg j}= EG>tREB.CղKTtlL/̿,nw_iG@y @Ϧ=O/<ң`O_a}v j:f۵p^<%D 7_OZ+&<-;zKW@myf=,?x:?NovzLIʽ R11.U6|=k1䫂E*sv#M.hYzZxS0+ V bÀSӍ8zk d>YāČ'4O;Jؒe) -O<=VEz<1Ocr)9s'o'ʶVDlW -a Ϛva s?7rQO&?<7/CꁭB#O.(gx+xZ乞$ )w<'LtVSfm\uOILq> ;}:[};'igN9O O  Okē$B.Fx8'^gZy`v|Нa/lӽݮk?٧ Iyڜ'!/(R3ɰYB?yZiSOWN荠z^44PDoײU7}pvΫ>{|yh.,Mg+U&}c?i<ቅ'oxNyڌsrڪӿƳ4wy^zvYw DigCC P><OC(]ϸU<-Ay/c_%x9Tqzs]y]aȓ"ϼ,v^C;>yg[T\K (OZ';< C} _tzgIhv4[Gͺgz w(X̭>{CKG.@94陫1vG_8; [|,YS0Ÿ%=rР{;<!"H𴎧yNx{ XiYZZ`zz`<=a'<llo=~SW5\KY<|`Mؓs`C0k^XX`b=d Ys'gVlݟ/pvgAofvB. Q\44} ڭUóN^ڒx&Sm ]J_'m{-P)>|C}&/Z&nz_T !O>S>AFqٿԿZ{ZgFDm@d>x"иl6AK=2s!?_w8ZxP9Tύ>V3zڽ#ϺzO Ȗx#35whxb̓L!_XF{eS})/rh'3{iXgKU$f||<7cW$s->L)Oy)pS|b-CnkuOxnt'}`=?Hx%Mw pWxU'aSSگLx'cETvކ.'r2<gp1]듮jzH ;Hg2 :~<'l?D=O:ޮzA1O]Wic5-Ϻ@IK%g|z쁍4]O.-\aՖ jY#o H8ߐeecK$I'?!d=Ix:xz鰕KJ[~[aGDӐ[Sf?{}๶zV-OP u!<yF.zD<rϘ3;t+ϼy/sӝJY`yz?Wӄ><{=<=YYk k$-ן:>Axڟ]?'OKz~~+p5ϭxz?ϸ8 aGSAD'YG<n*ˑ=Y*̙xZbejWS}vkP36]OSu. i#~ OWPa>K蓂4DM.u 'md&BUgLJ81r);vw2"\[\wG jد|Zc^V O/l7W=Oc{>+s%O;lybO< xbӋ>1KʡK)ܜ]4VWNxgy\sϤOXn<@vj?뭻 <x,ak݋<%=i1@koXbj-ㆆ'CoAZ@N5G&zig|rFNKO~rIdz [q,VEZ0(e#=6 )Zp+-V-y:剖'Jt}T5̇i,'O0ndJ_ZS=<'y?BﶬO I\ sC({f 's݂V˿Ӻ阣ig拢OW;)Y넧 yNs }Zh6Z^SM0װn81Ҧ0ӧ }=/[yl&Ohv“W`ahg'WAe,FAIy F h=9]y&J]!öys&09r6x58"Z^9Oc<;i O[<7z`է%3^|c)'&w<LW(Ϩφ'`̈́M3G{vn^xH^I`'?^剆If=(ܲ[`r7G]rCLm@6X g)D}W gL^Y'=w1i Se9Ghb*䡴cݭVࠅ ?{2^rcMxf=< z5CzhAH}S!ϩ3*ϴ}HE-6ANq?3x+'`j0$AQ)9@㙂'+=X ,x7h#|\eX&Zj ,"Ax%E<}Ɠ|YybSe%>"eLUP_ Ӈ<|Ag y8<<_>֧x&=jOn~\5I'gt6+O\_1u|= =O KM' 㐧eyt@*"i5yB6Xϰsk\QI.}gVPL̚"R•ǻĥ1Ů+Oih4Oy}h7sgzp#N z`꡻T-OМiTz>O= zu#=3z'.: [۫ҿ4t5OmB:j6mOޤ4.kDNUh3N $wK]s۶xSL\5a/@xֹ< ϩK|}ݿ$,~i4 x<>ԦFLbf=a'w<;=0@7xא퓺<7<Q5}!]`Dependencies $(CXX) -MM $(CXXFLAGS) $(OBJS:.o=.cxx) >>Dependencies # # htmldoc # htmldoc$(EXEEXT): $(HTMLDOCOBJS) $(COMMONOBJS) ../Makedefs echo Linking $@... $(CXX) $(LDFLAGS) -o htmldoc$(EXEEXT) $(HTMLDOCOBJS) $(COMMONOBJS) $(LIBS) if test `uname` = Darwin; then \ $(MAKE) -$(MAKEFLAGS) htmldoc.app || exit 1; \ fi htmldoc.app: htmldoc echo Creating application bundle... $(RM) -r htmldoc.app $(MKDIR) htmldoc.app $(MKDIR) htmldoc.app/Contents $(CP) ../desktop/htmldoc.plist htmldoc.app/Contents/Info.plist $(MKDIR) htmldoc.app/Contents/MacOS $(CP) htmldoc htmldoc.app/Contents/MacOS $(MKDIR) htmldoc.app/Contents/Resources $(CP) ../desktop/htmldoc.icns htmldoc.app/Contents/Resources $(CP) ../doc/help.html htmldoc.app/Contents/Resources $(MKDIR) htmldoc.app/Contents/Resources/data $(CP) ../data/cp-* htmldoc.app/Contents/Resources/data $(CP) ../data/iso-* htmldoc.app/Contents/Resources/data $(CP) ../data/koi8-r htmldoc.app/Contents/Resources/data $(CP) ../data/prolog.ps htmldoc.app/Contents/Resources/data $(CP) ../data/psglyphs htmldoc.app/Contents/Resources/data $(MKDIR) htmldoc.app/Contents/Resources/fonts $(CP) ../fonts/*.afm htmldoc.app/Contents/Resources/fonts $(CP) ../fonts/*.pfa htmldoc.app/Contents/Resources/fonts # # testhtml # testhtml$(EXEEXT): $(TESTOBJS) $(COMMONOBJS) echo Linking $@... $(CXX) $(LDFLAGS) -o testhtml$(EXEEXT) $(TESTOBJS) $(COMMONOBJS) $(LIBS) # # Dependencies... # $(OBJS): ../Makedefs tls.o: tls-darwin.c tls-gnutls.c tls-sspi.c include Dependencies htmldoc-1.9.7/htmldoc/array-private.h000066400000000000000000000013501354715574200175670ustar00rootroot00000000000000/* * Private array definitions for CUPS. * * Copyright 2011-2012 by Apple Inc. * * This program is free software. Distribution and use rights are outlined in * the file "COPYING". */ #ifndef _CUPS_ARRAY_PRIVATE_H_ # define _CUPS_ARRAY_PRIVATE_H_ /* * Include necessary headers... */ # include "array.h" /* * C++ magic... */ # ifdef __cplusplus extern "C" { # endif /* __cplusplus */ /* * Functions... */ extern int _cupsArrayAddStrings(cups_array_t *a, const char *s, char delim) _CUPS_API_1_5; extern cups_array_t *_cupsArrayNewStrings(const char *s, char delim) _CUPS_API_1_5; # ifdef __cplusplus } # endif /* __cplusplus */ #endif /* !_CUPS_ARRAY_PRIVATE_H_ */ htmldoc-1.9.7/htmldoc/array.c000066400000000000000000000664761354715574200161360ustar00rootroot00000000000000/* * Sorted array routines for HTMLDOC. * * Copyright 2016 by Michael R Sweet. * Copyright 2007-2014 by Apple Inc. * Copyright 1997-2007 by Easy Software Products. * * This program is free software. Distribution and use rights are outlined in * the file "COPYING". */ /* * Include necessary headers... */ #include "hdstring.h" #include "array-private.h" #ifndef DEBUG_printf # define DEBUG_printf(x) # define DEBUG_puts(x) #endif /* !DEBUG_printf */ /* * Limits... */ #define _CUPS_MAXSAVE 32 /**** Maximum number of saves ****/ /* * Types and structures... */ struct _cups_array_s /**** CUPS array structure ****/ { /* * The current implementation uses an insertion sort into an array of * sorted pointers. We leave the array type private/opaque so that we * can change the underlying implementation without affecting the users * of this API. */ int num_elements, /* Number of array elements */ alloc_elements, /* Allocated array elements */ current, /* Current element */ insert, /* Last inserted element */ unique, /* Are all elements unique? */ num_saved, /* Number of saved elements */ saved[_CUPS_MAXSAVE]; /* Saved elements */ void **elements; /* Array elements */ cups_array_func_t compare; /* Element comparison function */ void *data; /* User data passed to compare */ cups_ahash_func_t hashfunc; /* Hash function */ int hashsize, /* Size of hash */ *hash; /* Hash array */ cups_acopy_func_t copyfunc; /* Copy function */ cups_afree_func_t freefunc; /* Free function */ }; /* * Local functions... */ static int cups_array_add(cups_array_t *a, void *e, int insert); static int cups_array_find(cups_array_t *a, void *e, int prev, int *rdiff); /* * 'cupsArrayAdd()' - Add an element to the array. * * When adding an element to a sorted array, non-unique elements are * appended at the end of the run of identical elements. For unsorted arrays, * the element is appended to the end of the array. * * @since CUPS 1.2/macOS 10.5@ */ int /* O - 1 on success, 0 on failure */ cupsArrayAdd(cups_array_t *a, /* I - Array */ void *e) /* I - Element */ { DEBUG_printf(("2cupsArrayAdd(a=%p, e=%p)", a, e)); /* * Range check input... */ if (!a || !e) { DEBUG_puts("3cupsArrayAdd: returning 0"); return (0); } /* * Append the element... */ return (cups_array_add(a, e, 0)); } /* * '_cupsArrayAddStrings()' - Add zero or more delimited strings to an array. * * Note: The array MUST be created using the @link _cupsArrayNewStrings@ * function. Duplicate strings are NOT added. If the string pointer "s" is NULL * or the empty string, no strings are added to the array. */ int /* O - 1 on success, 0 on failure */ _cupsArrayAddStrings(cups_array_t *a, /* I - Array */ const char *s, /* I - Delimited strings or NULL */ char delim)/* I - Delimiter character */ { char *buffer, /* Copy of string */ *start, /* Start of string */ *end; /* End of string */ int status = 1; /* Status of add */ DEBUG_printf(("_cupsArrayAddStrings(a=%p, s=\"%s\", delim='%c')", a, s, delim)); if (!a || !s || !*s) { DEBUG_puts("1_cupsArrayAddStrings: Returning 0"); return (0); } if (delim == ' ') { /* * Skip leading whitespace... */ DEBUG_puts("1_cupsArrayAddStrings: Skipping leading whitespace."); while (*s && isspace(*s & 255)) s ++; DEBUG_printf(("1_cupsArrayAddStrings: Remaining string \"%s\".", s)); } if (!strchr(s, delim) && (delim != ' ' || (!strchr(s, '\t') && !strchr(s, '\n')))) { /* * String doesn't contain a delimiter, so add it as a single value... */ DEBUG_puts("1_cupsArrayAddStrings: No delimiter seen, adding a single " "value."); if (!cupsArrayFind(a, (void *)s)) status = cupsArrayAdd(a, (void *)s); } else if ((buffer = strdup(s)) == NULL) { DEBUG_puts("1_cupsArrayAddStrings: Unable to duplicate string."); status = 0; } else { for (start = end = buffer; *end; start = end) { /* * Find the end of the current delimited string and see if we need to add * it... */ if (delim == ' ') { while (*end && !isspace(*end & 255)) end ++; while (*end && isspace(*end & 255)) *end++ = '\0'; } else if ((end = strchr(start, delim)) != NULL) *end++ = '\0'; else end = start + strlen(start); DEBUG_printf(("1_cupsArrayAddStrings: Adding \"%s\", end=\"%s\"", start, end)); if (!cupsArrayFind(a, start)) status &= cupsArrayAdd(a, start); } free(buffer); } DEBUG_printf(("1_cupsArrayAddStrings: Returning %d.", status)); return (status); } /* * 'cupsArrayClear()' - Clear the array. * * This function is equivalent to removing all elements in the array. * The caller is responsible for freeing the memory used by the * elements themselves. * * @since CUPS 1.2/macOS 10.5@ */ void cupsArrayClear(cups_array_t *a) /* I - Array */ { /* * Range check input... */ if (!a) return; /* * Free the existing elements as needed.. */ if (a->freefunc) { int i; /* Looping var */ void **e; /* Current element */ for (i = a->num_elements, e = a->elements; i > 0; i --, e ++) (a->freefunc)(*e, a->data); } /* * Set the number of elements to 0; we don't actually free the memory * here - that is done in cupsArrayDelete()... */ a->num_elements = 0; a->current = -1; a->insert = -1; a->unique = 1; a->num_saved = 0; } /* * 'cupsArrayCount()' - Get the number of elements in the array. * * @since CUPS 1.2/macOS 10.5@ */ int /* O - Number of elements */ cupsArrayCount(cups_array_t *a) /* I - Array */ { /* * Range check input... */ if (!a) return (0); /* * Return the number of elements... */ return (a->num_elements); } /* * 'cupsArrayCurrent()' - Return the current element in the array. * * The current element is undefined until you call @link cupsArrayFind@, * @link cupsArrayFirst@, or @link cupsArrayIndex@, or @link cupsArrayLast@. * * @since CUPS 1.2/macOS 10.5@ */ void * /* O - Element */ cupsArrayCurrent(cups_array_t *a) /* I - Array */ { /* * Range check input... */ if (!a) return (NULL); /* * Return the current element... */ if (a->current >= 0 && a->current < a->num_elements) return (a->elements[a->current]); else return (NULL); } /* * 'cupsArrayDelete()' - Free all memory used by the array. * * The caller is responsible for freeing the memory used by the * elements themselves. * * @since CUPS 1.2/macOS 10.5@ */ void cupsArrayDelete(cups_array_t *a) /* I - Array */ { /* * Range check input... */ if (!a) return; /* * Free the elements if we have a free function (otherwise the caller is * responsible for doing the dirty work...) */ if (a->freefunc) { int i; /* Looping var */ void **e; /* Current element */ for (i = a->num_elements, e = a->elements; i > 0; i --, e ++) (a->freefunc)(*e, a->data); } /* * Free the array of element pointers... */ if (a->alloc_elements) free(a->elements); if (a->hashsize) free(a->hash); free(a); } /* * 'cupsArrayDup()' - Duplicate the array. * * @since CUPS 1.2/macOS 10.5@ */ cups_array_t * /* O - Duplicate array */ cupsArrayDup(cups_array_t *a) /* I - Array */ { cups_array_t *da; /* Duplicate array */ /* * Range check input... */ if (!a) return (NULL); /* * Allocate memory for the array... */ da = calloc(1, sizeof(cups_array_t)); if (!da) return (NULL); da->compare = a->compare; da->data = a->data; da->current = a->current; da->insert = a->insert; da->unique = a->unique; da->num_saved = a->num_saved; memcpy(da->saved, a->saved, sizeof(a->saved)); if (a->num_elements) { /* * Allocate memory for the elements... */ da->elements = malloc((size_t)a->num_elements * sizeof(void *)); if (!da->elements) { free(da); return (NULL); } /* * Copy the element pointers... */ if (a->copyfunc) { /* * Use the copy function to make a copy of each element... */ int i; /* Looping var */ for (i = 0; i < a->num_elements; i ++) da->elements[i] = (a->copyfunc)(a->elements[i], a->data); } else { /* * Just copy raw pointers... */ memcpy(da->elements, a->elements, (size_t)a->num_elements * sizeof(void *)); } da->num_elements = a->num_elements; da->alloc_elements = a->num_elements; } /* * Return the new array... */ return (da); } /* * 'cupsArrayFind()' - Find an element in the array. * * @since CUPS 1.2/macOS 10.5@ */ void * /* O - Element found or @code NULL@ */ cupsArrayFind(cups_array_t *a, /* I - Array */ void *e) /* I - Element */ { int current, /* Current element */ diff, /* Difference */ hash; /* Hash index */ /* * Range check input... */ if (!a || !e) return (NULL); /* * See if we have any elements... */ if (!a->num_elements) return (NULL); /* * Yes, look for a match... */ if (a->hash) { hash = (*(a->hashfunc))(e, a->data); if (hash < 0 || hash >= a->hashsize) { current = a->current; hash = -1; } else { current = a->hash[hash]; if (current < 0 || current >= a->num_elements) current = a->current; } } else { current = a->current; hash = -1; } current = cups_array_find(a, e, current, &diff); if (!diff) { /* * Found a match! If the array does not contain unique values, find * the first element that is the same... */ if (!a->unique && a->compare) { /* * The array is not unique, find the first match... */ while (current > 0 && !(*(a->compare))(e, a->elements[current - 1], a->data)) current --; } a->current = current; if (hash >= 0) a->hash[hash] = current; return (a->elements[current]); } else { /* * No match... */ a->current = -1; return (NULL); } } /* * 'cupsArrayFirst()' - Get the first element in the array. * * @since CUPS 1.2/macOS 10.5@ */ void * /* O - First element or @code NULL@ if the array is empty */ cupsArrayFirst(cups_array_t *a) /* I - Array */ { /* * Range check input... */ if (!a) return (NULL); /* * Return the first element... */ a->current = 0; return (cupsArrayCurrent(a)); } /* * 'cupsArrayGetIndex()' - Get the index of the current element. * * The current element is undefined until you call @link cupsArrayFind@, * @link cupsArrayFirst@, or @link cupsArrayIndex@, or @link cupsArrayLast@. * * @since CUPS 1.3/macOS 10.5@ */ int /* O - Index of the current element, starting at 0 */ cupsArrayGetIndex(cups_array_t *a) /* I - Array */ { if (!a) return (-1); else return (a->current); } /* * 'cupsArrayGetInsert()' - Get the index of the last inserted element. * * @since CUPS 1.3/macOS 10.5@ */ int /* O - Index of the last inserted element, starting at 0 */ cupsArrayGetInsert(cups_array_t *a) /* I - Array */ { if (!a) return (-1); else return (a->insert); } /* * 'cupsArrayIndex()' - Get the N-th element in the array. * * @since CUPS 1.2/macOS 10.5@ */ void * /* O - N-th element or @code NULL@ */ cupsArrayIndex(cups_array_t *a, /* I - Array */ int n) /* I - Index into array, starting at 0 */ { if (!a) return (NULL); a->current = n; return (cupsArrayCurrent(a)); } /* * 'cupsArrayInsert()' - Insert an element in the array. * * When inserting an element in a sorted array, non-unique elements are * inserted at the beginning of the run of identical elements. For unsorted * arrays, the element is inserted at the beginning of the array. * * @since CUPS 1.2/macOS 10.5@ */ int /* O - 0 on failure, 1 on success */ cupsArrayInsert(cups_array_t *a, /* I - Array */ void *e) /* I - Element */ { DEBUG_printf(("2cupsArrayInsert(a=%p, e=%p)", a, e)); /* * Range check input... */ if (!a || !e) { DEBUG_puts("3cupsArrayInsert: returning 0"); return (0); } /* * Insert the element... */ return (cups_array_add(a, e, 1)); } /* * 'cupsArrayLast()' - Get the last element in the array. * * @since CUPS 1.2/macOS 10.5@ */ void * /* O - Last element or @code NULL@ if the array is empty */ cupsArrayLast(cups_array_t *a) /* I - Array */ { /* * Range check input... */ if (!a) return (NULL); /* * Return the last element... */ a->current = a->num_elements - 1; return (cupsArrayCurrent(a)); } /* * 'cupsArrayNew()' - Create a new array. * * The comparison function ("f") is used to create a sorted array. The function * receives pointers to two elements and the user data pointer ("d") - the user * data pointer argument can safely be omitted when not required so functions * like @code strcmp@ can be used for sorted string arrays. * * @since CUPS 1.2/macOS 10.5@ */ cups_array_t * /* O - Array */ cupsArrayNew(cups_array_func_t f, /* I - Comparison function or @code NULL@ for an unsorted array */ void *d) /* I - User data pointer or @code NULL@ */ { return (cupsArrayNew3(f, d, 0, 0, 0, 0)); } /* * 'cupsArrayNew2()' - Create a new array with hash. * * The comparison function ("f") is used to create a sorted array. The function * receives pointers to two elements and the user data pointer ("d") - the user * data pointer argument can safely be omitted when not required so functions * like @code strcmp@ can be used for sorted string arrays. * * The hash function ("h") is used to implement cached lookups with the * specified hash size ("hsize"). * * @since CUPS 1.3/macOS 10.5@ */ cups_array_t * /* O - Array */ cupsArrayNew2(cups_array_func_t f, /* I - Comparison function or @code NULL@ for an unsorted array */ void *d, /* I - User data or @code NULL@ */ cups_ahash_func_t h, /* I - Hash function or @code NULL@ for unhashed lookups */ int hsize) /* I - Hash size (>= 0) */ { return (cupsArrayNew3(f, d, h, hsize, 0, 0)); } /* * 'cupsArrayNew3()' - Create a new array with hash and/or free function. * * The comparison function ("f") is used to create a sorted array. The function * receives pointers to two elements and the user data pointer ("d") - the user * data pointer argument can safely be omitted when not required so functions * like @code strcmp@ can be used for sorted string arrays. * * The hash function ("h") is used to implement cached lookups with the * specified hash size ("hsize"). * * The copy function ("cf") is used to automatically copy/retain elements when * added or the array is copied. * * The free function ("cf") is used to automatically free/release elements when * removed or the array is deleted. * * @since CUPS 1.5/macOS 10.7@ */ cups_array_t * /* O - Array */ cupsArrayNew3(cups_array_func_t f, /* I - Comparison function or @code NULL@ for an unsorted array */ void *d, /* I - User data or @code NULL@ */ cups_ahash_func_t h, /* I - Hash function or @code NULL@ for unhashed lookups */ int hsize, /* I - Hash size (>= 0) */ cups_acopy_func_t cf, /* I - Copy function */ cups_afree_func_t ff) /* I - Free function */ { cups_array_t *a; /* Array */ /* * Allocate memory for the array... */ a = calloc(1, sizeof(cups_array_t)); if (!a) return (NULL); a->compare = f; a->data = d; a->current = -1; a->insert = -1; a->num_saved = 0; a->unique = 1; if (hsize > 0 && h) { a->hashfunc = h; a->hashsize = hsize; a->hash = malloc((size_t)hsize * sizeof(int)); if (!a->hash) { free(a); return (NULL); } memset(a->hash, -1, (size_t)hsize * sizeof(int)); } a->copyfunc = cf; a->freefunc = ff; return (a); } /* * '_cupsArrayNewStrings()' - Create a new array of comma-delimited strings. * * Note: The array automatically manages copies of the strings passed. If the * string pointer "s" is NULL or the empty string, no strings are added to the * newly created array. */ cups_array_t * /* O - Array */ _cupsArrayNewStrings(const char *s, /* I - Delimited strings or NULL */ char delim) /* I - Delimiter character */ { cups_array_t *a; /* Array */ if ((a = cupsArrayNew3((cups_array_func_t)strcmp, NULL, NULL, 0, (cups_acopy_func_t)strdup, (cups_afree_func_t)free)) != NULL) _cupsArrayAddStrings(a, s, delim); return (a); } /* * 'cupsArrayNext()' - Get the next element in the array. * * This function is equivalent to "cupsArrayIndex(a, cupsArrayGetIndex(a) + 1)". * * The next element is undefined until you call @link cupsArrayFind@, * @link cupsArrayFirst@, or @link cupsArrayIndex@, or @link cupsArrayLast@ * to set the current element. * * @since CUPS 1.2/macOS 10.5@ */ void * /* O - Next element or @code NULL@ */ cupsArrayNext(cups_array_t *a) /* I - Array */ { /* * Range check input... */ if (!a) return (NULL); /* * Return the next element... */ if (a->current < a->num_elements) a->current ++; return (cupsArrayCurrent(a)); } /* * 'cupsArrayPrev()' - Get the previous element in the array. * * This function is equivalent to "cupsArrayIndex(a, cupsArrayGetIndex(a) - 1)". * * The previous element is undefined until you call @link cupsArrayFind@, * @link cupsArrayFirst@, or @link cupsArrayIndex@, or @link cupsArrayLast@ * to set the current element. * * @since CUPS 1.2/macOS 10.5@ */ void * /* O - Previous element or @code NULL@ */ cupsArrayPrev(cups_array_t *a) /* I - Array */ { /* * Range check input... */ if (!a) return (NULL); /* * Return the previous element... */ if (a->current >= 0) a->current --; return (cupsArrayCurrent(a)); } /* * 'cupsArrayRemove()' - Remove an element from the array. * * If more than one element matches "e", only the first matching element is * removed. * * The caller is responsible for freeing the memory used by the * removed element. * * @since CUPS 1.2/macOS 10.5@ */ int /* O - 1 on success, 0 on failure */ cupsArrayRemove(cups_array_t *a, /* I - Array */ void *e) /* I - Element */ { ssize_t i, /* Looping var */ current; /* Current element */ int diff; /* Difference */ /* * Range check input... */ if (!a || !e) return (0); /* * See if the element is in the array... */ if (!a->num_elements) return (0); current = cups_array_find(a, e, a->current, &diff); if (diff) return (0); /* * Yes, now remove it... */ a->num_elements --; if (a->freefunc) (a->freefunc)(a->elements[current], a->data); if (current < a->num_elements) memmove(a->elements + current, a->elements + current + 1, (size_t)(a->num_elements - current) * sizeof(void *)); if (current <= a->current) a->current --; if (current < a->insert) a->insert --; else if (current == a->insert) a->insert = -1; for (i = 0; i < a->num_saved; i ++) if (current <= a->saved[i]) a->saved[i] --; if (a->num_elements <= 1) a->unique = 1; return (1); } /* * 'cupsArrayRestore()' - Reset the current element to the last @link cupsArraySave@. * * @since CUPS 1.2/macOS 10.5@ */ void * /* O - New current element */ cupsArrayRestore(cups_array_t *a) /* I - Array */ { if (!a) return (NULL); if (a->num_saved <= 0) return (NULL); a->num_saved --; a->current = a->saved[a->num_saved]; if (a->current >= 0 && a->current < a->num_elements) return (a->elements[a->current]); else return (NULL); } /* * 'cupsArraySave()' - Mark the current element for a later @link cupsArrayRestore@. * * The current element is undefined until you call @link cupsArrayFind@, * @link cupsArrayFirst@, or @link cupsArrayIndex@, or @link cupsArrayLast@ * to set the current element. * * The save/restore stack is guaranteed to be at least 32 elements deep. * * @since CUPS 1.2/macOS 10.5@ */ int /* O - 1 on success, 0 on failure */ cupsArraySave(cups_array_t *a) /* I - Array */ { if (!a) return (0); if (a->num_saved >= _CUPS_MAXSAVE) return (0); a->saved[a->num_saved] = a->current; a->num_saved ++; return (1); } /* * 'cupsArrayUserData()' - Return the user data for an array. * * @since CUPS 1.2/macOS 10.5@ */ void * /* O - User data */ cupsArrayUserData(cups_array_t *a) /* I - Array */ { if (a) return (a->data); else return (NULL); } /* * 'cups_array_add()' - Insert or append an element to the array. * * @since CUPS 1.2/macOS 10.5@ */ static int /* O - 1 on success, 0 on failure */ cups_array_add(cups_array_t *a, /* I - Array */ void *e, /* I - Element to add */ int insert) /* I - 1 = insert, 0 = append */ { int i, /* Looping var */ current; /* Current element */ int diff; /* Comparison with current element */ DEBUG_printf(("7cups_array_add(a=%p, e=%p, insert=%d)", a, e, insert)); /* * Verify we have room for the new element... */ if (a->num_elements >= a->alloc_elements) { /* * Allocate additional elements; start with 16 elements, then * double the size until 1024 elements, then add 1024 elements * thereafter... */ void **temp; /* New array elements */ int count; /* New allocation count */ if (a->alloc_elements == 0) { count = 16; temp = malloc((size_t)count * sizeof(void *)); } else { if (a->alloc_elements < 1024) count = a->alloc_elements * 2; else count = a->alloc_elements + 1024; temp = realloc(a->elements, (size_t)count * sizeof(void *)); } DEBUG_printf(("9cups_array_add: count=" HTMLDOC_LLFMT, HTMLDOC_LLCAST count)); if (!temp) { DEBUG_puts("9cups_array_add: allocation failed, returning 0"); return (0); } a->alloc_elements = count; a->elements = temp; } /* * Find the insertion point for the new element; if there is no * compare function or elements, just add it to the beginning or end... */ if (!a->num_elements || !a->compare) { /* * No elements or comparison function, insert/append as needed... */ if (insert) current = 0; /* Insert at beginning */ else current = a->num_elements; /* Append to the end */ } else { /* * Do a binary search for the insertion point... */ current = cups_array_find(a, e, a->insert, &diff); if (diff > 0) { /* * Insert after the current element... */ current ++; } else if (!diff) { /* * Compared equal, make sure we add to the begining or end of * the current run of equal elements... */ a->unique = 0; if (insert) { /* * Insert at beginning of run... */ while (current > 0 && !(*(a->compare))(e, a->elements[current - 1], a->data)) current --; } else { /* * Append at end of run... */ do { current ++; } while (current < a->num_elements && !(*(a->compare))(e, a->elements[current], a->data)); } } } /* * Insert or append the element... */ if (current < a->num_elements) { /* * Shift other elements to the right... */ memmove(a->elements + current + 1, a->elements + current, (size_t)(a->num_elements - current) * sizeof(void *)); if (a->current >= current) a->current ++; for (i = 0; i < a->num_saved; i ++) if (a->saved[i] >= current) a->saved[i] ++; DEBUG_printf(("9cups_array_add: insert element at index " HTMLDOC_LLFMT, HTMLDOC_LLCAST current)); } #ifdef DEBUG else DEBUG_printf(("9cups_array_add: append element at " HTMLDOC_LLFMT, HTMLDOC_LLCAST current)); #endif /* DEBUG */ if (a->copyfunc) { if ((a->elements[current] = (a->copyfunc)(e, a->data)) == NULL) { DEBUG_puts("8cups_array_add: Copy function returned NULL, returning 0"); return (0); } } else a->elements[current] = e; a->num_elements ++; a->insert = current; #ifdef DEBUG for (current = 0; current < a->num_elements; current ++) DEBUG_printf(("9cups_array_add: a->elements[" HTMLDOC_LLFMT "]=%p", HTMLDOC_LLCAST current, a->elements[current])); #endif /* DEBUG */ DEBUG_puts("9cups_array_add: returning 1"); return (1); } /* * 'cups_array_find()' - Find an element in the array. */ static int /* O - Index of match */ cups_array_find(cups_array_t *a, /* I - Array */ void *e, /* I - Element */ int prev, /* I - Previous index */ int *rdiff) /* O - Difference of match */ { int left, /* Left side of search */ right, /* Right side of search */ current, /* Current element */ diff; /* Comparison with current element */ DEBUG_printf(("7cups_array_find(a=%p, e=%p, prev=%d, rdiff=%p)", a, e, prev, rdiff)); if (a->compare) { /* * Do a binary search for the element... */ DEBUG_puts("9cups_array_find: binary search"); if (prev >= 0 && prev < a->num_elements) { /* * Start search on either side of previous... */ if ((diff = (*(a->compare))(e, a->elements[prev], a->data)) == 0 || (diff < 0 && prev == 0) || (diff > 0 && prev == (a->num_elements - 1))) { /* * Exact or edge match, return it! */ DEBUG_printf(("9cups_array_find: Returning %d, diff=%d", prev, diff)); *rdiff = diff; return (prev); } else if (diff < 0) { /* * Start with previous on right side... */ left = 0; right = prev; } else { /* * Start wih previous on left side... */ left = prev; right = a->num_elements - 1; } } else { /* * Start search in the middle... */ left = 0; right = a->num_elements - 1; } do { current = (left + right) / 2; diff = (*(a->compare))(e, a->elements[current], a->data); DEBUG_printf(("9cups_array_find: left=%d, right=%d, current=%d, diff=%d", left, right, current, diff)); if (diff == 0) break; else if (diff < 0) right = current; else left = current; } while ((right - left) > 1); if (diff != 0) { /* * Check the last 1 or 2 elements... */ if ((diff = (*(a->compare))(e, a->elements[left], a->data)) <= 0) current = left; else { diff = (*(a->compare))(e, a->elements[right], a->data); current = right; } } } else { /* * Do a linear pointer search... */ DEBUG_puts("9cups_array_find: linear search"); diff = 1; for (current = 0; current < a->num_elements; current ++) if (a->elements[current] == e) { diff = 0; break; } } /* * Return the closest element and the difference... */ DEBUG_printf(("8cups_array_find: Returning %d, diff=%d", current, diff)); *rdiff = diff; return (current); } htmldoc-1.9.7/htmldoc/array.h000066400000000000000000000060161354715574200161230ustar00rootroot00000000000000/* * Sorted array definitions for CUPS. * * Copyright 2016 Michael R Sweet * Copyright 2007-2010 by Apple Inc. * Copyright 1997-2007 by Easy Software Products. * * This program is free software. Distribution and use rights are outlined in * the file "COPYING". */ #ifndef _CUPS_ARRAY_H_ # define _CUPS_ARRAY_H_ /* * Include necessary headers... */ # define _CUPS_DEPRECATED # define _CUPS_DEPRECATED_MSG(x) # define _CUPS_DEPRECATED_1_6_MSG(x) # define _CUPS_DEPRECATED_1_7_MSG(x) # define _CUPS_API_1_1_19 # define _CUPS_API_1_1_21 # define _CUPS_API_1_2 # define _CUPS_API_1_3 # define _CUPS_API_1_4 # define _CUPS_API_1_5 # define _CUPS_API_1_6 # define _CUPS_API_1_7 # define _CUPS_API_2_0 # include /* * C++ magic... */ # ifdef __cplusplus extern "C" { # endif /* __cplusplus */ /* * Types and structures... */ typedef struct _cups_array_s cups_array_t; /**** CUPS array type ****/ typedef int (*cups_array_func_t)(void *first, void *second, void *data); /**** Array comparison function ****/ typedef int (*cups_ahash_func_t)(void *element, void *data); /**** Array hash function ****/ typedef void *(*cups_acopy_func_t)(void *element, void *data); /**** Array element copy function ****/ typedef void (*cups_afree_func_t)(void *element, void *data); /**** Array element free function ****/ /* * Functions... */ extern int cupsArrayAdd(cups_array_t *a, void *e) _CUPS_API_1_2; extern void cupsArrayClear(cups_array_t *a) _CUPS_API_1_2; extern int cupsArrayCount(cups_array_t *a) _CUPS_API_1_2; extern void *cupsArrayCurrent(cups_array_t *a) _CUPS_API_1_2; extern void cupsArrayDelete(cups_array_t *a) _CUPS_API_1_2; extern cups_array_t *cupsArrayDup(cups_array_t *a) _CUPS_API_1_2; extern void *cupsArrayFind(cups_array_t *a, void *e) _CUPS_API_1_2; extern void *cupsArrayFirst(cups_array_t *a) _CUPS_API_1_2; extern int cupsArrayGetIndex(cups_array_t *a) _CUPS_API_1_3; extern int cupsArrayGetInsert(cups_array_t *a) _CUPS_API_1_3; extern void *cupsArrayIndex(cups_array_t *a, int n) _CUPS_API_1_2; extern int cupsArrayInsert(cups_array_t *a, void *e) _CUPS_API_1_2; extern void *cupsArrayLast(cups_array_t *a) _CUPS_API_1_2; extern cups_array_t *cupsArrayNew(cups_array_func_t f, void *d) _CUPS_API_1_2; extern cups_array_t *cupsArrayNew2(cups_array_func_t f, void *d, cups_ahash_func_t h, int hsize) _CUPS_API_1_3; extern cups_array_t *cupsArrayNew3(cups_array_func_t f, void *d, cups_ahash_func_t h, int hsize, cups_acopy_func_t cf, cups_afree_func_t ff) _CUPS_API_1_5; extern void *cupsArrayNext(cups_array_t *a) _CUPS_API_1_2; extern void *cupsArrayPrev(cups_array_t *a) _CUPS_API_1_2; extern int cupsArrayRemove(cups_array_t *a, void *e) _CUPS_API_1_2; extern void *cupsArrayRestore(cups_array_t *a) _CUPS_API_1_2; extern int cupsArraySave(cups_array_t *a) _CUPS_API_1_2; extern void *cupsArrayUserData(cups_array_t *a) _CUPS_API_1_2; # ifdef __cplusplus } # endif /* __cplusplus */ #endif /* !_CUPS_ARRAY_H_ */ htmldoc-1.9.7/htmldoc/debug.h000066400000000000000000000011161354715574200160670ustar00rootroot00000000000000/* * Debugging macros for HTMLDOC, a HTML document processing program. * * Copyright 2011 by Michael R Sweet. * Copyright 1997-2010 by Easy Software Products. All rights reserved. * * This program is free software. Distribution and use rights are outlined in * the file "COPYING". */ #ifndef _DEBUG_H_ # define _DEBUG_H_ /* * Include necessary headers. */ # include # ifdef DEBUG # define DEBUG_printf(x) printf x # define DEBUG_puts(x) puts(x) # else # define DEBUG_printf(x) # define DEBUG_puts(x) # endif /* DEBUG */ #endif /* !_DEBUG_H_ */ htmldoc-1.9.7/htmldoc/epub.cxx000066400000000000000000001202571354715574200163170ustar00rootroot00000000000000/* * EPUB exporting functions for HTMLDOC, a HTML document processing program. * * Copyright 2017-2019 by Michael R Sweet. * * This program is free software. Distribution and use rights are outlined in * the file "COPYING". */ /* * Include necessary headers. */ #include "htmldoc.h" #include "markdown.h" #include "zipc.h" #include #include #include /* * Named link structure... */ typedef struct { uchar *filename; /* File for link */ uchar name[124]; /* Reference name */ } link_t; /* * Local globals... */ static size_t num_links = 0, alloc_links = 0; static link_t *links; static size_t num_images = 0, alloc_images = 0; static char **images = NULL; /* * Local functions... */ extern "C" { typedef int (*compare_func_t)(const void *, const void *); } static int write_header(zipc_file_t *out, uchar *title, uchar *author, uchar *copyright, uchar *docnumber, tree_t *t); static int write_title(zipc_file_t *out, tree_t *title_tree, uchar *title, uchar *author, uchar *copyright, uchar *docnumber); static int write_all(zipc_file_t *out, tree_t *t); static int write_node(zipc_file_t *out, tree_t *t); static int write_nodeclose(zipc_file_t *out, tree_t *t); static int write_toc(zipc_file_t *out, tree_t *t); static char *get_iso_date(time_t t); static uchar *get_title(tree_t *doc); static void add_link(uchar *name, uchar *filename); static link_t *find_link(uchar *name); static int compare_links(link_t *n1, link_t *n2); static int compare_images(char **a, char **b); static int copy_image(zipc_t *zipc, const char *filename); static int copy_images(zipc_t *zipc, tree_t *t); static void scan_links(tree_t *t, uchar *filename); static void update_links(tree_t *t, uchar *filename); static tree_t *walk_next(tree_t *t); static int write_xhtml(zipc_file_t *out, uchar *s); static int write_xhtmlf(zipc_file_t *out, const char *format, ...); /* * 'epub_export()' - Export to EPUB... */ int /* O - 0 = success, -1 = failure */ epub_export(tree_t *document, /* I - Document to export */ tree_t *toc) /* I - Table of contents for document */ { uchar *title, /* Title text */ *author, /* Author name */ *copyright, /* Copyright text */ *docnumber, /* Document number */ *language, /* Language */ *subject; /* Subject/category */ zipc_t *epub; /* EPUB output file */ zipc_file_t *epubf; /* File in container */ struct stat epubinfo; /* EPUB file information */ const char *title_ext; /* Extension of title image */ tree_t *title_tree = NULL; /* Title file document tree */ const char *cover_image = NULL; /* Do we have a cover image? */ int status = 0; /* Return status */ static const char *mimetype = /* mimetype file as a string */ "application/epub+zip"; static const char *container_xml = /* container.xml file as a string */ "\n" "\n" " \n" " \n" " \n" "\n"; /* * Create the EPUB file... */ if ((epub = zipcOpen(OutputPath, "w")) == NULL) { progress_error(HD_ERROR_WRITE_ERROR, "Unable to create \"%s\": %s", OutputPath, strerror(errno)); return (-1); } /* * Add the mimetype file... */ status |= zipcCreateFileWithString(epub, "mimetype", mimetype); /* * The META-INF/ directory... */ status |= zipcCreateDirectory(epub, "META-INF/"); /* * The META-INF/container.xml file... */ if ((epubf = zipcCreateFile(epub, "META-INF/container.xml", 1)) != NULL) { status |= zipcFilePuts(epubf, container_xml); status |= zipcFileFinish(epubf); } else status = -1; /* * The OEBPS/ directory... */ status |= zipcCreateDirectory(epub, "OEBPS/"); /* * Copy logo and title images... */ if (LogoImage[0]) status |= copy_image(epub, file_find(Path, LogoImage)); for (int hfi = 0; hfi < MAX_HF_IMAGES; hfi ++) { if (HFImage[hfi][0]) status |= copy_image(epub, file_find(Path, HFImage[hfi])); } title_ext = file_extension(TitleImage); if (TitleImage[0] && TitlePage) { #ifdef WIN32 if (!stricmp(title_ext, "bmp") || !stricmp(title_ext, "gif") || !stricmp(title_ext, "jpg") || !stricmp(title_ext, "png")) #else if (!strcmp(title_ext, "bmp") || !strcmp(title_ext, "gif") || !strcmp(title_ext, "jpg") || !strcmp(title_ext, "png")) #endif // WIN32 { status |= copy_image(epub, file_find(Path, TitleImage)); cover_image = file_basename(TitleImage); } else { FILE *fp; /* Title file */ const char *title_file; /* Location of title file */ // Find the title page file... if ((title_file = file_find(Path, TitleImage)) == NULL) { progress_error(HD_ERROR_FILE_NOT_FOUND, "Unable to find title file \"%s\".", TitleImage); return (-1); } // Read a HTML title page... if ((fp = fopen(title_file, "rb")) == NULL) { progress_error(HD_ERROR_FILE_NOT_FOUND, "Unable to open title file \"%s\" - %s!", TitleImage, strerror(errno)); return (-1); } #ifdef _WIN32 if (!stricmp(title_ext, "md")) #else if (!strcmp(title_ext, "md")) #endif // _WIN32 title_tree = mdReadFile(NULL, fp, file_directory(TitleImage)); else title_tree = htmlReadFile(NULL, fp, file_directory(TitleImage)); htmlFixLinks(title_tree, title_tree, (uchar *)file_directory(TitleImage)); fclose(fp); status |= copy_images(epub, title_tree); } } status |= copy_images(epub, document); /* * Get document strings... */ if ((title = get_title(title_tree)) == NULL) title = get_title(document); if ((author = htmlGetMeta(title_tree, (uchar *)"author")) == NULL) author = htmlGetMeta(document, (uchar *)"author"); if ((copyright = htmlGetMeta(title_tree, (uchar *)"copyright")) == NULL) copyright = htmlGetMeta(document, (uchar *)"copyright"); if ((docnumber = htmlGetMeta(title_tree, (uchar *)"docnumber")) == NULL) docnumber = htmlGetMeta(document, (uchar *)"docnumber"); if (!docnumber) { if ((docnumber = htmlGetMeta(title_tree, (uchar *)"version")) == NULL) docnumber = htmlGetMeta(document, (uchar *)"version"); } if ((language = htmlGetMeta(title_tree, (uchar *)"lang")) == NULL) language = htmlGetMeta(document, (uchar *)"lang"); if (!language) language = (uchar *)"en-US"; if ((subject = htmlGetMeta(title_tree, (uchar *)"keywords")) == NULL) subject = htmlGetMeta(document, (uchar *)"keywords"); if (!subject) subject = (uchar *)"Unknown"; /* * Scan for all links in the document, and then update them... */ num_links = 0; alloc_links = 0; links = NULL; scan_links(document, NULL); update_links(document, NULL); update_links(toc, NULL); /* * Write the document content... */ if (!status && (epubf = zipcCreateFile(epub, "OEBPS/body.xhtml", 1)) != NULL) { status |= write_header(epubf, title, author, copyright, docnumber, NULL); if (TitlePage) { progress_show("Copying title page to EPUB container..."); status |= write_title(epubf, title_tree, title, author, copyright, docnumber); } while (document != NULL) { progress_show("Copying \"%s\" to EPUB container...", (char *)htmlGetVariable(document, (uchar *)"_HD_FILENAME")); status |= write_all(epubf, document->child); document = document->next; } status |= zipcFilePuts(epubf, "\n\n"); status |= zipcFileFinish(epubf); } else status = -1; /* * Write the package manifest... */ if (!status && (epubf = zipcCreateFile(epub, "OEBPS/package.opf", 1)) != NULL) { const char *uid = docnumber ? (char *)docnumber : file_basename(OutputPath); status |= write_xhtmlf(epubf, "\n" "\n" " \n" " %s\n" " %s\n" " %s\n" " %s\n" " %s\n" " %s\n" " htmldoc\n" " %s\n", uid, title, author, get_iso_date(time(NULL)), language, subject, copyright, uid); if (cover_image) status |= write_xhtmlf(epubf, " \n", cover_image); status |= zipcFilePuts(epubf, " \n" " \n" " \n" " \n"); for (size_t i = 0; !status && i < num_images; i ++) { const char *mimetype, *image_ext = file_extension(images[i]); if (!strcmp(image_ext, "bmp")) mimetype = "image/bmp"; else if (!strcmp(image_ext, "gif")) mimetype = "image/gif"; else if (!strcmp(image_ext, "jpg")) mimetype = "image/jpeg"; else mimetype = "image/png"; status |= write_xhtmlf(epubf, " \n", images[i], images[i], mimetype); } status |= zipcFilePuts(epubf, " \n" " \n" " \n" " \n" "\n"); status |= zipcFileFinish(epubf); } /* * Finally the table-of-contents file... */ if ((epubf = zipcCreateFile(epub, "OEBPS/nav.xhtml", 1)) != NULL) { progress_show("Copying table of contents to EPUB container..."); status |= write_xhtmlf(epubf, "\n" "\n" "\n" " \n" " %s\n" " \n" " \n" " \n" " \n" " \n" "\n"); status |= zipcFileFinish(epubf); } else status = -1; status |= zipcClose(epub); if (!stat(OutputPath, &epubinfo)) progress_error(HD_ERROR_NONE, "BYTES: %ld", (long)epubinfo.st_size); if (title != NULL) free(title); if (title_tree) htmlDeleteTree(title_tree); if (alloc_links) { free(links); num_links = 0; alloc_links = 0; links = NULL; } return (status); } /* * 'write_header()' - Output the standard "header" for a HTML file. */ static int /* O - 0 on success, -1 on failure */ write_header( zipc_file_t *out, /* I - Output file */ uchar *title, /* I - Title for document */ uchar *author, /* I - Author for document */ uchar *copyright, /* I - Copyright for document */ uchar *docnumber, /* I - ID number for document */ tree_t *t) /* I - Current document file */ { int status = 0; /* Write status */ static const char *families[] = /* Typeface names */ { "monospace", "serif", "sans-serif", "monospace", "serif", "sans-serif", "symbol", "dingbats" }; status |= zipcFilePuts(out, "\n" "\n" "\n" " \n"); if (title != NULL) status |= write_xhtmlf(out, " %s\n", title); if (author != NULL) status |= write_xhtmlf(out, " \n", author); if (copyright != NULL) status |= write_xhtmlf(out, " \n", copyright); if (docnumber != NULL) status |= write_xhtmlf(out, " \n", docnumber); status |= zipcFilePuts(out, " \n" " \n" " \n"); return (status); } /* * 'write_title()' - Write a title page... */ static int /* O - 0 on success, -1 on failure */ write_title(zipc_file_t *out, /* I - Output file */ tree_t *title_tree, /* I - Title tree, if any */ uchar *title, /* I - Title for document */ uchar *author, /* I - Author for document */ uchar *copyright, /* I - Copyright for document */ uchar *docnumber) /* I - ID number for document */ { int status = 0; /* Write status */ if (title_tree) { // Write a custom HTML title page... status |= write_all(out, title_tree); } else { // Write a "standard" title page with image... status |= zipcFilePuts(out, "
\n"); if (TitleImage[0]) { image_t *img = image_load(TitleImage, !OutputColor); status |= write_xhtmlf(out, "

\"%s\"

\n", file_basename((char *)TitleImage), img->width, img->height, title ? title : (uchar *)""); } if (title != NULL) status |= write_xhtmlf(out, "

%s

\n", title); const char *prefix = "

"; if (docnumber) { status |= zipcFilePuts(out, prefix); status |= write_xhtml(out, docnumber); prefix = "
\n"; } if (author) { status |= zipcFilePuts(out, prefix); status |= write_xhtml(out, author); prefix = "
\n"; } if (copyright) { status |= zipcFilePuts(out, prefix); status |= write_xhtml(out, copyright); prefix = "
\n"; } if (prefix[0] == '<') status |= zipcFilePuts(out, "

\n"); status |= zipcFilePuts(out, "
\n"); } return (status); } /* * 'write_all()' - Write all markup text for the given tree. */ static int /* O - 0 on success, -1 on error */ write_all(zipc_file_t *out, /* I - Output file */ tree_t *t) /* I - Document tree */ { while (t != NULL) { if (write_node(out, t)) return (-1); if (t->markup != MARKUP_HEAD && t->markup != MARKUP_TITLE) { if (write_all(out, t->child)) return (-1); } if (write_nodeclose(out, t)) return (-1); t = t->next; } return (0); } /* * 'write_node()' - Write a single tree node. */ static int /* O - 0 on success, -1 on error */ write_node(zipc_file_t *out, /* I - Output file */ tree_t *t) /* I - Document tree node */ { int status = 0; /* Write status */ int i; /* Looping var */ switch (t->markup) { case MARKUP_NONE : if (t->data == NULL) break; if (!t->prev && t->parent && t->parent->markup == MARKUP_PRE && !strcmp((char *)t->data, "\n")) break; /* Skip initial blank line */ status |= write_xhtml(out, t->data); break; case MARKUP_CENTER : /* Not in XHTML, use
instead */ if (t->child) status |= zipcFilePuts(out, "
"); break; case MARKUP_TABLE : /* No HTML 3.x table attributes in XHTML... */ if (t->child) status |= zipcFilePuts(out, "\n"); break; case MARKUP_TT : /* Not in XHTML, use instead... */ if (t->child) status |= zipcFilePuts(out, ""); break; case MARKUP_COMMENT : case MARKUP_UNKNOWN : case MARKUP_AREA : case MARKUP_BODY : case MARKUP_DOCTYPE : case MARKUP_ERROR : case MARKUP_FILE : case MARKUP_HEAD : case MARKUP_HTML : case MARKUP_MAP : case MARKUP_META : case MARKUP_TITLE : break; case MARKUP_BR : case MARKUP_DD : case MARKUP_DL : case MARKUP_DT : case MARKUP_H1 : case MARKUP_H2 : case MARKUP_H3 : case MARKUP_H4 : case MARKUP_H5 : case MARKUP_H6 : case MARKUP_H7 : case MARKUP_H8 : case MARKUP_H9 : case MARKUP_H10 : case MARKUP_H11 : case MARKUP_H12 : case MARKUP_H13 : case MARKUP_H14 : case MARKUP_H15 : case MARKUP_HR : case MARKUP_LI : case MARKUP_OL : case MARKUP_P : case MARKUP_UL : status |= zipcFilePuts(out, "\n"); default : if (t->markup != MARKUP_EMBED) { status |= zipcFilePrintf(out, "<%s", _htmlMarkups[t->markup]); for (i = 0; i < t->nvars; i ++) { if (strcasecmp((char *)t->vars[i].name, "BREAK") == 0 && t->markup == MARKUP_HR) continue; if (strcasecmp((char *)t->vars[i].name, "REALSRC") == 0 && t->markup == MARKUP_IMG) continue; if (strncasecmp((char *)t->vars[i].name, "_HD_", 4) == 0) continue; if (t->vars[i].value == NULL) status |= write_xhtmlf(out, " %ls=\"%ls\"", t->vars[i].name, t->vars[i].name); else if (t->markup == MARKUP_A && !strcasecmp((char *)t->vars[i].name, "NAME")) status |= write_xhtmlf(out, " id=\"%s\"", t->vars[i].value); else if (!strcasecmp((char *)t->vars[i].name, "ALIGN")) status |= write_xhtmlf(out, " style=\"text-align: %ls;\"", t->vars[i].value); else status |= write_xhtmlf(out, " %ls=\"%s\"", t->vars[i].name, t->vars[i].value); } if (t->child) status |= zipcFilePuts(out, ">"); else status |= zipcFilePuts(out, " />"); } break; } return (status); } /* * 'write_nodeclose()' - Close a single tree node. */ static int /* O - 0 on success, -1 on error */ write_nodeclose(zipc_file_t *out, /* I - Output file */ tree_t *t) /* I - Document tree node */ { if (t->markup != MARKUP_HEAD && t->markup != MARKUP_TITLE) { switch (t->markup) { case MARKUP_BODY : case MARKUP_ERROR : case MARKUP_FILE : case MARKUP_HEAD : case MARKUP_HTML : case MARKUP_NONE : case MARKUP_TITLE : case MARKUP_APPLET : case MARKUP_AREA : case MARKUP_BR : case MARKUP_COMMENT : case MARKUP_DOCTYPE : case MARKUP_EMBED : case MARKUP_HR : case MARKUP_IMG : case MARKUP_INPUT : case MARKUP_ISINDEX : case MARKUP_LINK : case MARKUP_META : case MARKUP_NOBR : case MARKUP_SPACER : case MARKUP_WBR : case MARKUP_UNKNOWN : break; case MARKUP_DD : case MARKUP_DL : case MARKUP_DT : case MARKUP_H1 : case MARKUP_H2 : case MARKUP_H3 : case MARKUP_H4 : case MARKUP_H5 : case MARKUP_H6 : case MARKUP_H7 : case MARKUP_H8 : case MARKUP_H9 : case MARKUP_H10 : case MARKUP_H11 : case MARKUP_H12 : case MARKUP_H13 : case MARKUP_H14 : case MARKUP_H15 : case MARKUP_LI : case MARKUP_OL : case MARKUP_P : case MARKUP_PRE : case MARKUP_TR : case MARKUP_UL : if (!t->child) break; if (zipcFilePrintf(out, "\n", _htmlMarkups[t->markup])) return (-1); break; case MARKUP_CENTER : /* Not in XHTML, use
instead */ if (t->child) { if (zipcFilePuts(out, "
\n")) return (-1); } break; case MARKUP_TABLE : /* No HTML 3.x table attributes in XHTML... */ if (t->child) { if (zipcFilePuts(out, "
\n")) return (-1); } break; case MARKUP_TT : /* Not in XHTML, use instead... */ if (t->child) { if (zipcFilePuts(out, "")) return (-1); } break; default : if (!t->child) break; if (zipcFilePrintf(out, "", _htmlMarkups[t->markup])) return (-1); break; } } return (0); } /* * 'write_toc()' - Write all markup text for the given table-of-contents. */ static int /* O - 0 on success, -1 on error */ write_toc(zipc_file_t *out, /* I - Output file */ tree_t *t) /* I - Document tree */ { int status = 0; /* Write status */ uchar *href; /* Link to heading */ while (t) { if (htmlGetVariable(t, (uchar *)"_HD_OMIT_TOC") == NULL) { switch (t->markup) { case MARKUP_NONE : status |= write_xhtml(out, t->data); break; case MARKUP_A : if ((href = htmlGetVariable(t, (uchar *)"HREF")) != NULL) { status |= write_xhtmlf(out, "
", href); status |= write_toc(out, t->child); status |= zipcFilePuts(out, ""); } break; case MARKUP_B : status |= zipcFilePuts(out, "
  • "); status |= write_toc(out, t->child); if (!t->next || t->next->markup != MARKUP_UL) status |= zipcFilePuts(out, "
  • \n"); break; case MARKUP_LI : status |= zipcFilePuts(out, "
  • "); status |= write_toc(out, t->child); status |= zipcFilePuts(out, "
  • \n"); break; case MARKUP_UL : status |= zipcFilePuts(out, "
      \n"); status |= write_toc(out, t->child); status |= zipcFilePuts(out, "
    "); if (t->prev && t->prev->markup == MARKUP_B) status |= zipcFilePuts(out, "\n"); break; case MARKUP_H1 : case MARKUP_BR : break; default : if (t->child) status |= write_toc(out, t->child); break; } } t = t->next; } return (status); } /* * 'get_iso_date()' - Get an ISO-formatted date/time string. */ static char * /* O - ISO date/time string */ get_iso_date(time_t t) /* I - Time value */ { struct tm *date; /* UTC date/time */ static char buffer[100]; /* String buffer */ date = gmtime(&t); snprintf(buffer, sizeof(buffer), "%04d-%02d-%02dT%02d:%02d:%02dZ", date->tm_year + 1900, date->tm_mon + 1, date->tm_mday, date->tm_hour, date->tm_min, date->tm_sec); return (buffer); } /* * 'get_title()' - Get the title string for the given document... */ static uchar * /* O - Title string */ get_title(tree_t *doc) /* I - Document tree */ { uchar *temp; /* Temporary pointer to title */ while (doc != NULL) { if (doc->markup == MARKUP_TITLE) return (htmlGetText(doc->child)); else if (doc->child != NULL) if ((temp = get_title(doc->child)) != NULL) return (temp); doc = doc->next; } return (NULL); } /* * 'add_link()' - Add a named link... */ static void add_link(uchar *name, /* I - Name of link */ uchar *filename) /* I - File for link */ { link_t *temp; /* New name */ if ((temp = find_link(name)) != NULL) temp->filename = filename; else { // See if we need to allocate memory for links... if (num_links >= alloc_links) { // Allocate more links... alloc_links += ALLOC_LINKS; if (num_links == 0) temp = (link_t *)malloc(sizeof(link_t) * alloc_links); else temp = (link_t *)realloc(links, sizeof(link_t) * alloc_links); if (temp == NULL) { progress_error(HD_ERROR_OUT_OF_MEMORY, "Unable to allocate memory for %d links - %s", alloc_links, strerror(errno)); alloc_links -= ALLOC_LINKS; return; } links = temp; } // Add a new link... temp = links + num_links; num_links ++; strlcpy((char *)temp->name, (char *)name, sizeof(temp->name)); temp->filename = filename; if (num_links > 1) qsort(links, num_links, sizeof(link_t), (compare_func_t)compare_links); } } /* * 'find_link()' - Find a named link... */ static link_t * find_link(uchar *name) /* I - Name to find */ { uchar *target; /* Pointer to target name portion */ link_t key, /* Search key */ *match; /* Matching name entry */ if (name == NULL || num_links == 0) return (NULL); if ((target = (uchar *)file_target((char *)name)) == NULL) return (NULL); strlcpy((char *)key.name, (char *)target, sizeof(key.name)); match = (link_t *)bsearch(&key, links, num_links, sizeof(link_t), (compare_func_t)compare_links); return (match); } /* * 'compare_links()' - Compare two named links. */ static int /* O - 0 = equal, -1 or 1 = not equal */ compare_links(link_t *n1, /* I - First name */ link_t *n2) /* I - Second name */ { return (strcasecmp((char *)n1->name, (char *)n2->name)); } /* * 'scan_links()' - Scan a document for link targets, and keep track of * the files they are in... */ static void scan_links(tree_t *t, /* I - Document tree */ uchar *filename) /* I - Filename */ { uchar *name; /* Name of link */ while (t != NULL) { if (t->markup == MARKUP_FILE) scan_links(t->child, (uchar *)file_basename((char *)htmlGetVariable(t, (uchar *)"_HD_FILENAME"))); else if (t->markup == MARKUP_A && (name = htmlGetVariable(t, (uchar *)"NAME")) != NULL) { add_link(name, filename); scan_links(t->child, filename); } else if (t->child != NULL) scan_links(t->child, filename); t = t->next; } } /* * 'update_links()' - Update links as needed. */ static void update_links(tree_t *t, /* I - Document tree */ uchar *filename) /* I - Current filename */ { link_t *link; /* Link */ uchar *href; /* Reference name */ uchar newhref[1024]; /* New reference name */ filename = (uchar *)file_basename((char *)filename); if (OutputFiles) { /* * Need to preserve/add filenames. */ while (t != NULL) { if (t->markup == MARKUP_A && (href = htmlGetVariable(t, (uchar *)"HREF")) != NULL) { /* * Update this link as needed... */ if (href[0] == '#' && (link = find_link(href)) != NULL) { #if defined(WIN32) || defined(__EMX__) if (filename == NULL || strcasecmp((char *)filename, (char *)link->filename) != 0) #else if (filename == NULL || strcmp((char *)filename, (char *)link->filename) != 0) #endif /* WIN32 || __EMX__ */ { snprintf((char *)newhref, sizeof(newhref), "%s%s", link->filename, href); htmlSetVariable(t, (uchar *)"HREF", newhref); } } } if (t->child != NULL) { if (t->markup == MARKUP_FILE) update_links(t->child, htmlGetVariable(t, (uchar *)"_HD_FILENAME")); else update_links(t->child, filename); } t = t->next; } } else { /* * Need to strip filenames. */ while (t != NULL) { if (t->markup == MARKUP_A && (href = htmlGetVariable(t, (uchar *)"HREF")) != NULL) { /* * Update this link as needed... */ if (href[0] != '#' && file_method((char *)href) == NULL && (link = find_link(href)) != NULL) { snprintf((char *)newhref, sizeof(newhref), "#%s", link->name); htmlSetVariable(t, (uchar *)"HREF", newhref); } } if (t->child != NULL) update_links(t->child, filename); t = t->next; } } } /* * 'compare_images()' - Compare two image filenames... */ static int compare_images(char **a, char **b) { return (strcmp(*a, *b)); } /* * 'copy_image()' - Copy an image to the ZIP container. */ static int /* O - 0 on success, -1 on failure */ copy_image(zipc_t *zipc, /* I - ZIP container */ const char *filename) /* I - File to copy */ { const char *base = file_basename(filename); /* Base filename */ char epubname[1024]; /* Name in ZIP container */ /* * Don't copy more than once for the same file... */ if (num_images > 0 && bsearch(&base, images, num_images, sizeof(char *), (compare_func_t)compare_images)) return (0); progress_show("Copying \"%s\" to EPUB container...", base); /* * Copy the file... */ snprintf(epubname, sizeof(epubname), "OEBPS/%s", base); if (zipcCopyFile(zipc, epubname, filename, 0, 0)) { progress_error(HD_ERROR_WRITE_ERROR, "Unable to copy \"%s\": %s", base, zipcError(zipc)); return (-1); } /* * Add it to the array of images... */ if (num_images >= alloc_images) { char **temp; alloc_images += 128; if (alloc_images == 128) temp = (char **)malloc(alloc_images * sizeof(char *)); else temp = (char **)realloc(images, alloc_images * sizeof(char *)); if (!temp) return (-1); images = temp; } images[num_images] = strdup(base); num_images ++; if (num_images > 1) qsort(images, num_images, sizeof(char *), (compare_func_t)compare_images); return (0); } /* * 'copy_images()' - Scan the tree for images and copy as needed... */ static int /* O - 0 on success, -1 on failure */ copy_images(zipc_t *zipc, /* I - ZIP container */ tree_t *t) /* I - Document tree */ { uchar *src, /* Image source */ *realsrc; /* Real image source */ while (t) { /* * If this is an image node, copy the image and update the SRC... */ if (t->markup == MARKUP_IMG && (src = htmlGetVariable(t, (uchar *)"SRC")) != NULL && (realsrc = htmlGetVariable(t, (uchar *)"REALSRC")) != NULL && file_method((char *)src) == NULL) { if (copy_image(zipc, (char *)realsrc)) return (-1); htmlSetVariable(t, (uchar *)"SRC", (uchar *)file_basename((char *)realsrc)); } /* * Move to the next node in the document tree... */ t = walk_next(t); } return (0); } /* * 'walk_next()' - Return the next node in the tree. */ static tree_t * /* O - Next node */ walk_next(tree_t *t) /* I - Current node */ { if (t->child) return (t->child); else if (t->next) return (t->next); else if (t->parent) { do { t = t->parent; } while (t && !t->next); if (t) return (t->next); else return (NULL); } else return (NULL); } /* * 'write_xhtml()' - Write an XHTML-safe string. */ static int /* O - 0 on success, -1 on error */ write_xhtml(zipc_file_t *out, /* I - Output file */ uchar *s) /* I - String to write */ { int status = 0; /* Return status */ uchar *start, /* First character in sequence */ *ptr; /* Current character */ for (ptr = s, start = s; *ptr; ptr ++) { if (*ptr > 0x7f || strchr("<>&\"", *ptr)) { if (ptr > start) status |= zipcFileWrite(out, start, (size_t)(ptr - start)); status |= zipcFilePuts(out, (char *)xhtml_entity(*ptr)); start = ptr + 1; } } if (ptr > start) status |= zipcFileWrite(out, start, (size_t)(ptr - start)); return (status); } /* * 'write_xhtmlf()' - Write an XHTML-safe printf string. */ static int /* O - 0 on success, -1 on error */ write_xhtmlf(zipc_file_t *out, /* I - Output file */ const char *format, /* I - Printf-style string to write */ ...) /* I - Additional args as needed */ { int status = 0; /* Return status */ va_list ap; /* Additional arguments */ uchar *start, /* First character in sequence */ *ptr; /* Current character */ const char *s; /* String pointer */ int d; /* Number */ char temp[32]; /* Temporary string buffer */ va_start(ap, format); for (ptr = (uchar *)format, start = (uchar *)format; *ptr; ptr ++) { if (*ptr == '%') { /* * Format character - write any pending text fragment... */ if (ptr > start) { /* * Include the % if the format char is %%... */ if (ptr[1] == '%') status |= zipcFileWrite(out, start, (size_t)(ptr - start + 1)); else status |= zipcFileWrite(out, start, (size_t)(ptr - start)); } /* * Start over and process the character... */ ptr ++; start = ptr + 1; switch (*ptr) { case '%' : /* Escaped % */ break; case 'd' : /* Substitute a single integer */ d = va_arg(ap, int); snprintf(temp, sizeof(temp), "%d", d); status |= zipcFilePuts(out, temp); break; case 'l' : /* Substitude (and lower-case) a single string */ if (ptr[1] != 's') { start = ptr - 1; break; } ptr ++; start = ptr + 1; s = va_arg(ap, const char *); if (!s) s = "(null)"; while (*s) { status |= zipcFilePuts(out, (char *)xhtml_entity((uchar)tolower(*s & 255))); s ++; } break; case 's' : /* Substitute a single string */ s = va_arg(ap, const char *); if (!s) s = "(null)"; status |= write_xhtml(out, (uchar *)s); break; default : /* Something else we don't support... */ start = ptr - 1; break; } } else if (*ptr > 0x7f) { if (ptr > start) status |= zipcFileWrite(out, start, (size_t)(ptr - start)); status |= zipcFilePuts(out, (char *)xhtml_entity(*ptr)); start = ptr + 1; } } if (ptr > start) status |= zipcFileWrite(out, start, (size_t)(ptr - start)); return (status); } htmldoc-1.9.7/htmldoc/file.c000066400000000000000000000625651354715574200157320ustar00rootroot00000000000000/* * Filename routines for HTMLDOC, a HTML document processing program. * * Copyright © 2011-2019 by Michael R Sweet. * Copyright © 1997-2010 by Easy Software Products. All rights reserved. * * This program is free software. Distribution and use rights are outlined in * the file "COPYING". */ /* * Include necessary headers. */ #include "file.h" #include "http.h" #include "progress.h" #include "debug.h" #if defined(WIN32) # include #else # include #endif /* WIN32 */ #include #include #include #include #include /* * Temporary file definitions... */ #ifdef WIN32 # define getpid GetCurrentProcessId # define TEMPLATE "%s/%08lx.%06d.tmp" # define OPENMODE (_O_CREAT | _O_RDWR | _O_TRUNC | _O_BINARY) # define OPENPERM (_S_IREAD | _S_IWRITE) #else # define TEMPLATE "%s/%06ld.%06d.tmp" # define OPENMODE (O_CREAT | O_RDWR | O_EXCL | O_TRUNC) # define OPENPERM 0600 #endif /* WIN32 */ /* * Cache file structure... */ typedef struct /* Cache for all temporary files */ { char *name; /* Temporary filename */ char *url; /* URL */ } cache_t; /* * Local globals... */ char proxy_host[HTTP_MAX_URI] = ""; /* Proxy hostname */ int proxy_port = 0; /* Proxy port */ http_t *http = NULL; /* Connection to remote server */ size_t web_files = 0, /* Number of temporary files */ web_alloc = 0; /* Number of allocated files */ cache_t *web_cache = NULL; /* Cache array */ int no_local = 0; /* Non-zero to disable local files */ char cookies[1024] = ""; /* HTTP cookies, if any */ char referer_url[HTTP_MAX_VALUE] = ""; /* HTTP referer, if any */ /* * 'file_basename()' - Return the base filename without directory or target. */ const char * /* O - Base filename */ file_basename(const char *s) /* I - Filename or URL */ { const char *basename; /* Pointer to directory separator */ static char buf[1024]; /* Buffer for files with targets */ if (s == NULL) return (NULL); if ((basename = strrchr(s, '/')) != NULL) basename ++; else if ((basename = strrchr(s, '\\')) != NULL) basename ++; else basename = (char *)s; if (basename[0] == '#') return (NULL); if (strchr(basename, '#') == NULL) return (basename); strlcpy(buf, basename, sizeof(buf)); *(char *)strchr(buf, '#') = '\0'; return (buf); } /* * 'file_cleanup()' - Close an open HTTP connection and remove temporary files... */ void file_cleanup(void) { size_t i; /* Looping var */ char filename[1024]; /* Temporary file */ struct stat fileinfo; /* File information */ size_t remotebytes; /* Size of remote data */ const char *tmpdir; /* Temporary directory */ #ifdef WIN32 char tmppath[1024]; /* Temporary directory */ #endif /* WIN32 */ const char *debug; /* HTMLDOC_DEBUG env var */ if (http) { httpClose(http); http = NULL; } #ifdef WIN32 if ((tmpdir = getenv("TEMP")) == NULL) { GetTempPath(sizeof(tmppath), tmppath); tmpdir = tmppath; } #else if ((tmpdir = getenv("TMPDIR")) == NULL) tmpdir = "/var/tmp"; #endif /* WIN32 */ /* * Report on the remote data bytes that were downloaded... */ debug = getenv("HTMLDOC_DEBUG"); if (debug && (strstr(debug, "all") != NULL || strstr(debug, "remotebytes") != NULL)) { for (i = 0, remotebytes = 0; i < web_files; i ++) if (web_cache[i].url) { snprintf(filename, sizeof(filename), TEMPLATE, tmpdir, (long)getpid(), (int)(i + 1)); if (!stat(filename, &fileinfo)) remotebytes += (size_t)fileinfo.st_size; } progress_error(HD_ERROR_NONE, "REMOTEBYTES: %ld", (long)remotebytes); } /* * Check to see if we want to leave the temporary files around for * debugging... */ if (debug && (strstr(debug, "all") != NULL || strstr(debug, "tempfiles") != NULL)) { /* * Yes, leave the files, but show the mapping from filename to URL... */ progress_error(HD_ERROR_NONE, "DEBUG: Temporary File Summary"); progress_error(HD_ERROR_NONE, "DEBUG:"); progress_error(HD_ERROR_NONE, "DEBUG: URL Filename"); progress_error(HD_ERROR_NONE, "DEBUG: ------------------------------- ---------------------"); for (i = 0; i < web_files; i ++) { snprintf(filename, sizeof(filename), TEMPLATE, tmpdir, (long)getpid(), (int)(i + 1)); progress_error(HD_ERROR_NONE, "DEBUG: %-31.31s %s\n", web_cache[i].url ? web_cache[i].url : "none", filename); } progress_error(HD_ERROR_NONE, "DEBUG:"); return; } while (web_files > 0) { snprintf(filename, sizeof(filename), TEMPLATE, tmpdir, (long)getpid(), (int)web_files); if (unlink(filename)) progress_error(HD_ERROR_DELETE_ERROR, "Unable to delete temporary file \"%s\": %s", filename, strerror(errno)); web_files --; if (web_cache[web_files].name) free(web_cache[web_files].name); if (web_cache[web_files].url) free(web_cache[web_files].url); } if (web_alloc) { free(web_cache); web_alloc = 0; web_cache = NULL; } } /* * 'file_cookies()' - Set the HTTP cookies for remote accesses. */ void file_cookies(const char *s) /* I - Cookie string or NULL */ { if (s) strlcpy(cookies, s, sizeof(cookies)); else cookies[0] = '\0'; } /* * 'file_directory()' - Return the directory without filename or target. */ const char * /* O - Directory for file */ file_directory(const char *s) /* I - Filename or URL */ { char *dir; /* Pointer to directory separator */ static char buf[1024]; /* Buffer for files with targets */ if (s == NULL || !strncmp(s, "data:", 5)) return (NULL); if (strncmp(s, "http://", 7) == 0 || strncmp(s, "https://", 8) == 0) { /* * Handle URLs... */ char scheme[HTTP_MAX_URI], username[HTTP_MAX_URI], hostname[HTTP_MAX_URI], resource[HTTP_MAX_URI]; int port; httpSeparateURI(HTTP_URI_CODING_ALL, s, scheme, sizeof(scheme), username, sizeof(username), hostname, sizeof(hostname), &port, resource, sizeof(resource)); if ((dir = strrchr(resource, '/')) != NULL) *dir = '\0'; httpAssembleURI(HTTP_URI_CODING_ALL, buf, sizeof(buf), scheme, username, hostname, port, resource); } else { /* * Normal stuff... */ strlcpy(buf, s, sizeof(buf)); if ((dir = strrchr(buf, '/')) != NULL) *dir = '\0'; else if ((dir = strrchr(buf, '\\')) != NULL) *dir = '\0'; else return ("."); if (strncmp(buf, "file:", 5) == 0) hd_strcpy(buf, buf + 5); if (!buf[0]) /* Safe because buf is more than 2 chars long */ strlcpy(buf, "/", sizeof(buf)); } return (buf); } /* * 'file_extension()' - Return the extension of a file without the target. */ const char * /* O - File extension */ file_extension(const char *s) /* I - Filename or URL */ { const char *extension; /* Pointer to directory separator */ static char buf[1024]; /* Buffer for files with targets */ if (s == NULL) return (NULL); else if (!strncmp(s, "data:image/bmp;", 15)) return ("bmp"); else if (!strncmp(s, "data:image/gif;", 15)) return ("gif"); else if (!strncmp(s, "data:image/jpeg;", 16)) return ("jpg"); else if (!strncmp(s, "data:image/png;", 15)) return ("png"); else if ((extension = strrchr(s, '/')) != NULL) extension ++; else if ((extension = strrchr(s, '\\')) != NULL) extension ++; else extension = s; if ((extension = strrchr(extension, '.')) == NULL) return (""); else extension ++; if (strchr(extension, '#') == NULL) return (extension); strlcpy(buf, extension, sizeof(buf)); *(char *)strchr(buf, '#') = '\0'; return (buf); } /* * 'file_find_check()' - Check to see if the specified file or URL exists... */ static const char * /* O - Pathname or NULL */ file_find_check(const char *filename) /* I - File or URL */ { int i; /* Looping var */ int retry; /* Current retry */ char scheme[HTTP_MAX_URI], /* Method/scheme */ username[HTTP_MAX_URI], /* Username:password */ hostname[HTTP_MAX_URI], /* Hostname */ resource[HTTP_MAX_URI]; /* Resource */ int port; /* Port number */ const char *connhost; /* Host to connect to */ int connport; /* Port to connect to */ char connpath[HTTP_MAX_URI], /* Path for GET */ connauth[HTTP_MAX_VALUE];/* Auth string */ http_status_t status; /* Status of request... */ FILE *fp; /* Web file */ ssize_t bytes, /* Bytes read */ count; /* Number of bytes so far */ off_t total; /* Total bytes in file */ char tempname[HTTP_MAX_URI]; /* Temporary filename */ DEBUG_printf(("file_find_check(filename=\"%s\")\n", filename)); if (strncmp(filename, "http:", 5) == 0 || strncmp(filename, "//", 2) == 0) strlcpy(scheme, "http", sizeof(scheme)); else if (strncmp(filename, "https:", 6) == 0) strlcpy(scheme, "https", sizeof(scheme)); else if (strncmp(filename, "data:", 5) == 0) strlcpy(scheme, "data", sizeof(scheme)); else strlcpy(scheme, "file", sizeof(scheme)); if (strcmp(scheme, "file") == 0) { /* * Return immediately if we aren't allowing access to local files... */ if (no_local) return (NULL); /* * If the filename exists, return the filename... */ if (!access(filename, 0)) { DEBUG_printf(("file_find_check: Returning \"%s\"!\n", filename)); return (filename); } } else if (!strcmp(scheme, "data")) { /* * Data URI; look it up in the web cache, then save to a temporary file... */ const char *data; /* Pointer to data */ int len; /* Number of bytes */ char buffer[8192]; /* Data buffer */ for (i = 0; i < (int)web_files; i ++) { if (web_cache[i].url && strcmp(web_cache[i].url, filename) == 0) { DEBUG_printf(("file_find_check: Returning \"%s\" for \"%s\".\n", web_cache[i].name, filename)); return (web_cache[i].name); } } if ((data = strstr(filename, ";base64,")) != NULL) { len = sizeof(buffer); httpDecode64_2(buffer, &len, data + 8); if ((fp = file_temp(tempname, sizeof(tempname))) == NULL) { progress_hide(); progress_error(HD_ERROR_WRITE_ERROR, "Unable to create temporary file \"%s\": %s", tempname, strerror(errno)); return (NULL); } fwrite(buffer, 1, (size_t)len, fp); fclose(fp); progress_hide(); web_cache[web_files - 1].url = strdup(filename); DEBUG_printf(("file_find_check: Returning \"%s\" for \"%s\".\n", tempname, filename)); return (web_cache[web_files - 1].name); } } else { /* * Remote file; look it up in the web cache, and then try getting it * from the remote system... */ for (i = 0; i < (int)web_files; i ++) { if (web_cache[i].url && strcmp(web_cache[i].url, filename) == 0) { DEBUG_printf(("file_find_check: Returning \"%s\" for \"%s\".\n", web_cache[i].name, filename)); return (web_cache[i].name); } } httpSeparateURI(HTTP_URI_CODING_ALL, filename, scheme, sizeof(scheme), username, sizeof(username), hostname, sizeof(hostname), &port, resource, sizeof(resource)); for (status = HTTP_ERROR, retry = 0; status == HTTP_ERROR && retry < 5; retry ++) { if (proxy_port) { /* * Send request to proxy host... */ connhost = proxy_host; connport = proxy_port; snprintf(connpath, sizeof(connpath), "%s://%s:%d%s", scheme, hostname, port, resource); } else { /* * Send request to host directly... */ connhost = hostname; connport = port; strlcpy(connpath, resource, sizeof(connpath)); } if (connport != httpAddrPort(httpGetAddress(http)) || strcasecmp(httpGetHostname(http, tempname, sizeof(tempname)), hostname)) { httpClose(http); http = NULL; } if (http == NULL) { progress_show("Connecting to %s...", connhost); #ifdef HAVE_SSL if (strcmp(scheme, "http") == 0) http = httpConnect(connhost, connport); else http = httpConnectEncrypt(connhost, connport, HTTP_ENCRYPT_ALWAYS); #else http = httpConnect(connhost, connport); #endif /* HAVE_SSL */ if (http == NULL) { progress_hide(); progress_error(HD_ERROR_NETWORK_ERROR, "Unable to connect to %s!", connhost); return (NULL); } } progress_show("Getting %s...", connpath); httpClearFields(http); httpSetField(http, HTTP_FIELD_HOST, hostname); httpSetField(http, HTTP_FIELD_CONNECTION, "Keep-Alive"); httpSetField(http, HTTP_FIELD_REFERER, referer_url); if (username[0]) { strlcpy(connauth, "Basic ", sizeof(connauth)); httpEncode64_2(connauth + 6, sizeof(connauth) - 6, username, strlen(username)); httpSetField(http, HTTP_FIELD_AUTHORIZATION, connauth); } if (cookies[0]) httpSetCookie(http, cookies); if (!httpGet(http, connpath)) { while ((status = httpUpdate(http)) == HTTP_CONTINUE); } else status = HTTP_ERROR; if (status >= HTTP_MOVED_PERMANENTLY && status <= HTTP_SEE_OTHER) { /* * Flush text... */ httpFlush(http); /* * Grab new location from HTTP data... */ httpSeparateURI(HTTP_URI_CODING_ALL, httpGetField(http, HTTP_FIELD_LOCATION), scheme, sizeof(scheme), username, sizeof(username), hostname, sizeof(hostname), &port, resource, sizeof(resource)); status = HTTP_ERROR; } } if (status != HTTP_OK) { progress_hide(); progress_error((HDerror)status, "%s (%s)", httpStatus(status), filename); httpFlush(http); return (NULL); } if ((fp = file_temp(tempname, sizeof(tempname))) == NULL) { progress_hide(); progress_error(HD_ERROR_WRITE_ERROR, "Unable to create temporary file \"%s\": %s", tempname, strerror(errno)); httpFlush(http); return (NULL); } if ((total = httpGetLength2(http)) == 0) total = 8192; count = 0; while ((bytes = httpRead2(http, resource, sizeof(resource))) > 0) { count += bytes; progress_update((100 * count / total) % 101); fwrite(resource, 1, (size_t)bytes, fp); } progress_hide(); fclose(fp); web_cache[web_files - 1].url = strdup(filename); DEBUG_printf(("file_find_check: Returning \"%s\" for \"%s\".\n", tempname, filename)); return (web_cache[web_files - 1].name); } return (NULL); } /* * 'file_find()' - Find a file in one of the path directories. */ const char * /* O - Pathname or NULL */ file_find(const char *path, /* I - Path "dir;dir;dir" */ const char *s) /* I - File to find */ { int i; /* Looping var */ char *temp; /* Current position in filename */ const char *sptr; /* Pointer into "s" */ int ch; /* Quoted character */ char basename[HTTP_MAX_URI]; /* Base (unquoted) filename */ const char *realname; /* Real filename */ static char filename[HTTP_MAX_URI]; /* Current filename */ /* * If the filename is NULL, return NULL... */ if (s == NULL) return (NULL); DEBUG_printf(("file_find(path=\"%s\", s=\"%s\")\n", path ? path : "(null)", s)); /* * See if this is a cached remote file... */ for (i = 0; i < (int)web_files; i ++) if (strcmp(s, web_cache[i].name) == 0) { DEBUG_printf(("file_find: Returning cache file \"%s\"!\n", s)); return (s); } DEBUG_printf(("file_find: \"%s\" not in web cache of %d files...\n", s, (int)web_files)); /* * Make sure the filename is not quoted... */ if (strchr(s, '%') == NULL) strlcpy(basename, s, sizeof(basename)); else { for (sptr = s, temp = basename; *sptr && temp < (basename + sizeof(basename) - 1);) if (*sptr == '%' && isxdigit(sptr[1]) && isxdigit(sptr[2])) { /* * Dequote %HH... */ if (isalpha(sptr[1])) ch = (tolower(sptr[1]) - 'a' + 10) << 4; else ch = (sptr[1] - '0') << 4; if (isalpha(sptr[2])) ch |= tolower(sptr[2]) - 'a' + 10; else ch |= sptr[2] - '0'; *temp++ = (char)ch; sptr += 3; } else *temp++ = *sptr++; *temp = '\0'; } /* * If we got a complete URL, we don't use the path... */ if (path != NULL && !path[0]) { DEBUG_puts("file_find: Resetting path to NULL since path is empty..."); path = NULL; } if (strncmp(s, "http:", 5) == 0 || strncmp(s, "https:", 6) == 0 || strncmp(s, "//", 2) == 0) { DEBUG_puts("file_find: Resetting path to NULL since filename is a URL..."); path = NULL; } /* * Loop through the path as needed... */ if (path != NULL) { filename[sizeof(filename) - 1] = '\0'; while (*path != '\0') { /* * Copy the path directory... */ temp = filename; while (*path != ';' && *path && temp < (filename + sizeof(filename) - 1)) *temp++ = *path++; if (*path == ';') path ++; /* * Append a slash as needed, then the filename... */ if (temp > filename && temp < (filename + sizeof(filename) - 1) && basename[0] != '/') *temp++ = '/'; strlcpy(temp, basename, sizeof(filename) - (size_t)(temp - filename)); /* * See if the file or URL exists... */ if ((realname = file_find_check(filename)) != NULL) return (realname); } } return (file_find_check(s)); } /* * 'file_gets()' - Read a line from a file terminated with CR, LF, or CR LF. */ char * /* O - Line from file or NULL on EOF */ file_gets(char *buf, /* I - Line buffer */ int buflen, /* I - Length of buffer */ FILE *fp) /* I - File to read from */ { int ch; /* Character from file */ char *ptr, /* Current position in line buffer */ *end; /* End of line buffer */ /* * Range check everything... */ if (fp == NULL || buf == NULL || buflen < 2) return (NULL); /* * Now loop until we have a valid line... */ ptr = buf; end = buf + buflen - 1; for (;;) { if ((ch = getc(fp)) == EOF) break; else if (ch == '\r') { /* * See if we have CR or CR LF... */ int nextch = getc(fp); if (nextch == EOF || nextch == '\n') break; /* * No LF, so save the next char for later... */ ungetc(nextch, fp); break; } else if (ch == '\n') break; else if (ch == '\\') { /* * Handle \ escapes, to continue to multiple lines... */ int nextch = getc(fp); if (nextch == EOF) break; else if (nextch == '\r') { nextch = getc(fp); if (nextch == EOF) break; else if (nextch != '\n') ungetc(nextch, fp); } else if (nextch != '\n' && ptr < end) *ptr++ = (char)nextch; } else if (ptr < end) *ptr++ = (char)ch; } *ptr = '\0'; if (ch != EOF || ptr > buf) return (buf); else return (NULL); } /* * 'file_localize()' - Localize a filename for the new working directory. */ const char * /* O - New filename */ file_localize(const char *filename, /* I - Filename */ const char *newcwd) /* I - New directory */ { const char *newslash; /* Directory separator */ char *slash; /* Directory separator */ char cwd[1024]; /* Current directory */ char temp[1024]; /* Temporary pathname */ static char newfilename[1024]; /* New filename */ if (filename[0] == '\0') return (""); if (file_method(filename)) return (filename); getcwd(cwd, sizeof(cwd)); if (newcwd == NULL) newcwd = cwd; #if defined(WIN32) || defined(__EMX__) if (filename[0] != '/' && filename[0] != '\\' && !(isalpha(filename[0]) && filename[1] == ':')) #else if (filename[0] != '/') #endif /* WIN32 || __EMX__ */ { for (newslash = filename; strncmp(newslash, "../", 3) == 0; newslash += 3) #if defined(WIN32) || defined(__EMX__) { if ((slash = strrchr(cwd, '/')) == NULL) slash = strrchr(cwd, '\\'); if (slash != NULL) *slash = '\0'; } #else if ((slash = strrchr(cwd, '/')) != NULL) *slash = '\0'; #endif /* WIN32 || __EMX__ */ snprintf(temp, sizeof(temp), "%s/%s", cwd, newslash); } else strlcpy(temp, filename, sizeof(temp)); for (slash = temp, newslash = newcwd; *slash != '\0' && *newslash != '\0'; slash ++, newslash ++) if ((*slash == '/' || *slash == '\\') && (*newslash == '/' || *newslash == '\\')) continue; else if (*slash != *newslash) break; while (*slash != '/' && *slash != '\\' && slash > temp) slash --; if (*slash == '/' || *slash == '\\') slash ++; #if defined(WIN32) || defined(__EMX__) if (isalpha(slash[0]) && slash[1] == ':') return ((char *)filename); /* Different drive letter... */ #endif /* WIN32 || __EMX__ */ if (*newslash != '\0') while (*newslash != '/' && *newslash != '\\' && newslash > newcwd) newslash --; newfilename[0] = '\0'; while (*newslash != '\0') { if (*newslash == '/' || *newslash == '\\') strlcat(newfilename, "../", sizeof(newfilename)); newslash ++; } strlcat(newfilename, slash, sizeof(newfilename)); return (newfilename); } /* * 'file_method()' - Return the method for a filename or URL. * * Returns NULL if the URL is a local file. */ const char * /* O - Method string ("http", "ftp", etc.) */ file_method(const char *s) /* I - Filename or URL */ { if (strncmp(s, "http:", 5) == 0) return ("http"); else if (strncmp(s, "https:", 6) == 0) return ("https"); else if (strncmp(s, "ftp:", 4) == 0) return ("ftp"); else if (strncmp(s, "mailto:", 7) == 0) return ("mailto"); else return (NULL); } /* * 'file_nolocal()' - Disable access to local files. */ void file_nolocal(void) { no_local = 1; } /* * 'file_proxy()' - Set the proxy host for all HTTP requests. */ void file_proxy(const char *url) /* I - URL of proxy server */ { char scheme[HTTP_MAX_URI], /* Method name (must be HTTP) */ username[HTTP_MAX_URI], /* Username:password information */ hostname[HTTP_MAX_URI], /* Hostname */ resource[HTTP_MAX_URI]; /* Resource name */ int port; /* Port number */ if (url == NULL || url[0] == '\0') { proxy_host[0] = '\0'; proxy_port = 0; } else { httpSeparateURI(HTTP_URI_CODING_ALL, url, scheme, sizeof(scheme), username, sizeof(username), hostname, sizeof(hostname), &port, resource, sizeof(resource)); if (strcmp(scheme, "http") == 0) { strlcpy(proxy_host, hostname, sizeof(proxy_host)); proxy_port = port; } } } /* * 'file_referer()' - Set the HTTP referer for remote accesses. */ void file_referer(const char *referer) /* I - Referer URL */ { if (referer) strlcpy(referer_url, referer, sizeof(referer_url)); else referer_url[0] = '\0'; } /* * 'file_rlookup()' - Lookup a filename to find the original URL, if applicable. */ const char * /* O - URL or filename */ file_rlookup(const char *filename) /* I - Filename */ { int i; /* Looping var */ cache_t *wc; /* Current cache file */ for (i = web_files, wc = web_cache; i > 0; i --, wc ++) if (!strcmp(wc->name, filename)) return (wc->url); return (filename); } /* * 'file_target()' - Return the target of a link. */ const char * /* O - Target name */ file_target(const char *s) /* I - Filename or URL */ { const char *basename; /* Pointer to directory separator */ const char *target; /* Pointer to target */ if (s == NULL) return (NULL); if ((basename = strrchr(s, '/')) != NULL) basename ++; else if ((basename = strrchr(s, '\\')) != NULL) basename ++; else basename = s; if ((target = strchr(basename, '#')) != NULL) return (target + 1); else return (NULL); } /* * 'file_temp()' - Create and open a temporary file. */ FILE * /* O - Temporary file */ file_temp(char *name, /* O - Filename */ int len) /* I - Length of filename buffer */ { cache_t *temp; /* Pointer to cache entry */ FILE *fp; /* File pointer */ int fd; /* File descriptor */ const char *tmpdir; /* Temporary directory */ #ifdef WIN32 char tmppath[1024]; /* Buffer for temp dir */ #endif /* WIN32 */ /* * Allocate memory for the file cache as needed... */ if (web_files >= web_alloc) { web_alloc += ALLOC_FILES; if (web_files == 0) temp = (cache_t *)malloc(sizeof(cache_t) * web_alloc); else temp = (cache_t *)realloc(web_cache, sizeof(cache_t) * web_alloc); if (temp == NULL) { progress_error(HD_ERROR_OUT_OF_MEMORY, "Unable to allocate memory for %d file entries - %s", web_alloc, strerror(errno)); web_alloc -= ALLOC_FILES; return (NULL); } web_cache = temp; } /* * Clear a new file cache entry... */ temp = web_cache + web_files; temp->name = NULL; temp->url = NULL; web_files ++; #ifdef WIN32 if ((tmpdir = getenv("TEMP")) == NULL) { GetTempPath(sizeof(tmppath), tmppath); tmpdir = tmppath; } #else if ((tmpdir = getenv("TMPDIR")) == NULL) tmpdir = "/var/tmp"; #endif /* WIN32 */ snprintf(name, (size_t)len, TEMPLATE, tmpdir, (long)getpid(), (int)web_files); if ((fd = open(name, OPENMODE, OPENPERM)) >= 0) fp = fdopen(fd, "w+b"); else fp = NULL; if (!fp) web_files --; temp->name = strdup(name); return (fp); } htmldoc-1.9.7/htmldoc/file.h000066400000000000000000000024351354715574200157250ustar00rootroot00000000000000/* * Filename definitions for HTMLDOC, a HTML document processing program. * * Copyright 2011, 2014 by Michael R Sweet. * Copyright 1997-2010 by Easy Software Products. All rights reserved. * * This program is free software. Distribution and use rights are outlined in * the file "COPYING". */ #ifndef _FILE_H_ # define _FILE_H_ /* * Include necessary headers... */ # include "hdstring.h" # ifdef __cplusplus extern "C" { # endif /* __cplusplus */ /* * Prototypes... */ extern const char *file_basename(const char *s); extern void file_cleanup(void); extern void file_cookies(const char *s); extern const char *file_directory(const char *s); extern const char *file_extension(const char *s); extern const char *file_find(const char *path, const char *s); extern char *file_gets(char *buf, int buflen, FILE *fp); extern const char *file_localize(const char *filename, const char *newcwd); extern const char *file_method(const char *s); extern void file_nolocal(void); extern void file_proxy(const char *url); extern void file_referer(const char *referer); extern const char *file_rlookup(const char *filename); extern const char *file_target(const char *s); extern FILE *file_temp(char *name, int len); # ifdef __cplusplus } # endif /* __cplusplus */ #endif /* !_FILE_H_ */ htmldoc-1.9.7/htmldoc/gui.cxx000066400000000000000000003357321354715574200161560ustar00rootroot00000000000000// // GUI routines for HTMLDOC, an HTML document processing program. // // Copyright 2011-2019 by Michael R Sweet. // Copyright 1997-2010 by Easy Software Products. All rights reserved. // // This program is free software. Distribution and use rights are outlined in // the file "COPYING". // #include "htmldoc.h" #include "markdown.h" #ifdef HAVE_LIBFLTK // // Include necessary headers. // # include # include # include # include # include # include # include # include # include "../desktop/htmldoc.xpm" # ifdef WIN32 # include # include # include "icons.h" # else # include # ifdef HAVE_LIBXPM # include # elif !defined(__APPLE__) # include "../desktop/htmldoc.xbm" # endif // HAVE_LIBXPM # endif // WIN32 // // Class globals... // const char *GUI::help_dir = DOCUMENTATION; #ifdef __APPLE__ char *apple_filename = NULL; #endif // __APPLE__ // // 'GUI()' - Build the HTMLDOC GUI and load the indicated book as necessary. // GUI::GUI(const char *filename) // Book file to load initially { Fl_Group *group; // Group Fl_Box *label; // Label box static Fl_Menu sizeMenu[] = // Menu items for page size button */ { {"A3", 0, 0, 0, 0, 0, FL_HELVETICA, 14, 0}, {"A4", 0, 0, 0, 0, 0, FL_HELVETICA, 14, 0}, {"Legal", 0, 0, 0, 0, 0, FL_HELVETICA, 14, 0}, {"Letter", 0, 0, 0, 0, 0, FL_HELVETICA, 14, 0}, {"Tabloid", 0, 0, 0, 0, 0, FL_HELVETICA, 14, 0}, {"Universal", 0, 0, 0, 0, 0, FL_HELVETICA, 14, 0}, {0} }; static Fl_Menu tocMenu[] = // Menu items for TOC chooser { {"None", 0, 0, 0, 0, 0, FL_HELVETICA, 14, 0}, {"1 level", 0, 0, 0, 0, 0, FL_HELVETICA, 14, 0}, {"2 levels", 0, 0, 0, 0, 0, FL_HELVETICA, 14, 0}, {"3 levels", 0, 0, 0, 0, 0, FL_HELVETICA, 14, 0}, {"4 Levels", 0, 0, 0, 0, 0, FL_HELVETICA, 14, 0}, {0} }; static Fl_Menu formatMenu[] = // Menu items for header/footer choosers { {"Blank", 0, 0, 0, 0, 0, FL_HELVETICA, 14, 0}, {"Title", 0, 0, 0, 0, 0, FL_HELVETICA, 14, 0}, {"Chapter Title", 0, 0, 0, 0, 0, FL_HELVETICA, 14, 0}, {"Heading", 0, 0, 0, 0, 0, FL_HELVETICA, 14, 0}, {"Logo", 0, 0, 0, 0, 0, FL_HELVETICA, 14, 0}, {"1,2,3,...", 0, 0, 0, 0, 0, FL_HELVETICA, 14, 0}, {"i,ii,iii,...", 0, 0, 0, 0, 0, FL_HELVETICA, 14, 0}, {"I,II,III,...", 0, 0, 0, 0, 0, FL_HELVETICA, 14, 0}, {"a,b,c,...", 0, 0, 0, 0, 0, FL_HELVETICA, 14, 0}, {"A,B,C,...", 0, 0, 0, 0, 0, FL_HELVETICA, 14, 0}, {"Chapter Page", 0, 0, 0, 0, 0, FL_HELVETICA, 14, 0}, {"1/N,2/N,...", 0, 0, 0, 0, 0, FL_HELVETICA, 14, 0}, {"1/C,2/C,...", 0, 0, 0, 0, 0, FL_HELVETICA, 14, 0}, {"Date", 0, 0, 0, 0, 0, FL_HELVETICA, 14, 0}, {"Time", 0, 0, 0, 0, 0, FL_HELVETICA, 14, 0}, {"Date + Time", 0, 0, 0, 0, 0, FL_HELVETICA, 14, 0}, {0} }; static Fl_Menu nupMenu[] = // Menu items for number-up chooser { {"1", 0, 0, 0, 0, 0, FL_HELVETICA, 14, 0}, {"2", 0, 0, 0, 0, 0, FL_HELVETICA, 14, 0}, {"4", 0, 0, 0, 0, 0, FL_HELVETICA, 14, 0}, {"6", 0, 0, 0, 0, 0, FL_HELVETICA, 14, 0}, {"9", 0, 0, 0, 0, 0, FL_HELVETICA, 14, 0}, {"16", 0, 0, 0, 0, 0, FL_HELVETICA, 14, 0}, {0} }; static Fl_Menu typefaceMenu[] = // Menu items for typeface choosers { {"Courier", 0, 0, 0, 0, 0, FL_COURIER, 14, 0}, {"Times", 0, 0, 0, 0, 0, FL_TIMES, 14, 0}, {"Helvetica", 0, 0, 0, 0, 0, FL_HELVETICA, 14, 0}, {"Monospace", 0, 0, 0, 0, 0, FL_COURIER, 14, 0}, {"Serif", 0, 0, 0, 0, 0, FL_HELVETICA, 14, 0}, {"Sans", 0, 0, 0, 0, 0, FL_TIMES, 14, 0}, {0} }; static Fl_Menu fontMenu[] = // Menu items for font choosers { {"Courier", 0, 0, 0, 0, 0, FL_COURIER, 14, 0}, {"Courier-Bold", 0, 0, 0, 0, 0, FL_COURIER_BOLD, 14, 0}, {"Courier-Oblique", 0, 0, 0, 0, 0, FL_COURIER_ITALIC, 14, 0}, {"Courier-BoldOblique", 0, 0, 0, 0, 0, FL_COURIER_BOLD_ITALIC, 14, 0}, {"Times-Roman", 0, 0, 0, 0, 0, FL_TIMES, 14, 0}, {"Times-Bold", 0, 0, 0, 0, 0, FL_TIMES_BOLD, 14, 0}, {"Times-Italic", 0, 0, 0, 0, 0, FL_TIMES_ITALIC, 14, 0}, {"Times-BoldItalic", 0, 0, 0, 0, 0, FL_TIMES_BOLD_ITALIC, 14, 0}, {"Helvetica", 0, 0, 0, 0, 0, FL_HELVETICA, 14, 0}, {"Helvetica-Bold", 0, 0, 0, 0, 0, FL_HELVETICA_BOLD, 14, 0}, {"Helvetica-Oblique", 0, 0, 0, 0, 0, FL_HELVETICA_ITALIC, 14, 0}, {"Helvetica-BoldOblique", 0, 0, 0, 0, 0, FL_HELVETICA_BOLD_ITALIC, 14, 0}, {"Monospace", 0, 0, 0, 0, 0, FL_COURIER, 14, 0}, {"Monospace-Bold", 0, 0, 0, 0, 0, FL_COURIER_BOLD, 14, 0}, {"Monospace-Oblique", 0, 0, 0, 0, 0, FL_COURIER_ITALIC, 14, 0}, {"Monospace-BoldOblique", 0, 0, 0, 0, 0, FL_COURIER_BOLD_ITALIC, 14, 0}, {"Serif-Roman", 0, 0, 0, 0, 0, FL_TIMES, 14, 0}, {"Serif-Bold", 0, 0, 0, 0, 0, FL_TIMES_BOLD, 14, 0}, {"Serif-Italic", 0, 0, 0, 0, 0, FL_TIMES_ITALIC, 14, 0}, {"Serif-BoldItalic", 0, 0, 0, 0, 0, FL_TIMES_BOLD_ITALIC, 14, 0}, {"Sans", 0, 0, 0, 0, 0, FL_HELVETICA, 14, 0}, {"Sans-Bold", 0, 0, 0, 0, 0, FL_HELVETICA_BOLD, 14, 0}, {"Sans-Oblique", 0, 0, 0, 0, 0, FL_HELVETICA_ITALIC, 14, 0}, {"Sans-BoldOblique", 0, 0, 0, 0, 0, FL_HELVETICA_BOLD_ITALIC, 14, 0}, {0} }; static Fl_Menu charsetMenu[] = // Menu items for charset chooser { {"cp-874", 0, 0, 0, 0, 0, FL_HELVETICA, 14, 0}, {"cp-1250", 0, 0, 0, 0, 0, FL_HELVETICA, 14, 0}, {"cp-1251", 0, 0, 0, 0, 0, FL_HELVETICA, 14, 0}, {"cp-1252", 0, 0, 0, 0, 0, FL_HELVETICA, 14, 0}, {"cp-1253", 0, 0, 0, 0, 0, FL_HELVETICA, 14, 0}, {"cp-1254", 0, 0, 0, 0, 0, FL_HELVETICA, 14, 0}, {"cp-1255", 0, 0, 0, 0, 0, FL_HELVETICA, 14, 0}, {"cp-1256", 0, 0, 0, 0, 0, FL_HELVETICA, 14, 0}, {"cp-1257", 0, 0, 0, 0, 0, FL_HELVETICA, 14, 0}, {"cp-1258", 0, 0, 0, 0, 0, FL_HELVETICA, 14, 0}, {"iso-8859-1", 0, 0, 0, 0, 0, FL_HELVETICA, 14, 0}, {"iso-8859-2", 0, 0, 0, 0, 0, FL_HELVETICA, 14, 0}, {"iso-8859-3", 0, 0, 0, 0, 0, FL_HELVETICA, 14, 0}, {"iso-8859-4", 0, 0, 0, 0, 0, FL_HELVETICA, 14, 0}, {"iso-8859-5", 0, 0, 0, 0, 0, FL_HELVETICA, 14, 0}, {"iso-8859-6", 0, 0, 0, 0, 0, FL_HELVETICA, 14, 0}, {"iso-8859-7", 0, 0, 0, 0, 0, FL_HELVETICA, 14, 0}, {"iso-8859-8", 0, 0, 0, 0, 0, FL_HELVETICA, 14, 0}, {"iso-8859-9", 0, 0, 0, 0, 0, FL_HELVETICA, 14, 0}, {"iso-8859-14", 0, 0, 0, 0, 0, FL_HELVETICA, 14, 0}, {"iso-8859-15", 0, 0, 0, 0, 0, FL_HELVETICA, 14, 0}, {"koi8-r", 0, 0, 0, 0, 0, FL_HELVETICA, 14, 0}, {"utf-8", 0, 0, 0, 0, 0, FL_HELVETICA, 14, 0}, {0} }; static Fl_Menu modeMenu[] = // Menu items for mode chooser { {"Document", 0, 0, 0, 0, 0, FL_HELVETICA, 14, 0}, {"Outline", 0, 0, 0, 0, 0, FL_HELVETICA, 14, 0}, {"Full-Screen", 0, 0, 0, 0, 0, FL_HELVETICA, 14, 0}, {0} }; static Fl_Menu layoutMenu[] = // Menu items for layout chooser { {"Single", 0, 0, 0, 0, 0, FL_HELVETICA, 14, 0}, {"One Column", 0, 0, 0, 0, 0, FL_HELVETICA, 14, 0}, {"Two Column Left", 0, 0, 0, 0, 0, FL_HELVETICA, 14, 0}, {"Two Column Right", 0, 0, 0, 0, 0, FL_HELVETICA, 14, 0}, {0} }; static Fl_Menu firstMenu[] = // Menu items for first chooser { {"Page 1", 0, 0, 0, 0, 0, FL_HELVETICA, 14, 0}, {"TOC", 0, 0, 0, 0, 0, FL_HELVETICA, 14, 0}, {"Chapter 1", 0, 0, 0, 0, 0, FL_HELVETICA, 14, 0}, {0} }; static Fl_Menu effectMenu[] = // Menu items for effect chooser { {"None", 0, 0, 0, 0, 0, FL_HELVETICA, 14, 0}, {"Box Inward", 0, 0, 0, 0, 0, FL_HELVETICA, 14, 0}, {"Box Outward", 0, 0, 0, 0, 0, FL_HELVETICA, 14, 0}, {"Dissolve", 0, 0, 0, 0, 0, FL_HELVETICA, 14, 0}, {"Glitter Down", 0, 0, 0, 0, 0, FL_HELVETICA, 14, 0}, {"Glitter Down+Right", 0, 0, 0, 0, 0, FL_HELVETICA, 14, 0}, {"Glitter Right", 0, 0, 0, 0, 0, FL_HELVETICA, 14, 0}, {"Horizontal Blinds", 0, 0, 0, 0, 0, FL_HELVETICA, 14, 0}, {"Horizontal Sweep Inward", 0, 0, 0, 0, 0, FL_HELVETICA, 14, 0}, {"Horizontal Sweep Outward", 0, 0, 0, 0, 0, FL_HELVETICA, 14, 0}, {"Vertical Blinds", 0, 0, 0, 0, 0, FL_HELVETICA, 14, 0}, {"Vertical Sweep Inward", 0, 0, 0, 0, 0, FL_HELVETICA, 14, 0}, {"Vertical Sweep Outward ", 0, 0, 0, 0, 0, FL_HELVETICA, 14, 0}, {"Wipe Down", 0, 0, 0, 0, 0, FL_HELVETICA, 14, 0}, {"Wipe Left", 0, 0, 0, 0, 0, FL_HELVETICA, 14, 0}, {"Wipe Right", 0, 0, 0, 0, 0, FL_HELVETICA, 14, 0}, {"Wipe Up", 0, 0, 0, 0, 0, FL_HELVETICA, 14, 0}, {0} }; #ifdef __APPLE__ // Support opening of books via the finder... fl_open_callback(appleOpenCB); #endif // __APPLE__ // Enable/disable tooltips... Fl_Tooltip::enable(Tooltips); // Update the theme Fl::scheme("gtk+"); // // Create a dialog window... // window = new Fl_Double_Window(505, 370, "HTMLDOC " SVERSION); window->callback((Fl_Callback *)closeBookCB, this); controls = new Fl_Group(0, 0, 505, 330); tabs = new Fl_Tabs(10, 10, 485, 285); // // Input tab... // inputTab = new Fl_Group(10, 35, 485, 260, "Input"); group = new Fl_Group(140, 45, 250, 20, "Document Type: "); group->align(FL_ALIGN_LEFT); typeBook = new Fl_Round_Button(140, 45, 60, 20, "Book"); typeBook->type(FL_RADIO_BUTTON); typeBook->setonly(); typeBook->callback((Fl_Callback *)docTypeCB, this); typeBook->tooltip("Convert chapters into a book."); typeContinuous = new Fl_Round_Button(200, 45, 100, 20, "Continuous"); typeContinuous->type(FL_RADIO_BUTTON); typeContinuous->callback((Fl_Callback *)docTypeCB, this); typeContinuous->tooltip("Convert web pages without page breaks."); typeWebPage = new Fl_Round_Button(300, 45, 90, 20, "Web Page"); typeWebPage->type(FL_RADIO_BUTTON); typeWebPage->callback((Fl_Callback *)docTypeCB, this); typeWebPage->tooltip("Convert web pages with page breaks."); group->end(); group = new Fl_Group(140, 70, 250, 20, "Input Files: "); group->align(FL_ALIGN_LEFT); group->end(); inputFiles = new Fl_File_Browser(140, 70, 250, 150); inputFiles->iconsize(20); inputFiles->type(FL_MULTI_BROWSER); inputFiles->callback((Fl_Callback *)inputFilesCB, this); inputFiles->when(FL_WHEN_RELEASE | FL_WHEN_NOT_CHANGED); inputFiles->tooltip("This is the list of HTML files and URLs that will be converted."); addFile = new Fl_Button(390, 70, 95, 25, "Add Files..."); addFile->callback((Fl_Callback *)addFileCB, this); addFile->tooltip("Add HTML files to the list."); addURL = new Fl_Button(390, 95, 95, 25, "Add URL..."); addURL->callback((Fl_Callback *)addURLCB, this); addURL->tooltip("Add a URL to the list."); editFile = new Fl_Button(390, 120, 95, 25, "Edit Files..."); editFile->deactivate(); editFile->callback((Fl_Callback *)editFilesCB, this); editFile->tooltip("Edit HTML files in the list."); deleteFile = new Fl_Button(390, 145, 95, 25, "Delete Files"); deleteFile->deactivate(); deleteFile->callback((Fl_Callback *)deleteFilesCB, this); deleteFile->tooltip("Remove HTML files and URLs from the list."); moveUpFile = new Fl_Button(390, 170, 95, 25, "Move Up"); moveUpFile->deactivate(); moveUpFile->callback((Fl_Callback *)moveUpFilesCB, this); moveUpFile->tooltip("Move HTML files and URLs up in the list."); moveDownFile = new Fl_Button(390, 195, 95, 25, "Move Down"); moveDownFile->deactivate(); moveDownFile->callback((Fl_Callback *)moveDownFilesCB, this); moveDownFile->tooltip("Move HTML files and URLs down in the list."); logoImage = new Fl_Input(140, 230, 250, 25, "Logo Image: "); logoImage->when(FL_WHEN_CHANGED); logoImage->callback((Fl_Callback *)logoImageCB, this); logoImage->tooltip("The logo image for the navigation bar and header or footer."); logoBrowse = new Fl_Button(390, 230, 95, 25, "Browse..."); logoBrowse->callback((Fl_Callback *)logoImageCB, this); logoBrowse->tooltip("Choose a logo image file."); titleImage = new Fl_Input(140, 260, 250, 25, "Title File/Image: "); titleImage->when(FL_WHEN_CHANGED); titleImage->callback((Fl_Callback *)titleImageCB, this); titleImage->tooltip("The title image or HTML file for the title page."); titleBrowse = new Fl_Button(390, 260, 95, 25, "Browse..."); titleBrowse->callback((Fl_Callback *)titleImageCB, this); titleBrowse->tooltip("Choose a title file."); inputTab->end(); inputTab->resizable(inputFiles); // // Output tab... // outputTab = new Fl_Group(10, 35, 485, 260, "Output"); outputTab->hide(); group = new Fl_Group(140, 45, 265, 20, "Output To: "); group->align(FL_ALIGN_LEFT); outputFile = new Fl_Round_Button(140, 45, 50, 20, "File"); outputFile->type(FL_RADIO_BUTTON); outputFile->setonly(); outputFile->callback((Fl_Callback *)outputTypeCB, this); outputFile->tooltip("Generate a single output file."); outputDirectory = new Fl_Round_Button(190, 45, 105, 20, "Directory"); outputDirectory->type(FL_RADIO_BUTTON); outputDirectory->callback((Fl_Callback *)outputTypeCB, this); outputDirectory->tooltip("Generate multiple output files in a directory."); group->end(); outputPath = new Fl_Input(140, 70, 250, 25, "Output Path: "); outputPath->when(FL_WHEN_CHANGED); outputPath->callback((Fl_Callback *)outputPathCB, this); outputPath->tooltip("The name of the output file or directory."); outputBrowse = new Fl_Button(390, 70, 95, 25, "Browse..."); outputBrowse->callback((Fl_Callback *)outputPathCB, this); outputBrowse->tooltip("Choose an output file."); group = new Fl_Group(140, 100, 325, 20, "Output Format: "); group->align(FL_ALIGN_LEFT); typeEPUB = new Fl_Round_Button(140, 100, 65, 20, "EPUB"); typeEPUB->type(FL_RADIO_BUTTON); typeEPUB->callback((Fl_Callback *)outputFormatCB, this); typeEPUB->tooltip("Generate EPUB file(s)."); typeHTML = new Fl_Round_Button(205, 100, 65, 20, "HTML"); typeHTML->type(FL_RADIO_BUTTON); typeHTML->setonly(); typeHTML->callback((Fl_Callback *)outputFormatCB, this); typeHTML->tooltip("Generate HTML file(s)."); typeHTMLSep = new Fl_Round_Button(270, 100, 95, 20, "Split HTML"); typeHTMLSep->type(FL_RADIO_BUTTON); typeHTMLSep->callback((Fl_Callback *)outputFormatCB, this); typeHTMLSep->tooltip("Generate separate HTML files for each TOC heading."); typePS = new Fl_Round_Button(365, 100, 45, 20, "PS"); typePS->type(FL_RADIO_BUTTON); typePS->callback((Fl_Callback *)outputFormatCB, this); typePS->tooltip("Generate Adobe PostScript(r) file(s)."); typePDF = new Fl_Round_Button(410, 100, 55, 20, "PDF"); typePDF->type(FL_RADIO_BUTTON); typePDF->callback((Fl_Callback *)outputFormatCB, this); typePDF->tooltip("Generate an Adobe Acrobat file."); group->end(); group = new Fl_Group(140, 125, 265, 20, "Output Options: "); group->align(FL_ALIGN_LEFT); group->end(); grayscale = new Fl_Check_Button(140, 125, 90, 20, "Grayscale"); grayscale->callback((Fl_Callback *)changeCB, this); grayscale->tooltip("Check to produce grayscale output."); titlePage = new Fl_Check_Button(230, 125, 90, 20, "Title Page"); titlePage->callback((Fl_Callback *)changeCB, this); titlePage->tooltip("Check to generate a title page."); jpegCompress = new Fl_Check_Button(320, 125, 140, 20, "JPEG Big Images"); jpegCompress->callback((Fl_Callback *)jpegCB, this); jpegCompress->tooltip("Check to reduce the size of large images using the JPEG algorithm."); compGroup = new Fl_Group(140, 150, 345, 40, "Compression: \n "); compGroup->align(FL_ALIGN_LEFT); compression = new Fl_Slider(140, 150, 345, 20); compression->type(FL_HOR_NICE_SLIDER); compression->minimum(0.0); compression->maximum(9.0); compression->value(1.0); compression->step(1.0); compression->callback((Fl_Callback *)changeCB, this); compression->tooltip("Reduce the size of output files."); label = new Fl_Box(140, 170, 30, 10, "None"); label->align(FL_ALIGN_LEFT | FL_ALIGN_INSIDE); label->labelsize(10); label = new Fl_Box(170, 170, 30, 10, "Fast"); label->align(FL_ALIGN_LEFT | FL_ALIGN_INSIDE); label->labelsize(10); label = new Fl_Box(455, 170, 30, 10, "Best"); label->align(FL_ALIGN_RIGHT | FL_ALIGN_INSIDE); label->labelsize(10); compGroup->end(); jpegGroup = new Fl_Group(140, 185, 345, 40, "JPEG Quality: \n "); jpegGroup->align(FL_ALIGN_LEFT); jpegQuality = new Fl_Value_Slider(140, 185, 345, 20); jpegQuality->type(FL_HOR_NICE_SLIDER); jpegQuality->minimum(50.0); jpegQuality->maximum(100.0); jpegQuality->value(90.0); jpegQuality->step(1.0); jpegQuality->callback((Fl_Callback *)changeCB, this); jpegQuality->tooltip("Set the quality of images using JPEG compression.\n" "(lower quality produces smaller output)"); label = new Fl_Box(175, 205, 40, 10, "Good"); label->align(FL_ALIGN_LEFT | FL_ALIGN_INSIDE); label->labelsize(10); label = new Fl_Box(445, 205, 40, 10, "Best"); label->align(FL_ALIGN_RIGHT | FL_ALIGN_INSIDE); label->labelsize(10); jpegGroup->end(); outputTab->end(); // // Page tab... // pageTab = new Fl_Group(10, 35, 485, 260, "Page"); pageTab->hide(); pageSize = new Fl_Input(145, 45, 100, 25, "Page Size: "); pageSize->when(FL_WHEN_CHANGED); pageSize->callback((Fl_Callback *)changeCB, this); pageSize->tooltip("Enter the page size."); pageSizeMenu = new Fl_Menu_Button(245, 45, 25, 25, ""); pageSizeMenu->menu(sizeMenu); pageSizeMenu->callback((Fl_Callback *)sizeCB, this); pageSizeMenu->tooltip("Click to choose a standard size."); pageDuplex = new Fl_Check_Button(275, 48, 70, 20, "2-Sided"); pageDuplex->callback((Fl_Callback *)changeCB, this); pageDuplex->tooltip("Produce output suitable for double-sided printing."); landscape = new Fl_Check_Button(350, 48, 90, 20, "Landscape"); landscape->callback((Fl_Callback *)changeCB, this); landscape->tooltip("Check to rotate the output to landscape orientation."); pageTop = new Fl_Input(230, 75, 60, 25, "Top"); pageTop->when(FL_WHEN_CHANGED); pageTop->callback((Fl_Callback *)changeCB, this); pageTop->tooltip("Enter the top margin."); pageLeft = new Fl_Input(195, 105, 60, 25, "Left"); pageLeft->when(FL_WHEN_CHANGED); pageLeft->callback((Fl_Callback *)changeCB, this); pageLeft->tooltip("Enter the left margin."); pageRight = new Fl_Input(260, 105, 60, 25, "Right"); pageRight->when(FL_WHEN_CHANGED); pageRight->align(FL_ALIGN_RIGHT); pageRight->callback((Fl_Callback *)changeCB, this); pageRight->tooltip("Enter the right margin."); pageBottom = new Fl_Input(230, 135, 60, 25, "Bottom"); pageBottom->when(FL_WHEN_CHANGED); pageBottom->callback((Fl_Callback *)changeCB, this); pageBottom->tooltip("Enter the bottom margin."); pageHeaderLeft = new Fl_Choice(145, 165, 110, 25, "Header: "); pageHeaderLeft->menu(formatMenu); pageHeaderLeft->callback((Fl_Callback *)changeCB, this); pageHeaderLeft->tooltip("Choose the left header."); pageHeaderCenter = new Fl_Choice(260, 165, 110, 25); pageHeaderCenter->menu(formatMenu); pageHeaderCenter->callback((Fl_Callback *)changeCB, this); pageHeaderCenter->tooltip("Choose the center header."); pageHeaderRight = new Fl_Choice(375, 165, 110, 25); pageHeaderRight->menu(formatMenu); pageHeaderRight->callback((Fl_Callback *)changeCB, this); pageHeaderRight->tooltip("Choose the right header."); pageHeader1Left = new Fl_Choice(145, 195, 110, 25, "Header (1st Page): "); pageHeader1Left->menu(formatMenu); pageHeader1Left->callback((Fl_Callback *)changeCB, this); pageHeader1Left->tooltip("Choose the left header1."); pageHeader1Center = new Fl_Choice(260, 195, 110, 25); pageHeader1Center->menu(formatMenu); pageHeader1Center->callback((Fl_Callback *)changeCB, this); pageHeader1Center->tooltip("Choose the center header1."); pageHeader1Right = new Fl_Choice(375, 195, 110, 25); pageHeader1Right->menu(formatMenu); pageHeader1Right->callback((Fl_Callback *)changeCB, this); pageHeader1Right->tooltip("Choose the right header1."); pageFooterLeft = new Fl_Choice(145, 225, 110, 25, "Footer: "); pageFooterLeft->menu(formatMenu); pageFooterLeft->callback((Fl_Callback *)changeCB, this); pageFooterLeft->tooltip("Choose the left footer."); pageFooterCenter = new Fl_Choice(260, 225, 110, 25); pageFooterCenter->menu(formatMenu); pageFooterCenter->callback((Fl_Callback *)changeCB, this); pageFooterCenter->tooltip("Choose the center header."); pageFooterRight = new Fl_Choice(375, 225, 110, 25); pageFooterRight->menu(formatMenu); pageFooterRight->callback((Fl_Callback *)changeCB, this); pageFooterRight->tooltip("Choose the right header."); numberUp = new Fl_Choice(145, 255, 50, 25, "Number Up: "); numberUp->menu(nupMenu); numberUp->callback((Fl_Callback *)changeCB, this); numberUp->tooltip("Set the number of pages on each sheet."); pageTab->end(); // // TOC tab... // tocTab = new Fl_Group(10, 35, 485, 260, "TOC"); tocTab->hide(); tocLevels = new Fl_Choice(140, 45, 100, 25, "Table of Contents: "); tocLevels->menu(tocMenu); tocLevels->callback((Fl_Callback *)tocCB, this); tocLevels->tooltip("Choose the number of table of contents levels."); numberedToc = new Fl_Check_Button(245, 47, 160, 20, "Numbered Headings"); numberedToc->callback((Fl_Callback *)changeCB, this); numberedToc->tooltip("Check to number all of the headings in the document."); tocHeader = new Fl_Group(140, 75, 345, 25, "Header: "); tocHeader->align(FL_ALIGN_LEFT); tocHeaderLeft = new Fl_Choice(140, 75, 110, 25); tocHeaderLeft->menu(formatMenu); tocHeaderLeft->callback((Fl_Callback *)changeCB, this); tocHeaderLeft->tooltip("Choose the left header."); tocHeaderCenter = new Fl_Choice(255, 75, 110, 25); tocHeaderCenter->menu(formatMenu); tocHeaderCenter->callback((Fl_Callback *)changeCB, this); tocHeaderCenter->tooltip("Choose the center header."); tocHeaderRight = new Fl_Choice(370, 75, 110, 25); tocHeaderRight->menu(formatMenu); tocHeaderRight->callback((Fl_Callback *)changeCB, this); tocHeaderRight->tooltip("Choose the right header."); tocHeader->end(); tocFooter = new Fl_Group(140, 105, 345, 25, "Footer: "); tocFooter->align(FL_ALIGN_LEFT); tocFooterLeft = new Fl_Choice(140, 105, 110, 25, "Footer: "); tocFooterLeft->menu(formatMenu); tocFooterLeft->callback((Fl_Callback *)changeCB, this); tocFooterLeft->tooltip("Choose the left footer."); tocFooterCenter = new Fl_Choice(255, 105, 110, 25); tocFooterCenter->menu(formatMenu); tocFooterCenter->callback((Fl_Callback *)changeCB, this); tocFooterCenter->tooltip("Choose the center footer."); tocFooterRight = new Fl_Choice(370, 105, 110, 25); tocFooterRight->menu(formatMenu); tocFooterRight->callback((Fl_Callback *)changeCB, this); tocFooterRight->tooltip("Choose the right footer."); tocFooter->end(); tocTitle = new Fl_Input(140, 135, 345, 25, "Title: "); tocTitle->when(FL_WHEN_CHANGED); tocTitle->callback((Fl_Callback *)changeCB, this); tocTitle->tooltip("Enter the title of the table of contents."); tocTab->end(); // // Colors tab... // colorsTab = new Fl_Group(10, 35, 485, 260, "Colors"); colorsTab->hide(); bodyColor = new Fl_Input(140, 45, 100, 25, "Body Color: "); bodyColor->when(FL_WHEN_CHANGED); bodyColor->callback((Fl_Callback *)bodyColorCB, this); bodyColor->tooltip("Enter the HTML color for the body (background)."); bodyLookup = new Fl_Button(240, 45, 80, 25, "Lookup..."); bodyLookup->callback((Fl_Callback *)bodyColorCB, this); bodyLookup->tooltip("Click to choose the HTML color for the body (background)."); bodyImage = new Fl_Input(140, 75, 250, 25, "Body Image: "); bodyImage->when(FL_WHEN_CHANGED); bodyImage->callback((Fl_Callback *)bodyImageCB, this); bodyImage->tooltip("Enter the image file for the body (background)."); bodyBrowse = new Fl_Button(390, 75, 95, 25, "Browse..."); bodyBrowse->callback((Fl_Callback *)bodyImageCB, this); bodyBrowse->tooltip("Click to choose the image file for the body (background)."); textColor = new Fl_Input(140, 105, 100, 25, "Text Color: "); textColor->when(FL_WHEN_CHANGED); textColor->callback((Fl_Callback *)textColorCB, this); textColor->tooltip("Enter the HTML color for the text."); textLookup = new Fl_Button(240, 105, 80, 25, "Lookup..."); textLookup->callback((Fl_Callback *)textColorCB, this); textLookup->tooltip("Click to choose the HTML color for the text."); linkColor = new Fl_Input(140, 135, 100, 25, "Link Color: "); linkColor->when(FL_WHEN_CHANGED); linkColor->callback((Fl_Callback *)linkColorCB, this); linkColor->tooltip("Enter the HTML color for links."); linkLookup = new Fl_Button(240, 135, 80, 25, "Lookup..."); linkLookup->callback((Fl_Callback *)linkColorCB, this); linkLookup->tooltip("Click to choose the HTML color for links."); linkStyle = new Fl_Choice(140, 165, 100, 25, "Link Style: "); linkStyle->add("Plain"); linkStyle->add("Underline"); linkStyle->callback((Fl_Callback *)changeCB, this); linkStyle->tooltip("Choose the appearance of links."); colorsTab->end(); // // Fonts tab... // fontsTab = new Fl_Group(10, 35, 485, 260, "Fonts"); fontsTab->hide(); fontBaseSize = new Fl_Counter(200, 45, 150, 25, "Base Font Size: "); fontBaseSize->callback((Fl_Callback *)changeCB, this); fontBaseSize->minimum(4.0); fontBaseSize->maximum(24.0); fontBaseSize->step(0.1); fontBaseSize->value(11.0); fontBaseSize->align(FL_ALIGN_LEFT); fontBaseSize->tooltip("Set the default size of text."); fontSpacing = new Fl_Counter(200, 75, 150, 25, "Line Spacing: "); fontSpacing->callback((Fl_Callback *)changeCB, this); fontSpacing->minimum(1.0); fontSpacing->maximum(3.0); fontSpacing->step(0.1); fontSpacing->value(1.2); fontSpacing->align(FL_ALIGN_LEFT); fontSpacing->tooltip("Set the spacing between lines of text."); bodyFont = new Fl_Choice(200, 105, 100, 25, "Body Typeface: "); bodyFont->menu(typefaceMenu); bodyFont->callback((Fl_Callback *)changeCB, this); bodyFont->tooltip("Choose the default typeface (font) of text."); headingFont = new Fl_Choice(200, 135, 100, 25, "Heading Typeface: "); headingFont->menu(typefaceMenu); headingFont->callback((Fl_Callback *)changeCB, this); headingFont->tooltip("Choose the default typeface (font) of headings."); headFootSize = new Fl_Counter(200, 165, 150, 25, "Header/Footer Size: "); headFootSize->callback((Fl_Callback *)changeCB, this); headFootSize->minimum(4.0); headFootSize->maximum(24.0); headFootSize->step(0.1); headFootSize->value(11.0); headFootSize->align(FL_ALIGN_LEFT); headFootSize->tooltip("Set the size of header and footer text."); headFootFont = new Fl_Choice(200, 195, 220, 25, "Header/Footer Font: "); headFootFont->menu(fontMenu); headFootFont->callback((Fl_Callback *)changeCB, this); headFootFont->tooltip("Choose the font for header and footer text."); charset = new Fl_Choice(200, 225, 110, 25, "Character Set: "); charset->menu(charsetMenu); charset->callback((Fl_Callback *)changeCB, this); charset->tooltip("Choose the encoding of text."); group = new Fl_Group(200, 255, 285, 25, "Options: "); group->align(FL_ALIGN_LEFT); embedFonts = new Fl_Check_Button(200, 255, 110, 25, "Embed Fonts"); embedFonts->callback((Fl_Callback *)changeCB, this); embedFonts->tooltip("Check to embed fonts in the output file."); group->end(); fontsTab->end(); // // PostScript tab... // psTab = new Fl_Group(10, 35, 485, 260, "PS"); psTab->hide(); psLevel = new Fl_Group(140, 45, 310, 20, "PostScript: "); psLevel->align(FL_ALIGN_LEFT); ps1 = new Fl_Round_Button(140, 45, 70, 20, "Level 1"); ps1->type(FL_RADIO_BUTTON); ps1->callback((Fl_Callback *)psCB, this); ps1->tooltip("Produce PostScript Level 1 output."); ps2 = new Fl_Round_Button(210, 45, 70, 20, "Level 2"); ps2->type(FL_RADIO_BUTTON); ps2->callback((Fl_Callback *)psCB, this); ps2->tooltip("Produce PostScript Level 2 output.\n" "(most common)"); ps3 = new Fl_Round_Button(280, 45, 70, 20, "Level 3"); ps3->type(FL_RADIO_BUTTON); ps3->callback((Fl_Callback *)psCB, this); ps3->tooltip("Produce PostScript Level 3 output."); psLevel->end(); psCommands = new Fl_Check_Button(140, 70, 310, 20, "Send Printer Commands"); psCommands->callback((Fl_Callback *)changeCB, this); psCommands->tooltip("Include PostScript commands to set the media size, etc."); xrxComments = new Fl_Check_Button(140, 95, 310, 20, "Include Xerox Job Comments"); xrxComments->callback((Fl_Callback *)changeCB, this); xrxComments->tooltip("Include Xerox job comments to set the media size, etc."); psTab->end(); // // PDF tab... // pdfTab = new Fl_Group(10, 35, 485, 260, "PDF"); pdfTab->hide(); pdfVersion = new Fl_Group(140, 45, 310, 40, "PDF Version: \n "); pdfVersion->align(FL_ALIGN_LEFT); pdf11 = new Fl_Round_Button(140, 45, 125, 20, "1.1 (Acrobat 2.x)"); pdf11->type(FL_RADIO_BUTTON); pdf11->callback((Fl_Callback *)pdfCB, this); pdf11->tooltip("Produce PDF files for Acrobat 2.x."); pdf12 = new Fl_Round_Button(270, 45, 125, 20, "1.2 (Acrobat 3.0)"); pdf12->type(FL_RADIO_BUTTON); pdf12->callback((Fl_Callback *)pdfCB, this); pdf12->tooltip("Produce PDF files for Acrobat 3.0."); pdf13 = new Fl_Round_Button(140, 65, 125, 20, "1.3 (Acrobat 4.0)"); pdf13->type(FL_RADIO_BUTTON); pdf13->callback((Fl_Callback *)pdfCB, this); pdf13->tooltip("Produce PDF files for Acrobat 4.0."); pdf14 = new Fl_Round_Button(270, 65, 125, 20, "1.4 (Acrobat 5.0)"); pdf14->type(FL_RADIO_BUTTON); pdf14->callback((Fl_Callback *)pdfCB, this); pdf14->tooltip("Produce PDF files for Acrobat 5.0."); pdfVersion->end(); pageMode = new Fl_Choice(140, 90, 120, 25, "Page Mode: "); pageMode->menu(modeMenu); pageMode->callback((Fl_Callback *)changeCB, this); pageMode->tooltip("Choose the initial viewing mode for the file."); pageLayout = new Fl_Choice(140, 120, 150, 25, "Page Layout: "); pageLayout->menu(layoutMenu); pageLayout->callback((Fl_Callback *)changeCB, this); pageLayout->tooltip("Choose the initial page layout for the file."); firstPage = new Fl_Choice(140, 150, 100, 25, "First Page: "); firstPage->menu(firstMenu); firstPage->callback((Fl_Callback *)changeCB, this); firstPage->tooltip("Choose the initial page that will be shown."); pageEffect = new Fl_Choice(140, 180, 210, 25, "Page Effect: "); pageEffect->menu(effectMenu); pageEffect->callback((Fl_Callback *)effectCB, this); pageEffect->tooltip("Choose the page transition effect."); pageDuration = new Fl_Value_Slider(140, 210, 345, 20, "Page Duration: "); pageDuration->align(FL_ALIGN_LEFT); pageDuration->type(FL_HOR_NICE_SLIDER); pageDuration->minimum(1.0); pageDuration->maximum(60.0); pageDuration->value(10.0); pageDuration->step(1.0); pageDuration->callback((Fl_Callback *)changeCB, this); pageDuration->tooltip("Set the amount of time each page is visible."); effectDuration = new Fl_Value_Slider(140, 235, 345, 20, "Effect Duration: "); effectDuration->align(FL_ALIGN_LEFT); effectDuration->type(FL_HOR_NICE_SLIDER); effectDuration->minimum(0.5); effectDuration->maximum(5.0); effectDuration->value(1.0); effectDuration->step(0.1); effectDuration->callback((Fl_Callback *)changeCB, this); effectDuration->tooltip("Set the amount of time to use for the page transition effect."); group = new Fl_Group(140, 260, 350, 25, "Options: "); group->align(FL_ALIGN_LEFT); links = new Fl_Check_Button(140, 260, 110, 25, "Include Links"); links->callback((Fl_Callback *)changeCB, this); links->tooltip("Check to include hyperlinks in the output file."); group->end(); pdfTab->end(); // // Security tab... // securityTab = new Fl_Group(10, 35, 485, 260, "Security"); securityTab->hide(); encryption = new Fl_Group(140, 45, 310, 20, "Encryption: "); encryption->align(FL_ALIGN_LEFT); encryptionNo = new Fl_Round_Button(140, 45, 40, 20, "No"); encryptionNo->type(FL_RADIO_BUTTON); encryptionNo->set(); encryptionNo->callback((Fl_Callback *)encryptionCB, this); encryptionNo->tooltip("Select to disable encryption (scrambling) of the output file."); encryptionYes = new Fl_Round_Button(180, 45, 45, 20, "Yes"); encryptionYes->type(FL_RADIO_BUTTON); encryptionYes->callback((Fl_Callback *)encryptionCB, this); encryptionYes->tooltip("Select to enable encryption (scrambling) of the output file.\n" "(128-bit encryption for Acrobat 5.0, 40-bit for older versions.)"); encryption->end(); permissions = new Fl_Group(140, 70, 310, 40, "Permissions: "); permissions->align(FL_ALIGN_LEFT); permPrint = new Fl_Check_Button(140, 70, 80, 20, "Print"); permPrint->tooltip("Check to allow the user to print the output file."); permModify = new Fl_Check_Button(220, 70, 80, 20, "Modify"); permModify->tooltip("Check to allow the user to modify the output file."); permCopy = new Fl_Check_Button(140, 90, 80, 20, "Copy"); permCopy->tooltip("Check to allow the user to copy text and images from the output file."); permAnnotate = new Fl_Check_Button(220, 90, 80, 20, "Annotate"); permAnnotate->tooltip("Check to allow the user to annotate the output file."); permissions->end(); ownerPassword = new Fl_Secret_Input(140, 115, 150, 25, "Owner Password: "); ownerPassword->maximum_size(32); ownerPassword->tooltip("Enter the password required to modify the file.\n" "(leave blank for a random password)"); userPassword = new Fl_Secret_Input(140, 145, 150, 25, "User Password: "); userPassword->maximum_size(32); userPassword->tooltip("Enter the password required to open the file.\n" "(leave blank for no password)"); securityTab->end(); // // Options tab... // optionsTab = new Fl_Group(10, 35, 485, 260, "Options"); optionsTab->hide(); htmlEditor = new Fl_Input(140, 45, 250, 25, "HTML Editor: "); htmlEditor->value(HTMLEditor); htmlEditor->when(FL_WHEN_CHANGED); htmlEditor->callback((Fl_Callback *)htmlEditorCB, this); htmlEditor->tooltip("Enter the command used to edit HTML files.\n" "(use \"%s\" to insert the filename)"); htmlBrowse = new Fl_Button(390, 45, 95, 25, "Browse..."); htmlBrowse->callback((Fl_Callback *)htmlEditorCB, this); htmlBrowse->tooltip("Click to choose the HTML editor."); browserWidth = new Fl_Value_Slider(140, 75, 345, 20, "Browser Width: "); browserWidth->align(FL_ALIGN_LEFT); browserWidth->type(FL_HOR_NICE_SLIDER); browserWidth->minimum(300.0); browserWidth->maximum(1200.0); browserWidth->value(_htmlBrowserWidth); browserWidth->step(5.0); browserWidth->callback((Fl_Callback *)changeCB, this); browserWidth->tooltip("Set the target browser width in pixels.\n" "(this determines the page scaling of images)"); path = new Fl_Input(140, 100, 345, 25, "Search Path: "); path->value(Path); path->maximum_size(sizeof(Path) - 1); path->when(FL_WHEN_CHANGED); path->callback((Fl_Callback *)changeCB, this); path->tooltip("Enter one or more directories or URLs to search for files.\n" "(separate each directory or URL with the ';' character)"); proxy = new Fl_Input(140, 130, 345, 25, "HTTP Proxy URL: "); proxy->value(Proxy); proxy->maximum_size(sizeof(Proxy) - 1); proxy->when(FL_WHEN_CHANGED); proxy->callback((Fl_Callback *)changeCB, this); proxy->tooltip("Enter a URL for your HTTP proxy server.\n" "(http://server:port)"); group = new Fl_Group(140, 160, 350, 80, "GUI Options: \n\n\n\n\n"); group->align(FL_ALIGN_LEFT); tooltips = new Fl_Check_Button(140, 160, 75, 20, "Tooltips"); tooltips->callback((Fl_Callback *)tooltipCB, this); tooltips->value(Tooltips); tooltips->tooltip("Check to show tooltips."); strict_html = new Fl_Check_Button(140, 180, 100, 20, "Strict HTML"); strict_html->value(StrictHTML); strict_html->tooltip("Check to require strict HTML conformance."); overflow_errors = new Fl_Check_Button(140, 200, 135, 20, "Error on Overflow"); overflow_errors->value(OverflowErrors); overflow_errors->tooltip("Check to display an error when the HTML content\n" "is too large to fit on the page."); group->end(); showAbout = new Fl_Button(75, 260, 130, 25, "About HTMLDOC"); showAbout->callback((Fl_Callback *)showAboutCB); showAbout->tooltip("Click to show information about HTMLDOC."); showLicense = new Fl_Button(215, 260, 70, 25, "License"); showLicense->callback((Fl_Callback *)showLicenseCB); showLicense->tooltip("Click to show the software license."); saveOptions = new Fl_Button(295, 260, 190, 25, "Save Options and Defaults"); saveOptions->callback((Fl_Callback *)saveOptionsCB, this); saveOptions->tooltip("Click to save the current options."); optionsTab->end(); tabs->end(); // // Button bar... // bookHelp = new Fl_Button(10, 305, 55, 25, "Help"); bookHelp->shortcut(FL_F + 1); bookHelp->callback((Fl_Callback *)helpCB, this); bookNew = new Fl_Button(70, 305, 50, 25, "New"); bookNew->shortcut(FL_CTRL | 'n'); bookNew->callback((Fl_Callback *)newBookCB, this); bookOpen = new Fl_Button(125, 305, 65, 25, "Open..."); bookOpen->shortcut(FL_CTRL | 'o'); bookOpen->callback((Fl_Callback *)openBookCB, this); bookSave = new Fl_Button(195, 305, 55, 25, "Save"); bookSave->shortcut(FL_CTRL | 's'); bookSave->callback((Fl_Callback *)saveBookCB, this); bookSaveAs = new Fl_Button(255, 305, 85, 25, "Save As..."); bookSaveAs->shortcut(FL_CTRL | FL_SHIFT | 's'); bookSaveAs->callback((Fl_Callback *)saveAsBookCB, this); bookGenerate = new Fl_Button(345, 305, 85, 25, "Generate"); bookGenerate->shortcut(FL_CTRL | 'g'); bookGenerate->callback((Fl_Callback *)generateBookCB, this); bookClose = new Fl_Button(435, 305, 60, 25, "Close"); bookClose->shortcut(FL_CTRL | 'q'); bookClose->callback((Fl_Callback *)closeBookCB, this); controls->end(); // // Progress bar... // progressBar = new Fl_Progress(10, 340, 485, 20, "HTMLDOC " SVERSION " Ready."); window->end(); // Set the class name to "htmldoc". window->xclass("htmldoc"); # ifdef WIN32 // Load the HTMLDOC icon image... window->icon((char *)LoadImage(fl_display, MAKEINTRESOURCE(IDI_ICON), IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR)); # elif defined(__APPLE__) // MacOS X gets the icon from the application bundle... # elif defined(HAVE_LIBXPM) // X11 w/Xpm library Pixmap pixmap, mask; // Icon pixmaps XpmAttributes attrs; // Attributes of icon // Open the X display and load the HTMLDOC icon image... fl_open_display(); memset(&attrs, 0, sizeof(attrs)); XpmCreatePixmapFromData(fl_display, DefaultRootWindow(fl_display), (char **)htmldoc_xpm, &pixmap, &mask, &attrs); window->icon((char *)pixmap); # else // X11 w/o Xpm library // Open the X display and load the HTMLDOC icon image... fl_open_display(); window->icon((char *)XCreateBitmapFromData(fl_display, DefaultRootWindow(fl_display), (char *)htmldoc_bits, htmldoc_width, htmldoc_height)); # endif // WIN32 window->resizable(tabs); window->size_range(470, 360); // File chooser, icons, help dialog, error window... fc = new Fl_File_Chooser(".", "*", Fl_File_Chooser::SINGLE, "Title"); fc->iconsize(20); if (!Fl_File_Icon::first()) Fl_File_Icon::load_system_icons(); icon = Fl_File_Icon::find("file.html", Fl_File_Icon::PLAIN); help = new Fl_Help_Dialog(); error_window = new Fl_Window(400, 300, "Errors"); error_list = new Fl_Browser(10, 10, 380, 245); error_ok = new Fl_Button(335, 265, 55, 25, "Close"); error_ok->callback((Fl_Callback *)errorCB, this); error_window->end(); error_window->resizable(error_list); // // Load the given book or create a new one... // book_changed = 0; book_filename[0] = '\0'; #ifdef __APPLE__ if (apple_filename) { loadBook(apple_filename); free(apple_filename); apple_filename = NULL; } else #endif // __APPLE__ if (filename == NULL) newBookCB(NULL, this); else loadBook(filename); // Show the window... show(); #if 0 // Wait for the window to be drawn... while (window->damage()) Fl::check(); #endif // 0 } // // '~GUI()' - Destroy the HTMLDOC GUI. // GUI::~GUI(void) { delete window; delete fc; delete help; delete error_window; while (Fl_File_Icon::first()) delete Fl_File_Icon::first(); } // // 'GUI::show()' - Display the window. // void GUI::show(void) { static char *htmldoc[1] = { (char *)"htmldoc" }; // argv[] array window->show(1, htmldoc); } // // 'GUI::progress()' - Update the progress bar on the GUI. // void GUI::progress(int percent, // I - Percent complete const char *text) // I - Text prompt { if (text != NULL) progressBar->label(text); else if (percent == 0) progressBar->label("HTMLDOC " SVERSION " Ready."); if ((percent - (int)progressBar->value()) >= 10 || percent < (int)progressBar->value()) progressBar->value(percent); if (progressBar->damage()) Fl::check(); } // // 'GUI::title()' - Set the title bar of the window. // void GUI::title(const char *filename,// Name of file being edited int changed) // Whether or not the file is modified { book_changed = changed; if (filename == NULL || filename[0] == '\0') { book_filename[0] = '\0'; strlcpy(title_string, "NewBook", sizeof(title_string)); } else { strlcpy(book_filename, filename, sizeof(book_filename)); strlcpy(title_string, file_basename(filename), sizeof(title_string)); } if (changed) strlcat(title_string, "(modified) - ", sizeof(title_string)); else strlcat(title_string, " - ", sizeof(title_string)); strlcat(title_string, "HTMLDOC " SVERSION, sizeof(title_string)); window->label(title_string); if (window->visible()) Fl::check(); } // // 'GUI::loadSettings()' - Load the current settings into the HTMLDOC globals. // void GUI::loadSettings() { char temp[4]; // Format string static const char *formats = ".tchl1iIaAC/:dTD"; // Format characters set_page_size((char *)pageSize->value()); PageLeft = get_measurement((char *)pageLeft->value()); PageRight = get_measurement((char *)pageRight->value()); PageTop = get_measurement((char *)pageTop->value()); PageBottom = get_measurement((char *)pageBottom->value()); PageDuplex = pageDuplex->value(); Landscape = landscape->value(); Compression = (int)compression->value(); OutputColor = !grayscale->value(); TocNumbers = numberedToc->value(); TocLevels = tocLevels->value(); TitlePage = titlePage->value(); if (jpegCompress->value()) OutputJPEG = (int)jpegQuality->value(); else OutputJPEG = 0; strlcpy(TocTitle, tocTitle->value(), sizeof(TocTitle)); temp[0] = formats[tocHeaderLeft->value()]; temp[1] = formats[tocHeaderCenter->value()]; temp[2] = formats[tocHeaderRight->value()]; temp[3] = '\0'; get_format(temp, TocHeader); temp[0] = formats[tocFooterLeft->value()]; temp[1] = formats[tocFooterCenter->value()]; temp[2] = formats[tocFooterRight->value()]; get_format(temp, TocFooter); temp[0] = formats[pageHeaderLeft->value()]; temp[1] = formats[pageHeaderCenter->value()]; temp[2] = formats[pageHeaderRight->value()]; get_format(temp, Header); temp[0] = formats[pageHeader1Left->value()]; temp[1] = formats[pageHeader1Center->value()]; temp[2] = formats[pageHeader1Right->value()]; get_format(temp, Header1); temp[0] = formats[pageFooterLeft->value()]; temp[1] = formats[pageFooterCenter->value()]; temp[2] = formats[pageFooterRight->value()]; get_format(temp, Footer); NumberUp = atoi(numberUp->text(numberUp->value())); _htmlBodyFont = (typeface_t)bodyFont->value(); _htmlHeadingFont = (typeface_t)headingFont->value(); htmlSetBaseSize(fontBaseSize->value(), fontSpacing->value()); HeadFootType = (typeface_t)(headFootFont->value() / 4); HeadFootStyle = (style_t)(headFootFont->value() & 3); HeadFootSize = headFootSize->value(); if (pdf11->value()) PDFVersion = 11; else if (pdf12->value()) PDFVersion = 12; else if (pdf13->value()) PDFVersion = 13; else PDFVersion = 14; PDFPageMode = pageMode->value(); PDFPageLayout = pageLayout->value(); PDFFirstPage = firstPage->value(); PDFEffect = pageEffect->value(); PDFPageDuration = pageDuration->value(); PDFEffectDuration = effectDuration->value(); Links = links->value(); EmbedFonts = embedFonts->value(); Encryption = encryptionYes->value(); Permissions = -64; if (permPrint->value()) Permissions |= PDF_PERM_PRINT; if (permModify->value()) Permissions |= PDF_PERM_MODIFY; if (permCopy->value()) Permissions |= PDF_PERM_COPY; if (permAnnotate->value()) Permissions |= PDF_PERM_ANNOTATE; strlcpy(UserPassword, userPassword->value(), sizeof(UserPassword)); strlcpy(OwnerPassword, ownerPassword->value(), sizeof(OwnerPassword)); if (ps1->value()) PSLevel = 1; else if (ps2->value()) PSLevel = 2; else PSLevel = 3; PSCommands = psCommands->value(); XRXComments = xrxComments->value(); strlcpy(BodyColor, bodyColor->value(), sizeof(BodyColor)); strlcpy(BodyImage, bodyImage->value(), sizeof(BodyImage)); htmlSetTextColor((uchar *)textColor->value()); htmlSetCharSet(charset->text(charset->value())); strlcpy(LinkColor, linkColor->value(), sizeof(LinkColor)); LinkStyle = linkStyle->value(); _htmlBrowserWidth = browserWidth->value(); strlcpy(Path, path->value(), sizeof(Path)); strlcpy(Proxy, proxy->value(), sizeof(Proxy)); StrictHTML = strict_html->value(); OverflowErrors = overflow_errors->value(); } // // 'GUI::newBook()' - Clear out the current GUI settings for a new book. // int // O - 1 on success, 0 on failure GUI::newBook(void) { int i; // Looping var char size[255]; // Page size string char formats[256]; // Format characters const char *fmt; // Old format string prefs_load(); switch (OutputType) { case OUTPUT_BOOK : typeBook->setonly(); docTypeCB(typeBook, this); break; case OUTPUT_CONTINUOUS : typeContinuous->setonly(); docTypeCB(typeContinuous, this); break; case OUTPUT_WEBPAGES : typeWebPage->setonly(); docTypeCB(typeWebPage, this); break; } inputFiles->clear(); inputFilesCB(inputFiles, this); logoImage->value(""); titleImage->value(""); outputFile->setonly(); outputTypeCB(outputFile, this); outputPath->value(""); typeHTML->setonly(); outputFormatCB(typeHTML, this); grayscale->value(!OutputColor); titlePage->value(TitlePage); bodyColor->value(BodyColor); bodyImage->value(BodyImage); textColor->value((char *)_htmlTextColor); linkColor->value(LinkColor); linkStyle->value(LinkStyle); if (PageWidth == 595 && PageLength == 842) pageSize->value("A4"); else if (PageWidth == 595 && PageLength == 792) pageSize->value("Universal"); else if (PageWidth == 612 && PageLength == 792) pageSize->value("Letter"); else { snprintf(size, sizeof(size), "%.2fx%.2fin", PageWidth / 72.0f, PageLength / 72.0f); pageSize->value(size); } snprintf(size, sizeof(size), "%.2fin", PageLeft / 72.0f); pageLeft->value(size); snprintf(size, sizeof(size), "%.2fin", PageRight / 72.0f); pageRight->value(size); snprintf(size, sizeof(size), "%.2fin", PageTop / 72.0f); pageTop->value(size); snprintf(size, sizeof(size), "%.2fin", PageBottom / 72.0f); pageBottom->value(size); pageDuplex->value(PageDuplex); landscape->value(Landscape); memset(formats, 0, sizeof(formats)); formats[(int)'t'] = 1; formats[(int)'c'] = 2; formats[(int)'h'] = 3; formats[(int)'l'] = 4; formats[(int)'1'] = 5; formats[(int)'i'] = 6; formats[(int)'I'] = 7; formats[(int)'a'] = 8; formats[(int)'A'] = 9; formats[(int)'C'] = 10; formats[(int)'/'] = 11; formats[(int)':'] = 12; formats[(int)'d'] = 13; formats[(int)'T'] = 14; formats[(int)'D'] = 15; fmt = get_fmt(Header); pageHeaderLeft->value(formats[fmt[0]]); pageHeaderCenter->value(formats[fmt[1]]); pageHeaderRight->value(formats[fmt[2]]); fmt = get_fmt(Header1); pageHeader1Left->value(formats[fmt[0]]); pageHeader1Center->value(formats[fmt[1]]); pageHeader1Right->value(formats[fmt[2]]); fmt = get_fmt(Footer); pageFooterLeft->value(formats[fmt[0]]); pageFooterCenter->value(formats[fmt[1]]); pageFooterRight->value(formats[fmt[2]]); if (NumberUp == 1) numberUp->value(0); else if (NumberUp == 2) numberUp->value(1); else if (NumberUp == 4) numberUp->value(2); else if (NumberUp == 6) numberUp->value(3); else if (NumberUp == 9) numberUp->value(4); else if (NumberUp == 16) numberUp->value(5); tocLevels->value(TocLevels); numberedToc->value(TocNumbers); fmt = get_fmt(TocHeader); tocHeaderLeft->value(formats[fmt[0]]); tocHeaderCenter->value(formats[fmt[1]]); tocHeaderRight->value(formats[fmt[2]]); fmt = get_fmt(TocFooter); tocFooterLeft->value(formats[fmt[0]]); tocFooterCenter->value(formats[fmt[1]]); tocFooterRight->value(formats[fmt[2]]); tocTitle->value(TocTitle); headingFont->value(_htmlHeadingFont); bodyFont->value(_htmlBodyFont); headFootFont->value(HeadFootType * 4 + HeadFootStyle); fontBaseSize->value(_htmlSizes[SIZE_P]); fontSpacing->value(_htmlSpacings[SIZE_P] / _htmlSizes[SIZE_P]); headFootSize->value(HeadFootSize); for (i = 0; i < (charset->size() - 1); i ++) if (strcasecmp(_htmlCharSet, charset->text(i)) == 0) { charset->value(i); break; } compression->value(Compression); compGroup->deactivate(); jpegCompress->value(OutputJPEG > 0); jpegQuality->value(OutputJPEG > 0 ? OutputJPEG : 90); jpegGroup->deactivate(); pdfTab->deactivate(); if (PDFVersion < 12) { pdf11->setonly(); pdfCB(pdf11, this); } else if (PDFVersion < 13) { pdf12->setonly(); pdfCB(pdf12, this); } else if (PDFVersion < 14) { pdf13->setonly(); pdfCB(pdf13, this); } else { pdf14->setonly(); pdfCB(pdf14, this); } pageMode->value(PDFPageMode); pageLayout->value(PDFPageLayout); firstPage->value(PDFFirstPage); pageEffect->value(PDFEffect); effectCB(pageEffect, this); pageDuration->value(PDFPageDuration); effectDuration->value(PDFEffectDuration); links->value(Links); embedFonts->value(EmbedFonts); securityTab->deactivate(); if (Encryption) { encryptionYes->setonly(); encryptionCB(encryptionYes, this); } else { encryptionNo->setonly(); encryptionCB(encryptionNo, this); } if (Permissions & PDF_PERM_PRINT) permPrint->set(); else permPrint->clear(); if (Permissions & PDF_PERM_MODIFY) permModify->set(); else permModify->clear(); if (Permissions & PDF_PERM_COPY) permCopy->set(); else permCopy->clear(); if (Permissions & PDF_PERM_ANNOTATE) permAnnotate->set(); else permAnnotate->clear(); ownerPassword->value(OwnerPassword); userPassword->value(UserPassword); if (PSLevel == 1) ps1->setonly(); else if (PSLevel == 2) ps2->setonly(); else ps3->setonly(); if (PSLevel == 1) psCommands->deactivate(); else psCommands->activate(); psCommands->value(PSCommands); xrxComments->value(XRXComments); path->value(Path); proxy->value(Proxy); browserWidth->value(_htmlBrowserWidth); strict_html->value(StrictHTML); overflow_errors->value(OverflowErrors); title(NULL, 0); return (1); } // // 'GUI::loadBook()' - Load a book file from disk. // int // O - 1 = success, 0 = fail GUI::loadBook(const char *filename) // I - Name of book file { FILE *fp; // File to read from char line[10240]; // Line from file const char *dir; // Directory char basename[1024]; // Base filename // If the filename contains a path, chdir to it first... if ((dir = file_directory(filename)) != NULL) { /* * Filename contains a complete path - get the directory portion and do * a chdir()... */ strlcpy(basename, file_basename(filename), sizeof(basename)); filename = basename; chdir(dir); fc->directory("."); } // Open the file... fp = fopen(filename, "r"); if (fp == NULL) { fl_alert("Unable to open \"%s\"!", filename); return (0); } // Get the header... file_gets(line, sizeof(line), fp); if (strncmp(line, "#HTMLDOC", 8) != 0) { fclose(fp); fl_alert("Bad or missing #HTMLDOC header:\n%-80.80s", line); return (0); } // Reset the GUI... if (!newBook()) { fclose(fp); return (0); } // Read the second line from the book file; for older book files, this will // be the file count; for new files this will be the options... do { file_gets(line, sizeof(line), fp); if (line[0] == '-') parseOptions(line); } while (!line[0]); // Skip blank lines... // Get input files/options... while (file_gets(line, sizeof(line), fp) != NULL) { if (line[0] == '\0') continue; // Skip blank lines else if (line[0] == '-') parseOptions(line); else if (line[0] == '\\') inputFiles->add(line + 1, icon); else inputFiles->add(line, icon); } // Close the book file and update the GUI... fclose(fp); inputFiles->topline(1); title(filename, 0); return (1); } // // 'GUI::parseOptions()' - Parse options in a book file... // void GUI::parseOptions(const char *line) // I - Line from file { int i; // Looping var const char *lineptr; // Pointer into line char temp[1024], // Option name temp2[1024], // Option value *tempptr, // Pointer into option formats[256]; // Header/footer formats static const char *types[] = // Typeface names... { "Courier", "Times", "Helvetica", "Monospace", "Serif", "Sans" }; static const char *fonts[] = // Font names... { "Courier", "Courier-Bold", "Courier-Oblique", "Courier-BoldOblique", "Times-Roman", "Times-Bold", "Times-Italic", "Times-BoldItalic", "Helvetica", "Helvetica-Bold", "Helvetica-Oblique", "Helvetica-BoldOblique", "Monospace", "Monospace-Bold", "Monospace-Oblique", "Monospace-BoldOblique", "Serif-Roman", "Serif-Bold", "Serif-Oblique", "Serif-BoldOblique", "Sans", "Sans-Bold", "Sans-Oblique", "Sans-BoldOblique" }; // Initialize the format character lookup table... memset(formats, 0, sizeof(formats)); formats[(int)'t'] = 1; formats[(int)'c'] = 2; formats[(int)'h'] = 3; formats[(int)'l'] = 4; formats[(int)'1'] = 5; formats[(int)'i'] = 6; formats[(int)'I'] = 7; formats[(int)'a'] = 8; formats[(int)'A'] = 9; formats[(int)'C'] = 10; formats[(int)'/'] = 11; formats[(int)':'] = 12; formats[(int)'d'] = 13; formats[(int)'T'] = 14; formats[(int)'D'] = 15; // Parse the input line... for (lineptr = line; *lineptr != '\0';) { while (*lineptr == ' ') lineptr ++; for (tempptr = temp; *lineptr != '\0' && *lineptr != ' ';) *tempptr++ = *lineptr++; *tempptr = '\0'; while (*lineptr == ' ') lineptr ++; if (strcmp(temp, "--duplex") == 0) { pageDuplex->set(); continue; } else if (strcmp(temp, "--landscape") == 0) { landscape->set(); continue; } else if (strcmp(temp, "--portrait") == 0) { landscape->clear(); continue; } else if (strncmp(temp, "--jpeg", 6) == 0) { if (strlen(temp) > 7) jpegQuality->value(atof(temp + 7)); else jpegQuality->value(90.0); if (jpegQuality->value() > 0.0) { jpegCompress->set(); jpegGroup->activate(); } else { jpegCompress->clear(); jpegGroup->deactivate(); } continue; } else if (strcmp(temp, "--grayscale") == 0) { grayscale->set(); continue; } else if (strcmp(temp, "--color") == 0) { grayscale->clear(); continue; } else if (strcmp(temp, "--links") == 0) { links->set(); continue; } else if (strcmp(temp, "--no-links") == 0) { links->clear(); continue; } else if (strcmp(temp, "--truetype") == 0 || strcmp(temp, "--embedfonts") == 0) { embedFonts->set(); continue; } else if (strcmp(temp, "--no-truetype") == 0 || strcmp(temp, "--no-embedfonts") == 0) { embedFonts->clear(); continue; } else if (strcmp(temp, "--pscommands") == 0) { psCommands->set(); continue; } else if (strcmp(temp, "--no-pscommands") == 0) { psCommands->clear(); continue; } else if (strcmp(temp, "--xrxcomments") == 0) { xrxComments->set(); continue; } else if (strcmp(temp, "--no-xrxcomments") == 0) { xrxComments->clear(); continue; } else if (strncmp(temp, "--compression", 13) == 0) { if (strlen(temp) > 14) compression->value(atof(temp + 14)); else compression->value(1.0); continue; } else if (strcmp(temp, "--no-compression") == 0) { compression->value(0.0); continue; } else if (strcmp(temp, "--no-jpeg") == 0) { jpegCompress->clear(); jpegGroup->deactivate(); continue; } else if (strcmp(temp, "--numbered") == 0) { numberedToc->set(); continue; } else if (strcmp(temp, "--no-numbered") == 0) { numberedToc->clear(); continue; } else if (strcmp(temp, "--no-toc") == 0) { tocLevels->value(0); continue; } else if (strcmp(temp, "--title") == 0) { titlePage->set(); continue; } else if (strcmp(temp, "--no-title") == 0) { titlePage->clear(); continue; } else if (strcmp(temp, "--strict") == 0) { strict_html->set(); continue; } else if (strcmp(temp, "--no-strict") == 0) { strict_html->clear(); continue; } else if (strcmp(temp, "--overflow") == 0) { overflow_errors->set(); continue; } else if (strcmp(temp, "--no-overflow") == 0) { overflow_errors->clear(); continue; } else if (strcmp(temp, "--book") == 0) { typeBook->setonly(); docTypeCB(typeBook, this); continue; } else if (strcmp(temp, "--continuous") == 0) { typeContinuous->setonly(); docTypeCB(typeContinuous, this); continue; } else if (strcmp(temp, "--webpage") == 0) { typeWebPage->setonly(); docTypeCB(typeWebPage, this); continue; } else if (strcmp(temp, "--encryption") == 0) { encryptionYes->setonly(); encryptionCB(encryptionYes, this); continue; } else if (strcmp(temp, "--no-encryption") == 0) { encryptionNo->setonly(); encryptionCB(encryptionNo, this); continue; } else if (temp[0] != '-') { inputFiles->add(temp, icon); continue; } if (*lineptr == '\"') { lineptr ++; for (tempptr = temp2; *lineptr != '\0' && *lineptr != '\"';) *tempptr++ = *lineptr++; if (*lineptr == '\"') lineptr ++; } else { for (tempptr = temp2; *lineptr != '\0' && *lineptr != ' ';) *tempptr++ = *lineptr++; } *tempptr = '\0'; if (strcmp(temp, "-t") == 0) { if (strcmp(temp2, "epub") == 0) { typeEPUB->setonly(); outputFormatCB(typeEPUB, this); } else if (strcmp(temp2, "html") == 0) { typeHTML->setonly(); outputFormatCB(typeHTML, this); } else if (strcmp(temp2, "htmlsep") == 0) { typeHTMLSep->setonly(); outputFormatCB(typeHTMLSep, this); } else if (strcmp(temp2, "ps1") == 0) { typePS->setonly(); ps1->setonly(); outputFormatCB(typePS, this); psCB(ps1, this); } else if (strcmp(temp2, "ps") == 0 || strcmp(temp2, "ps2") == 0) { typePS->setonly(); ps2->setonly(); outputFormatCB(typePS, this); psCB(ps2, this); } else if (strcmp(temp2, "ps3") == 0) { typePS->setonly(); ps3->setonly(); outputFormatCB(typePS, this); psCB(ps3, this); } else if (strcmp(temp2, "pdf11") == 0) { typePDF->setonly(); pdf11->setonly(); outputFormatCB(typePDF, this); pdfCB(pdf11, this); } else if (strcmp(temp2, "pdf12") == 0) { typePDF->setonly(); pdf12->setonly(); outputFormatCB(typePDF, this); pdfCB(pdf12, this); } else if (strcmp(temp2, "pdf") == 0 || strcmp(temp2, "pdf13") == 0) { typePDF->setonly(); pdf13->setonly(); outputFormatCB(typePDF, this); pdfCB(pdf13, this); } else if (strcmp(temp2, "pdf14") == 0) { typePDF->setonly(); pdf14->setonly(); outputFormatCB(typePDF, this); pdfCB(pdf14, this); } } else if (strcmp(temp, "--logo") == 0 || strcmp(temp, "--logoimage") == 0) logoImage->value(temp2); else if (strcmp(temp, "--titlefile") == 0 || strcmp(temp, "--titleimage") == 0) { titlePage->set(); titleImage->value(temp2); } else if (strcmp(temp, "-f") == 0) { outputPath->value(temp2); outputFile->setonly(); outputTypeCB(outputFile, this); } else if (strcmp(temp, "-d") == 0) { outputPath->value(temp2); outputDirectory->setonly(); outputTypeCB(outputDirectory, this); } else if (strcmp(temp, "--browserwidth") == 0) browserWidth->value(atof(temp2)); else if (strcmp(temp, "--size") == 0) pageSize->value(temp2); else if (strcmp(temp, "--left") == 0) pageLeft->value(temp2); else if (strcmp(temp, "--right") == 0) pageRight->value(temp2); else if (strcmp(temp, "--top") == 0) pageTop->value(temp2); else if (strcmp(temp, "--bottom") == 0) pageBottom->value(temp2); else if (strcmp(temp, "--header") == 0) { pageHeaderLeft->value(formats[temp2[0]]); pageHeaderCenter->value(formats[temp2[1]]); pageHeaderRight->value(formats[temp2[2]]); } else if (strcmp(temp, "--header1") == 0) { pageHeader1Left->value(formats[temp2[0]]); pageHeader1Center->value(formats[temp2[1]]); pageHeader1Right->value(formats[temp2[2]]); } else if (strcmp(temp, "--footer") == 0) { pageFooterLeft->value(formats[temp2[0]]); pageFooterCenter->value(formats[temp2[1]]); pageFooterRight->value(formats[temp2[2]]); } else if (strcmp(temp, "--nup") == 0) { i = atoi(temp2); if (i == 1) numberUp->value(0); else if (i == 2) numberUp->value(1); else if (i == 4) numberUp->value(2); else if (i == 6) numberUp->value(3); else if (i == 9) numberUp->value(4); else if (i == 16) numberUp->value(5); } else if (strcmp(temp, "--bodycolor") == 0) bodyColor->value(temp2); else if (strcmp(temp, "--bodyimage") == 0) bodyImage->value(temp2); else if (strcmp(temp, "--textcolor") == 0) textColor->value(temp2); else if (strcmp(temp, "--linkcolor") == 0) linkColor->value(temp2); else if (strcmp(temp, "--linkstyle") == 0) { if (strcmp(temp2, "plain") == 0) linkStyle->value(0); else linkStyle->value(1); } else if (strcmp(temp, "--toclevels") == 0) tocLevels->value(atoi(temp2)); else if (strcmp(temp, "--tocheader") == 0) { tocHeaderLeft->value(formats[temp2[0]]); tocHeaderCenter->value(formats[temp2[1]]); tocHeaderRight->value(formats[temp2[2]]); } else if (strcmp(temp, "--tocfooter") == 0) { tocFooterLeft->value(formats[temp2[0]]); tocFooterCenter->value(formats[temp2[1]]); tocFooterRight->value(formats[temp2[2]]); } else if (strcmp(temp, "--toctitle") == 0) tocTitle->value(temp2); else if (strcmp(temp, "--fontsize") == 0) fontBaseSize->value(atof(temp2)); else if (strcmp(temp, "--fontspacing") == 0) fontSpacing->value(atof(temp2)); else if (strcmp(temp, "--headingfont") == 0) { for (i = 0; i < (int)(sizeof(types) / sizeof(types[0])); i ++) if (strcasecmp(types[i], temp2) == 0) { headingFont->value(i); break; } } else if (strcmp(temp, "--bodyfont") == 0) { for (i = 0; i < (int)(sizeof(types) / sizeof(types[0])); i ++) if (strcasecmp(types[i], temp2) == 0) { bodyFont->value(i); break; } } else if (strcmp(temp, "--headfootsize") == 0) headFootSize->value(atof(temp2)); else if (strcmp(temp, "--headfootfont") == 0) { for (i = 0; i < (int)(sizeof(fonts) / sizeof(fonts[0])); i ++) if (strcasecmp(fonts[i], temp2) == 0) { headFootFont->value(i); break; } } else if (strcmp(temp, "--charset") == 0) { for (i = 0; i < (charset->size() - 1); i ++) if (strcasecmp(temp2, charset->text(i)) == 0) { charset->value(i); break; } } else if (strcmp(temp, "--pagemode") == 0) { for (i = 0; i < (int)(sizeof(PDFModes) / sizeof(PDFModes[0])); i ++) if (strcasecmp(temp2, PDFModes[i]) == 0) { pageMode->value(i); break; } } else if (strcmp(temp, "--pagelayout") == 0) { for (i = 0; i < (int)(sizeof(PDFLayouts) / sizeof(PDFLayouts[0])); i ++) if (strcasecmp(temp2, PDFLayouts[i]) == 0) { pageLayout->value(i); break; } } else if (strcmp(temp, "--firstpage") == 0) { for (i = 0; i < (int)(sizeof(PDFPages) / sizeof(PDFPages[0])); i ++) if (strcasecmp(temp2, PDFPages[i]) == 0) { firstPage->value(i); break; } } else if (strcmp(temp, "--pageeffect") == 0) { for (i = 0; i < (int)(sizeof(PDFEffects) / sizeof(PDFEffects[0])); i ++) if (strcasecmp(temp2, PDFEffects[i]) == 0) { pageEffect->value(i); effectCB(pageEffect, this); break; } } else if (strcmp(temp, "--pageduration") == 0) pageDuration->value(atof(temp2)); else if (strcmp(temp, "--effectduration") == 0) effectDuration->value(atof(temp2)); else if (strcmp(temp, "--permissions") == 0) { if (strcmp(temp2, "all") == 0) { permPrint->set(); permModify->set(); permCopy->set(); permAnnotate->set(); } else if (strcmp(temp2, "none") == 0) { permPrint->clear(); permModify->clear(); permCopy->clear(); permAnnotate->clear(); } else if (strcmp(temp2, "print") == 0) permPrint->set(); else if (strcmp(temp2, "no-print") == 0) permPrint->clear(); else if (strcmp(temp2, "modify") == 0) permModify->set(); else if (strcmp(temp2, "no-modify") == 0) permModify->clear(); else if (strcmp(temp2, "copy") == 0) permCopy->set(); else if (strcmp(temp2, "no-copy") == 0) permCopy->clear(); else if (strcmp(temp2, "annotate") == 0) permAnnotate->set(); else if (strcmp(temp2, "no-annotate") == 0) permAnnotate->clear(); } else if (strcmp(temp, "--user-password") == 0) userPassword->value(temp2); else if (strcmp(temp, "--owner-password") == 0) ownerPassword->value(temp2); else if (strcmp(temp, "--path") == 0) path->value(temp2); else if (strcmp(temp, "--proxy") == 0) proxy->value(temp2); } } #ifdef __APPLE__ // // 'GUI::appleOpenCB()' - Handle open file events from Finder. // void GUI::appleOpenCB(const char *f) // I - Book file to open { // Save the filename if the book GUI hasn't been initialized... if (!BookGUI) { apple_filename = strdup(f); return; } // See if the user wants to save the current book... if (!BookGUI->checkSave()) return; // Load the new book... BookGUI->loadBook(f); } #endif // __APPLE__ // // 'GUI::saveBook()' - Save a book to disk. // int // O - 1 = success, 0 = fail GUI::saveBook(const char *filename) // I - Name of book file { int i, // Looping var count; // Number of files FILE *fp; // Book file pointer static const char *formats = ".tchl1iIaAC/:dTD"; // Format characters static const char *types[] = // Typeface names... { "Courier", "Times", "Helvetica", "Monospace", "Serif", "Sans" }; static const char *fonts[] = // Font names... { "Courier", "Courier-Bold", "Courier-Oblique", "Courier-BoldOblique", "Times-Roman", "Times-Bold", "Times-Italic", "Times-BoldItalic", "Helvetica", "Helvetica-Bold", "Helvetica-Oblique", "Helvetica-BoldOblique", "Monospace", "Monospace-Bold", "Monospace-Oblique", "Monospace-BoldOblique", "Serif-Roman", "Serif-Bold", "Serif-Oblique", "Serif-BoldOblique", "Sans", "Sans-Bold", "Sans-Oblique", "Sans-BoldOblique" }; // Open the book file... fp = fopen(filename, "w"); if (fp == NULL) { fl_alert("Unable to create \"%s\"!", filename); return (0); } // Write the standard header... fputs("#HTMLDOC " SVERSION "\n", fp); // Write the options... if (typeEPUB->value()) fputs("-t epub", fp); else if (typeHTML->value()) fputs("-t html", fp); else if (typeHTMLSep->value()) fputs("-t htmlsep", fp); else if (typePS->value()) { if (ps1->value()) fputs("-t ps1", fp); else if (ps2->value()) fputs("-t ps2", fp); else if (ps3->value()) fputs("-t ps3", fp); } else if (pdf11->value()) fputs("-t pdf11", fp); else if (pdf12->value()) fputs("-t pdf12", fp); else if (pdf13->value()) fputs("-t pdf13", fp); else fputs("-t pdf14", fp); if (outputFile->value()) fprintf(fp, " -f \"%s\"", outputPath->value()); else fprintf(fp, " -d \"%s\"", outputPath->value()); if (typeWebPage->value()) fputs(" --webpage", fp); else if (typeContinuous->value()) fputs(" --continuous", fp); else { fputs(" --book", fp); if (tocLevels->value() == 0) fputs(" --no-toc", fp); else fprintf(fp, " --toclevels %d", tocLevels->value()); if (numberedToc->value()) fputs(" --numbered", fp); else fputs(" --no-numbered", fp); fprintf(fp, " --toctitle \"%s\"", tocTitle->value()); } if (titlePage->value()) { fputs(" --title", fp); if (titleImage->size() > 0) fprintf(fp, " --titleimage \"%s\"", titleImage->value()); } else fputs(" --no-title", fp); if (logoImage->size() > 0) fprintf(fp, " --logoimage \"%s\"", logoImage->value()); if (textColor->size() > 0) fprintf(fp, " --textcolor %s", textColor->value()); if (linkColor->size() > 0) fprintf(fp, " --linkcolor %s", linkColor->value()); if (linkStyle->value()) fputs(" --linkstyle underline", fp); else fputs(" --linkstyle plain", fp); if (bodyColor->size() > 0) fprintf(fp, " --bodycolor %s", bodyColor->value()); if (bodyImage->size() > 0) fprintf(fp, " --bodyimage %s", bodyImage->value()); if (!typeEPUB->value() && !typeHTML->value() && !typeHTMLSep->value()) { if (pageSize->size() > 0) fprintf(fp, " --size %s", pageSize->value()); if (pageLeft->size() > 0) fprintf(fp, " --left %s", pageLeft->value()); if (pageRight->size() > 0) fprintf(fp, " --right %s", pageRight->value()); if (pageTop->size() > 0) fprintf(fp, " --top %s", pageTop->value()); if (pageBottom->size() > 0) fprintf(fp, " --bottom %s", pageBottom->value()); fprintf(fp, " --header %c%c%c", formats[pageHeaderLeft->value()], formats[pageHeaderCenter->value()], formats[pageHeaderRight->value()]); fprintf(fp, " --header1 %c%c%c", formats[pageHeader1Left->value()], formats[pageHeader1Center->value()], formats[pageHeader1Right->value()]); fprintf(fp, " --footer %c%c%c", formats[pageFooterLeft->value()], formats[pageFooterCenter->value()], formats[pageFooterRight->value()]); fprintf(fp, " --nup %s", numberUp->text(numberUp->value())); fprintf(fp, " --tocheader %c%c%c", formats[tocHeaderLeft->value()], formats[tocHeaderCenter->value()], formats[tocHeaderRight->value()]); fprintf(fp, " --tocfooter %c%c%c", formats[tocFooterLeft->value()], formats[tocFooterCenter->value()], formats[tocFooterRight->value()]); if (pageDuplex->value()) fputs(" --duplex", fp); if (landscape->value()) fputs(" --landscape", fp); else fputs(" --portrait", fp); if (grayscale->value()) fputs(" --grayscale", fp); else fputs(" --color", fp); if (psCommands->value()) fputs(" --pscommands", fp); else fputs(" --no-pscommands", fp); if (xrxComments->value()) fputs(" --xrxcomments", fp); else fputs(" --no-xrxcomments", fp); if (compression->value() == 0.0f) fputs(" --no-compression", fp); else fprintf(fp, " --compression=%.0f", compression->value()); if (jpegCompress->value()) fprintf(fp, " --jpeg=%.0f", jpegQuality->value()); else fputs(" --jpeg=0", fp); } fprintf(fp, " --fontsize %.1f", fontBaseSize->value()); fprintf(fp, " --fontspacing %.1f", fontSpacing->value()); fprintf(fp, " --headingfont %s", types[headingFont->value()]); fprintf(fp, " --bodyfont %s", types[bodyFont->value()]); fprintf(fp, " --headfootsize %.1f", headFootSize->value()); fprintf(fp, " --headfootfont %s", fonts[headFootFont->value()]); fprintf(fp, " --charset %s", charset->text(charset->value())); if (typePDF->value()) { if (links->value()) fputs(" --links", fp); else fputs(" --no-links", fp); if (embedFonts->value()) fputs(" --embedfonts", fp); else fputs(" --no-embedfonts", fp); fprintf(fp, " --pagemode %s", PDFModes[pageMode->value()]); fprintf(fp, " --pagelayout %s", PDFLayouts[pageLayout->value()]); fprintf(fp, " --firstpage %s", PDFPages[firstPage->value()]); fprintf(fp, " --pageeffect %s", PDFEffects[pageEffect->value()]); fprintf(fp, " --pageduration %.0f", pageDuration->value()); fprintf(fp, " --effectduration %.1f", effectDuration->value()); fprintf(fp, " --%sencryption", encryptionYes->value() ? "" : "no-"); if (permPrint->value() && permModify->value() && permCopy->value() && permAnnotate->value()) fputs(" --permissions all", fp); else if (permPrint->value() || permModify->value() || permCopy->value() || permAnnotate->value()) { if (permPrint->value()) fputs(" --permissions print", fp); else fputs(" --permissions no-print", fp); if (permModify->value()) fputs(" --permissions modify", fp); else fputs(" --permissions no-modify", fp); if (permCopy->value()) fputs(" --permissions copy", fp); else fputs(" --permissions no-copy", fp); if (permAnnotate->value()) fputs(" --permissions annotate", fp); else fputs(" --permissions no-annotate", fp); } else fputs(" --permissions none", fp); fprintf(fp, " --owner-password \"%s\"", ownerPassword->value()); fprintf(fp, " --user-password \"%s\"", userPassword->value()); } fprintf(fp, " --browserwidth %.0f", browserWidth->value()); if (path->value()[0]) fprintf(fp, " --path \"%s\"", path->value()); if (proxy->value()[0]) fprintf(fp, " --proxy \"%s\"", proxy->value()); if (strict_html->value()) fputs(" --strict", fp); else fputs(" --no-strict", fp); if (overflow_errors->value()) fputs(" --overflow", fp); else fputs(" --no-overflow", fp); fputs("\n", fp); // Output the files... count = inputFiles->size(); for (i = 1; i <= count; i ++) if (inputFiles->text(i)[0] == '-') fprintf(fp, "\\%s\n", inputFiles->text(i)); else fprintf(fp, "%s\n", inputFiles->text(i)); // Close the file and update the GUI... fclose(fp); title(filename, 0); return (1); } // // 'GUI::checkSave()' - Check to see if a save is needed. // int // O - 1 if no save is needed, 0 if save is needed GUI::checkSave(void) { if (book_changed) { switch (fl_choice("The current book has been changed.\n" "Do you wish to save it first?", "Cancel", "Save", "Discard")) { case 0 : /* Cancel */ return (0); case 1 : /* Save */ if (book_filename[0] != '\0') return (saveBook(book_filename)); else { saveAsBookCB(NULL, this); return (!book_changed); } case 2 : /* Discard */ return (1); } } return (1); } // // 'GUI::changeCB()' - Mark the current book as changed. // void GUI::changeCB(Fl_Widget *w, // I - Widget GUI *gui) // I - GUI { REF(w); gui->title(gui->book_filename, 1); } // // 'GUI::docTypeCB()' - Handle input on the document type buttons. // void GUI::docTypeCB(Fl_Widget *w, // I - Toggle button widget GUI *gui) // I - GUI { gui->title(gui->book_filename, 1); if (w == gui->typeBook) { gui->typeEPUB->activate(); gui->typeHTML->activate(); gui->typeHTMLSep->activate(); gui->titlePage->value(1); gui->tocTab->activate(); gui->tocLevels->value(3); gui->firstPage->activate(); gui->pageMode->value(1); } else { gui->typeEPUB->deactivate(); gui->typeHTML->deactivate(); gui->typeHTMLSep->deactivate(); if (gui->typeEPUB->value() || gui->typeHTML->value() || gui->typeHTMLSep->value()) { gui->typePDF->setonly(); outputFormatCB(gui->typePDF, gui); } gui->titlePage->value(0); gui->tocTab->deactivate(); gui->firstPage->value(0); gui->firstPage->deactivate(); gui->pageMode->value(0); } } // // 'GUI::inputFilesCB()' - Handle selections in the input files browser. // void GUI::inputFilesCB(Fl_Widget *w, // I - Widget GUI *gui) // I - GUI { int i, // Looping var num_items; // Number of items in the file list REF(w); num_items = gui->inputFiles->size(); for (i = 1; i <= num_items; i ++) if (gui->inputFiles->selected(i)) break; if (i <= num_items) { gui->editFile->activate(); gui->deleteFile->activate(); } else { gui->editFile->deactivate(); gui->deleteFile->deactivate(); } if (gui->inputFiles->selected(1) || num_items == 0) gui->moveUpFile->deactivate(); else gui->moveUpFile->activate(); if (gui->inputFiles->selected(num_items) || num_items == 0) gui->moveDownFile->deactivate(); else gui->moveDownFile->activate(); if (Fl::event_clicks() && i <= num_items) editFilesCB(gui->editFile, gui); } // // 'GUI::addFileCB()' - Add a file to the input files list. // void GUI::addFileCB(Fl_Widget *w, // I - Widget GUI *gui) // I - GUI { int i; // Looping var REF(w); gui->fc->filter("WWW Files (*.{htm,html,md,shtml,book})"); gui->fc->type(Fl_File_Chooser::MULTI); gui->fc->label("Add Input Files"); gui->fc->show(); while (gui->fc->shown()) Fl::wait(); if (gui->fc->count()) { for (i = 1; i <= gui->fc->count(); i ++) { if (strcasecmp(file_extension(gui->fc->value(i)), "book") == 0) { // Import files from the book... FILE *fp; char line[1024]; char directory[1024]; int count; getcwd(directory, sizeof(directory)); chdir(file_directory(gui->fc->value(i))); if ((fp = fopen(gui->fc->value(i), "rb")) == NULL) { fl_alert("Unable to import %s:\n%s", gui->fc->value(i), strerror(errno)); chdir(directory); continue; } if (fgets(line, sizeof(line), fp) == NULL) { fl_alert("Unable to import %s:\nShort file.", gui->fc->value(i)); fclose(fp); chdir(directory); continue; } if (strncmp(line, "#HTMLDOC", 8) != 0) { fl_alert("Unable to import %s:\nBad header line.", gui->fc->value(i)); fclose(fp); chdir(directory); continue; } if (fgets(line, sizeof(line), fp) == NULL) { fl_alert("Unable to import %s:\nNo file count.", gui->fc->value(i)); fclose(fp); chdir(directory); continue; } count = atoi(line); while (count > 0) { count --; if (fgets(line, sizeof(line), fp) == NULL) { fl_alert("Unable to import %s:\nMissing file.", gui->fc->value(i)); fclose(fp); chdir(directory); continue; } line[strlen(line) - 1] = '\0'; // strip newline gui->inputFiles->add(file_localize(line, directory), gui->icon); } fclose(fp); chdir(directory); } else gui->inputFiles->add(file_localize(gui->fc->value(i), NULL), gui->icon); } gui->title(gui->book_filename, 1); } } // // 'GUI::addURLCB()' - Add a URL to the input files list. // void GUI::addURLCB(Fl_Widget *w, // I - Widget GUI *gui) // I - GUI { const char *url; // New URL to add REF(w); if ((url = fl_input("URL?", "http://")) != NULL) { gui->inputFiles->add(url, gui->icon); gui->title(gui->book_filename, 1); } } // // 'GUI::editFilesCB()' - Edit one or more files in the input files list. // void GUI::editFilesCB(Fl_Widget *w, // I - Widget GUI *gui) // I - GUI { int i, // Looping var num_items; // Number of items in the file list char command[1024]; // Editor command #ifdef WIN32 STARTUPINFO suInfo; // Process startup information PROCESS_INFORMATION prInfo; // Process information #endif // WIN32 REF(w); num_items = gui->inputFiles->size(); for (i = 1; i <= num_items; i ++) if (gui->inputFiles->selected(i)) { snprintf(command, sizeof(command), gui->htmlEditor->value(), gui->inputFiles->text(i)); #ifdef WIN32 memset(&suInfo, 0, sizeof(suInfo)); suInfo.cb = sizeof(suInfo); if (!CreateProcess(NULL, command, NULL, NULL, FALSE, NORMAL_PRIORITY_CLASS, NULL, NULL, &suInfo, &prInfo)) fl_alert("Unable to start editor!"); #else strlcat(command, "&", sizeof(command)); if (system(command)) fl_alert("Unable to start editor!"); #endif // !WIN32 } } // // 'GUI::deleteFileCB()' - Delete one or more files from the input files list. // void GUI::deleteFilesCB(Fl_Widget *w, // I - Widget GUI *gui) // I - GUI { int i, // Looping var num_items; // Number of items in the file list REF(w); num_items = gui->inputFiles->size(); for (i = num_items; i > 0; i --) if (gui->inputFiles->selected(i)) { gui->inputFiles->select(i, 0); gui->inputFiles->remove(i); gui->title(gui->book_filename, 1); } } // // 'GUI::moveUpFileCB()' - Move one or more files up in the input files list. // void GUI::moveUpFilesCB(Fl_Widget *w, // I - Widget GUI *gui) // I - GUI { int i, // Looping var num_items; // Number of items in the file list char *file; // File to move up REF(w); num_items = gui->inputFiles->size(); for (i = 1; i <= num_items; i ++) if (gui->inputFiles->selected(i)) { file = (char *)gui->inputFiles->text(i); gui->inputFiles->insert(i - 1, file, gui->icon); gui->inputFiles->select(i - 1); gui->inputFiles->remove(i + 1); gui->inputFiles->select(i, 0); gui->title(gui->book_filename, 1); } for (i = 1; i <= num_items; i ++) if (gui->inputFiles->selected(i)) break; gui->inputFiles->make_visible(i); if (gui->inputFiles->selected(1)) gui->moveUpFile->deactivate(); if (!gui->inputFiles->selected(num_items)) gui->moveDownFile->activate(); } // // 'GUI::moveDownFileCB()' - Move one or more files down in the input files list. // void GUI::moveDownFilesCB(Fl_Widget *w, // I - Widget GUI *gui) // I - GUI { int i, // Looping var num_items; // Number of items in the file list char *file; // File to move down REF(w); num_items = gui->inputFiles->size(); for (i = num_items; i > 0; i --) if (gui->inputFiles->selected(i)) { file = (char *)gui->inputFiles->text(i); gui->inputFiles->insert(i + 2, file, gui->icon); gui->inputFiles->select(i + 2); gui->inputFiles->remove(i); gui->inputFiles->select(i, 0); gui->title(gui->book_filename, 1); } for (i = num_items; i >= 1; i --) if (gui->inputFiles->selected(i)) break; gui->inputFiles->make_visible(i); if (!gui->inputFiles->selected(1)) gui->moveUpFile->activate(); if (gui->inputFiles->selected(num_items)) gui->moveDownFile->deactivate(); } // // 'GUI::logoImageCB()' - Change the logo image file. // void GUI::logoImageCB(Fl_Widget *w, // I - Widget GUI *gui) // I - GUI { if (w == gui->logoBrowse) { gui->fc->filter("Image Files (*.{bmp,gif,jpg,png})"); gui->fc->label("Logo Image?"); gui->fc->type(Fl_File_Chooser::SINGLE); gui->fc->show(); while (gui->fc->shown()) Fl::wait(); if (gui->fc->count()) { gui->logoImage->value(file_localize(gui->fc->value(), NULL)); gui->title(gui->book_filename, 1); } } else gui->title(gui->book_filename, 1); } // // 'GUI::titleImageCB()' - Change the title image file. // void GUI::titleImageCB(Fl_Widget *w, // I - Widget GUI *gui) // I - GUI { if (w == gui->titleBrowse) { gui->fc->filter("Image Files (*.{bmp,gif,jpg,png})\tWWW Files (*.{htm,html,md,shtml})"); gui->fc->label("Title Image?"); gui->fc->type(Fl_File_Chooser::SINGLE); gui->fc->show(); while (gui->fc->shown()) Fl::wait(); if (gui->fc->count()) { gui->titleImage->value(file_localize(gui->fc->value(), NULL)); gui->title(gui->book_filename, 1); } } else gui->title(gui->book_filename, 1); } // // 'GUI::outputTypeCB()' - Set the output file type. // void GUI::outputTypeCB(Fl_Widget *w, // I - Widget GUI *gui) // I - GUI { if (w == gui->outputFile) { gui->outputBrowse->activate(); gui->typePDF->activate(); } else if (gui->typePDF->value()) gui->outputFile->setonly(); else { gui->outputBrowse->deactivate(); gui->typePDF->deactivate(); } gui->title(gui->book_filename, 1); } // // 'GUI::outputPathCB()' - Set the output path. // void GUI::outputPathCB(Fl_Widget *w, // I - Widget GUI *gui) // I - GUI { char filename[1024]; // Name of the output file const char *extension; // Extension of the output file if (w == gui->outputBrowse) { gui->fc->label("Output Path?"); if (gui->outputFile->value()) { gui->fc->type(Fl_File_Chooser::CREATE); if (gui->typeEPUB->value()) gui->fc->filter("EPUB Files (*.epub)"); else if (gui->typeHTML->value() || gui->typeHTMLSep->value()) gui->fc->filter("WWW Files (*.htm*)"); else if (gui->typePDF->value()) gui->fc->filter("PDF Files (*.pdf)"); else gui->fc->filter("PostScript Files (*.ps)"); } else { gui->fc->type(Fl_File_Chooser::DIRECTORY | Fl_File_Chooser::CREATE); gui->fc->filter("*"); } gui->fc->show(); while (gui->fc->shown()) Fl::wait(); if (gui->fc->count()) { // Get the selected file... strlcpy(filename, file_localize(gui->fc->value(), NULL), sizeof(filename)); extension = file_extension(filename); if (extension[0]) { // Have an extension - check it! if (strcasecmp(extension, "PS") == 0) { gui->typePS->setonly(); outputFormatCB(gui->typePS, gui); } else if (strcasecmp(extension, "PDF") == 0) { gui->typePDF->setonly(); outputFormatCB(gui->typePDF, gui); } } else if (gui->outputFile->value()) { // No extension - add one! if (gui->typeEPUB->value()) strlcat(filename, ".epub", sizeof(filename)); else if (gui->typeHTML->value() || gui->typeHTMLSep->value()) strlcat(filename, ".html", sizeof(filename)); else if (gui->typePS->value()) strlcat(filename, ".ps", sizeof(filename)); else strlcat(filename, ".pdf", sizeof(filename)); } gui->outputPath->value(filename); gui->title(gui->book_filename, 1); } } else gui->title(gui->book_filename, 1); } // // 'GUI::outputFormatCB()' - Set the output format. // void GUI::outputFormatCB(Fl_Widget *w, // I - Widget GUI *gui) // I - GUI { char filename[1024], // Output filename *ptr; // Pointer to extension const char *ext = NULL; // Extension gui->title(gui->book_filename, 1); if (w == gui->typePDF) { gui->pdfTab->activate(); gui->securityTab->activate(); gui->outputDirectory->deactivate(); gui->outputFile->setonly(); ext = ".pdf"; } else { gui->pdfTab->deactivate(); gui->securityTab->deactivate(); gui->outputDirectory->activate(); } if (w == gui->typeHTMLSep) { gui->outputFile->deactivate(); gui->outputDirectory->setonly(); } else gui->outputFile->activate(); if (w == gui->typeEPUB || w == gui->typeHTML || w == gui->typeHTMLSep) { gui->compression->value(0); gui->jpegCompress->value(0); gui->jpegCompress->deactivate(); gui->jpegGroup->deactivate(); gui->grayscale->value(0); gui->grayscale->deactivate(); gui->pageTab->deactivate(); gui->tocHeaderLeft->deactivate(); gui->tocHeaderCenter->deactivate(); gui->tocHeaderRight->deactivate(); gui->tocFooterLeft->deactivate(); gui->tocFooterCenter->deactivate(); gui->tocFooterRight->deactivate(); if (w == gui->typeEPUB) ext = ".epub"; else ext = ".html"; } else { gui->grayscale->activate(); gui->pageTab->activate(); gui->tocHeaderLeft->activate(); gui->tocHeaderCenter->activate(); gui->tocHeaderRight->activate(); gui->tocFooterLeft->activate(); gui->tocFooterCenter->activate(); gui->tocFooterRight->activate(); if (w == gui->typePDF || !gui->ps1->value()) gui->jpegCompress->activate(); else gui->jpegCompress->deactivate(); } if (w == gui->typePS) { gui->psTab->activate(); if (gui->ps1->value()) gui->psCommands->deactivate(); else gui->psCommands->activate(); ext = ".ps"; } else gui->psTab->deactivate(); if ((w == gui->typePDF && !gui->pdf11->value()) || (w == gui->typePS && gui->ps3->value())) gui->compGroup->activate(); else gui->compGroup->deactivate(); // Update the output filename's extension if we are writing to a file // and the output filename is not blank... if (gui->outputFile->value() && gui->outputPath->value()[0]) { strlcpy(filename, gui->outputPath->value(), sizeof(filename)); if ((ptr = strrchr(filename, '/')) == NULL) ptr = filename; if ((ptr = strrchr(ptr, '.')) == NULL) strlcat(filename, ext, sizeof(filename)); else strlcpy(ptr, ext, sizeof(filename) - (ptr - filename)); gui->outputPath->value(filename); } } // // 'GUI::jpegCB()' - Handle JPEG changes. // void GUI::jpegCB(Fl_Widget *w, // I - Widget GUI *gui) // I - GUI { REF(w); gui->title(gui->book_filename, 1); if (gui->jpegCompress->value()) gui->jpegGroup->activate(); else gui->jpegGroup->deactivate(); } // // 'GUI::sizeCB()' - Change the page size based on the menu selection. // void GUI::sizeCB(Fl_Widget *w, // I - Widget GUI *gui) // I - GUI { REF(w); gui->title(gui->book_filename, 1); gui->pageSize->value(gui->pageSizeMenu->text(gui->pageSizeMenu->value())); } // // 'GUI::tocCB()' - Handle Table-of-Contents changes. // void GUI::tocCB(Fl_Widget *w, // I - Widget GUI *gui) // I - GUI { REF(w); gui->title(gui->book_filename, 1); if (gui->tocLevels->value()) { gui->numberedToc->activate(); gui->tocHeader->activate(); gui->tocFooter->activate(); gui->tocTitle->activate(); } else { gui->numberedToc->deactivate(); gui->tocHeader->deactivate(); gui->tocFooter->deactivate(); gui->tocTitle->deactivate(); } } // // 'GUI::pdfCB()' - Handle PDF version changes. // void GUI::pdfCB(Fl_Widget *w, // I - Widget GUI *gui) // I - GUI { REF(w); if (gui->typePDF->value()) { if (w == gui->pdf11) gui->compGroup->deactivate(); else gui->compGroup->activate(); } gui->title(gui->book_filename, 1); } // // 'GUI::encryptionCB()' - Handle PDF encryption changes. // void GUI::encryptionCB(Fl_Widget *w, // I - Widget GUI *gui) // I - GUI { if (w == gui->encryptionYes) { gui->permissions->activate(); gui->ownerPassword->activate(); gui->userPassword->activate(); } else if (w == gui->encryptionNo) { gui->permissions->deactivate(); gui->ownerPassword->deactivate(); gui->userPassword->deactivate(); } gui->title(gui->book_filename, 1); } // // 'GUI::effectCB()' - Handle PDF effect changes. // void GUI::effectCB(Fl_Widget *w, // I - Widget GUI *gui) // I - GUI { REF(w); if (gui->pageEffect->value()) { gui->pageDuration->activate(); gui->effectDuration->activate(); } else { gui->pageDuration->deactivate(); gui->effectDuration->deactivate(); } gui->title(gui->book_filename, 1); } // // 'GUI::psCB()' - Handle PS language level changes. // void GUI::psCB(Fl_Widget *w, // I - Widget GUI *gui) // I - GUI { if (w == gui->ps1) { gui->jpegCompress->deactivate(); gui->psCommands->deactivate(); gui->psCommands->value(0); } else { gui->jpegCompress->activate(); gui->psCommands->activate(); } if (gui->typePS->value()) { if (w == gui->ps3) gui->compGroup->activate(); else gui->compGroup->deactivate(); } gui->title(gui->book_filename, 1); } // // 'GUI::htmlEditorCB()' - Change the HTML editor. // void GUI::htmlEditorCB(Fl_Widget *w, // I - Widget GUI *gui) // I - GUI { const char *filename; // New HTML editor file char command[1024]; // Command string if (w == gui->htmlBrowse) { # if defined(WIN32) || defined(__EMX__) gui->fc->filter("Program Files (*.exe)"); # else gui->fc->filter("*"); # endif // WIN32 || __EMX__ gui->fc->label("HTML Editor?"); gui->fc->type(Fl_File_Chooser::SINGLE); gui->fc->show(); while (gui->fc->shown()) Fl::wait(); if (gui->fc->count()) { filename = gui->fc->value(); if (strstr(filename, "netscape") != NULL || strstr(filename, "NETSCAPE") != NULL) #if defined(WIN32) || defined(__EMX__) snprintf(command, sizeof(command), "%s -edit \"%%s\"", filename); #else snprintf(command, sizeof(command), "%s -remote \'editFile(%%s)\'", filename); #endif // WIN32 || __EMX__ else snprintf(command, sizeof(command), "%s \"%%s\"", filename); gui->htmlEditor->value(command); } } strlcpy(HTMLEditor, gui->htmlEditor->value(), sizeof(HTMLEditor)); } // // 'GUI::tooltipCB()' - Enable or disable tooltips. // void GUI::tooltipCB(Fl_Widget *w, // I - Widget GUI *gui) // I - GUI interface { REF(gui); Tooltips = ((Fl_Button *)w)->value(); Fl_Tooltip::enable(Tooltips); } #if 0 // // 'GUI::skinCB()' - Enable or disable the modern "skin". // void GUI::skinCB(Fl_Widget *, // I - Widget GUI *gui) // I - GUI interface { ModernSkin = gui->modern_skin->value(); Fl::scheme(ModernSkin ? "plastic" : ""); if (ModernSkin) { // Use alternate colors for the "modern" look-n-feel... gui->tabs->selection_color(FL_BLUE); gui->grayscale->color2(FL_RED); gui->titlePage->color2(FL_RED); gui->jpegCompress->color2(FL_RED); gui->pageDuplex->color2(FL_RED); gui->landscape->color2(FL_RED); gui->numberedToc->color2(FL_RED); gui->psCommands->color2(FL_RED); gui->xrxComments->color2(FL_RED); gui->links->color2(FL_RED); gui->embedFonts->color2(FL_RED); gui->permPrint->color2(FL_RED); gui->permModify->color2(FL_RED); gui->permCopy->color2(FL_RED); gui->permAnnotate->color2(FL_RED); gui->tooltips->color2(FL_RED); gui->modern_skin->color2(FL_RED); gui->strict_html->color2(FL_RED); gui->overflow_errors->color2(FL_RED); gui->progressBar->color2(FL_BLUE); gui->progressBar->box(FL_UP_BOX); } else { // Use standard colors... gui->tabs->selection_color(FL_GRAY); gui->grayscale->color2(FL_BLACK); gui->titlePage->color2(FL_BLACK); gui->jpegCompress->color2(FL_BLACK); gui->pageDuplex->color2(FL_BLACK); gui->landscape->color2(FL_BLACK); gui->numberedToc->color2(FL_BLACK); gui->psCommands->color2(FL_BLACK); gui->xrxComments->color2(FL_BLACK); gui->links->color2(FL_BLACK); gui->embedFonts->color2(FL_BLACK); gui->permPrint->color2(FL_BLACK); gui->permModify->color2(FL_BLACK); gui->permCopy->color2(FL_BLACK); gui->permAnnotate->color2(FL_BLACK); gui->tooltips->color2(FL_BLACK); gui->modern_skin->color2(FL_BLACK); gui->strict_html->color2(FL_BLACK); gui->overflow_errors->color2(FL_BLACK); gui->progressBar->color2(FL_YELLOW); gui->progressBar->box(FL_DOWN_BOX); } } #endif // 0 // // 'GUI::saveOptionsCB()' - Save preferences... // void GUI::saveOptionsCB(Fl_Widget *w, GUI *gui) { gui->loadSettings(); prefs_save(); } // // 'GUI::bodyColorCB()' - Set the body color. // void GUI::bodyColorCB(Fl_Widget *w, // I - Widget GUI *gui) // I - GUI { uchar r, g, b; // Color values int color; // Color from bar color char newcolor[255]; // New color string if (w == gui->bodyLookup) { if (sscanf(gui->bodyColor->value(), "#%x", &color) == 1) { r = color >> 16; g = (color >> 8) & 255; b = color & 255; } else { r = 191; g = 191; b = 191; } if (fl_color_chooser("Body Color?", r, g, b)) { snprintf(newcolor, sizeof(newcolor), "#%02x%02x%02x", r, g, b); gui->bodyColor->value(newcolor); gui->title(gui->book_filename, 1); } } else gui->title(gui->book_filename, 1); } // // 'GUI::bodyImageCB()' - Set the body image. // void GUI::bodyImageCB(Fl_Widget *w, // I - Widget GUI *gui) // I - GUI { if (w == gui->bodyBrowse) { gui->fc->filter("Image Files (*.{bmp,gif,jpg,png})"); gui->fc->label("Body Image?"); gui->fc->type(Fl_File_Chooser::SINGLE); gui->fc->show(); while (gui->fc->shown()) Fl::wait(); if (gui->fc->count()) { gui->bodyImage->value(file_localize(gui->fc->value(), NULL)); gui->title(gui->book_filename, 1); } } else gui->title(gui->book_filename, 1); } // // 'GUI::textColorCB()' - Set the text color. // void GUI::textColorCB(Fl_Widget *w, // I - Widget GUI *gui) // I - GUI { uchar r, g, b; // Color values int color; // Color from bar color char newcolor[255]; // New color string if (w == gui->textLookup) { if (sscanf(gui->textColor->value(), "#%x", &color) == 1) { r = color >> 16; g = (color >> 8) & 255; b = color & 255; } else { r = 0; g = 0; b = 0; } if (fl_color_chooser("Text Color?", r, g, b)) { snprintf(newcolor, sizeof(newcolor), "#%02x%02x%02x", r, g, b); gui->textColor->value(newcolor); gui->title(gui->book_filename, 1); } } else gui->title(gui->book_filename, 1); } // // 'GUI::linkColorCB()' - Set the link color. // void GUI::linkColorCB(Fl_Widget *w, // I - Widget GUI *gui) // I - GUI { uchar r, g, b; // Color values int color; // Color from bar color char newcolor[255]; // New color string if (w == gui->linkLookup) { if (sscanf(gui->linkColor->value(), "#%x", &color) == 1) { r = color >> 16; g = (color >> 8) & 255; b = color & 255; } else { r = 0; g = 0; b = 255; } if (fl_color_chooser("Link Color?", r, g, b)) { snprintf(newcolor, sizeof(newcolor), "#%02x%02x%02x", r, g, b); gui->linkColor->value(newcolor); gui->title(gui->book_filename, 1); } } else gui->title(gui->book_filename, 1); } // // 'GUI::helpCB()' - Show on-line help... // void GUI::helpCB(Fl_Widget *w, // I - Widget GUI *gui) // I - GUI { char link[1024]; // filename#link REF(w); snprintf(link, sizeof(link), "%s/help.html#%s", help_dir, gui->tabs->value()->label()); gui->help->load(link); gui->help->show(); } // // 'GUI::newBookCB()' - Create a new book. // void GUI::newBookCB(Fl_Widget *w, // I - Widget GUI *gui) // I - GUI { REF(w); if (!gui->checkSave()) return; gui->newBook(); } // // 'GUI::openBookCB()' - Open an existing book. // void GUI::openBookCB(Fl_Widget *w, // I - Widget GUI *gui) // I - GUI { REF(w); if (!gui->checkSave()) return; gui->fc->filter("Book Files (*.book)"); gui->fc->label("Book File?"); gui->fc->type(Fl_File_Chooser::SINGLE); gui->fc->show(); while (gui->fc->shown()) Fl::wait(); if (gui->fc->count()) gui->loadBook(gui->fc->value()); } // // 'GUI::saveBookCB()' - Save the current book to disk. // void GUI::saveBookCB(Fl_Widget *w, // I - Widget GUI *gui) // I - GUI { if (gui->book_filename[0] == '\0') saveAsBookCB(w, gui); else gui->saveBook(gui->book_filename); } // // 'GUI::saveAsBookCB()' - Save the current book to disk to a new file. // void GUI::saveAsBookCB(Fl_Widget *w, // I - Widget GUI *gui) // I - GUI { const char *filename; // Book filename char realname[1024]; // Real filename const char *extension; // Filename extension const char *newfile; // New filename const char *dir; // Book directory REF(w); gui->fc->filter("Book Files (*.book)"); gui->fc->label("Book File?"); gui->fc->type(Fl_File_Chooser::CREATE); gui->fc->show(); while (gui->fc->shown()) Fl::wait(); if (gui->fc->count()) { filename = gui->fc->value(); if (access(filename, 0) == 0) if (!fl_choice("File already exists! OK to overwrite?", "Cancel", "Overwrite", NULL)) return; extension = file_extension(filename); if (!extension[0]) { // No extension! Add .book to the name... snprintf(realname, sizeof(realname), "%s.book", filename); filename = realname; } else if (strcasecmp(extension, "pdf") == 0 || strcasecmp(extension, "html") == 0 || strcasecmp(extension, "ps") == 0) { gui->tabs->value(gui->outputTab); gui->outputPath->value(file_localize(filename, NULL)); gui->outputFile->setonly(); outputTypeCB(gui->outputFile, gui); if (strcasecmp(extension, "pdf") == 0) { gui->typePDF->setonly(); outputFormatCB(gui->typePDF, gui); } else if (strcasecmp(extension, "epub") == 0) { gui->typeEPUB->setonly(); outputFormatCB(gui->typeEPUB, gui); } else if (strcasecmp(extension, "html") == 0) { gui->typeHTML->setonly(); outputFormatCB(gui->typeHTML, gui); } else { gui->typePS->setonly(); outputFormatCB(gui->typePS, gui); } fl_alert("To generate a HTML, PDF, or PS file you must click on " "the GENERATE button. The SAVE and SAVE AS buttons " "save the current book file."); return; } dir = file_directory(filename); for (int i = 1; i <= gui->inputFiles->size(); i ++) { newfile = file_localize(gui->inputFiles->text(i), dir); gui->inputFiles->text(i, newfile); } newfile = file_localize(gui->logoImage->value(), dir); gui->logoImage->value(newfile); newfile = file_localize(gui->titleImage->value(), dir); gui->titleImage->value(newfile); newfile = file_localize(gui->bodyImage->value(), dir); gui->bodyImage->value(newfile); newfile = file_localize(gui->outputPath->value(), dir); gui->outputPath->value(newfile); chdir(dir); gui->saveBook(filename); } } // // 'GUI::generateBookCB()' - Generate the current book. // void GUI::generateBookCB(Fl_Widget *w, // I - Widget GUI *gui) // I - GUI { int i, // Looping var count; // Number of files char temp[1024]; // Temporary string FILE *docfile; // Document file tree_t *document, // Master HTML document *file, // HTML document file *toc; // Table of contents const char *filename, // HTML filename *ext; // Extension of filename char base[1024], // Base directory of HTML file bookbase[1024]; // Base directory of book file REF(w); // Do we have an output filename? if (gui->outputPath->size() == 0) { gui->tabs->value(gui->outputTab); gui->outputPath->take_focus(); fl_alert("You must specify an output directory or filename before " "you click on GENERATE."); return; } // Disable the GUI while we generate... gui->controls->deactivate(); gui->window->cursor(FL_CURSOR_WAIT); // Set global vars used for converting the HTML files to XYZ format... strlcpy(bookbase, file_directory(gui->book_filename), sizeof(bookbase)); Verbosity = 1; gui->loadSettings(); strlcpy(LogoImage, gui->logoImage->value(), sizeof(LogoImage)); strlcpy(TitleImage, gui->titleImage->value(), sizeof(TitleImage)); strlcpy(OutputPath, gui->outputPath->value(), sizeof(OutputPath)); OutputFiles = gui->outputDirectory->value(); if (gui->typeBook->value()) OutputType = OUTPUT_BOOK; else if (gui->typeContinuous->value()) OutputType = OUTPUT_CONTINUOUS; else OutputType = OUTPUT_WEBPAGES; strlcpy(UserPassword, gui->userPassword->value(), sizeof(UserPassword)); strlcpy(OwnerPassword, gui->ownerPassword->value(), sizeof(OwnerPassword)); if (gui->typePDF->value()) PSLevel = 0; else if (gui->ps1->value()) PSLevel = 1; else if (gui->ps2->value()) PSLevel = 2; else PSLevel = 3; _htmlPPI = 72.0f * _htmlBrowserWidth / (PageWidth - PageLeft - PageRight); file_proxy(gui->proxy->value()); Errors = 0; gui->error_list->clear(); /* * Load the input files... */ count = gui->inputFiles->size(); document = NULL; for (i = 1; i <= count; i ++) { filename = file_find(Path, gui->inputFiles->text(i)); if (filename != NULL && (docfile = fopen(filename, "rb")) != NULL) { /* * Read from a file... */ snprintf(temp, sizeof(temp), "Loading \"%s\"...", filename); gui->progress(100 * i / count, temp); strlcpy(base, file_directory(gui->inputFiles->text(i)), sizeof(base)); ext = file_extension(filename); file = htmlAddTree(NULL, MARKUP_FILE, NULL); htmlSetVariable(file, (uchar *)"_HD_FILENAME", (uchar *)file_basename(filename)); htmlSetVariable(file, (uchar *)"_HD_BASE", (uchar *)base); if (ext && !strcmp(ext, "md")) { // Read markdown from a file... mdReadFile(file, docfile, base); } else { // Read HTML from a file... _htmlCurrentFile = gui->inputFiles->text(i); htmlReadFile(file, docfile, base); } fclose(docfile); if (file->child != NULL) { if (document == NULL) document = file; else { while (document->next != NULL) document = document->next; document->next = file; file->prev = document; } } else htmlDeleteTree(file); } else progress_error(HD_ERROR_FILE_NOT_FOUND, "Unable to open \"%s\" for reading!", gui->inputFiles->text(i)); } /* * We *must* have a document to process... */ if (document == NULL) progress_error(HD_ERROR_NO_FILES, "No input files to format, cannot generate document."); else { /* * Find the first one in the list... */ while (document->prev != NULL) document = document->prev; // Fix links... htmlFixLinks(document, document); // Show debug info... htmlDebugStats("Document Tree", document); // Build a table of contents for the documents... if (OutputType == OUTPUT_BOOK && TocLevels > 0) toc = toc_build(document); else toc = NULL; // Generate the output file(s). if (gui->typeEPUB->value()) epub_export(document, toc); else if (gui->typeHTML->value()) html_export(document, toc); else if (gui->typeHTMLSep->value()) htmlsep_export(document, toc); else pspdf_export(document, toc); htmlDeleteTree(document); htmlDeleteTree(toc); file_cleanup(); image_flush_cache(); } if (Errors == 0) fl_message("Document generated successfully!"); else if (fl_choice("%d error%s occurred while generating document.\n" "Would you like to see the list?", "Continue", "View Error List", NULL, Errors, Errors == 1 ? "" : "s")) gui->error_window->show(); gui->controls->activate(); gui->window->cursor(FL_CURSOR_DEFAULT); gui->progress(0); } // // 'GUI::closeBookCB()' - Close the current book. // void GUI::closeBookCB(Fl_Widget *w, // I - Widget GUI *gui) // I - GUI { REF(w); if (gui->checkSave()) gui->hide(); } // // 'GUI::errorCB()' - Close the error window. // void GUI::errorCB(Fl_Widget *w, // I - Widget GUI *gui) // I - GUI { REF(w); gui->error_window->hide(); } // // 'aboutCloseCB()' - Close the about window. // static void aboutCloseCB(Fl_Widget *w) // I - Widget { if (w && w->window()) w->window()->hide(); } // // 'GUI::showAboutCB()' - Show the about window. // void GUI::showAboutCB(void) { Fl_Window *about; // About window Fl_Group *group; // Group Fl_Box *label; // Labels Fl_Help_View *text; // Help text Fl_Button *button; // Close button Fl_Pixmap logo(htmldoc_xpm); // Logo image about = new Fl_Window(550, 300, "About HTMLDOC"); about->set_modal(); about->hotspot(about); group = new Fl_Group(10, 10, 530, 245, "About HTMLDOC"); group->align(FL_ALIGN_TOP_LEFT | FL_ALIGN_INSIDE); group->labelcolor(FL_BLUE); group->labelfont(FL_HELVETICA_BOLD); group->labelsize(18); group->box(FL_THIN_UP_BOX); label = new Fl_Box(20, 45, 35, 35); label->image(&logo); label = new Fl_Box(60, 45, 530, 35, "HTMLDOC " SVERSION "\nCopyright 2011-2019 by Michael R Sweet." ); label->align(FL_ALIGN_TOP_LEFT | FL_ALIGN_INSIDE | FL_ALIGN_WRAP); text = new Fl_Help_View(20, 90, 510, 155); text->value( "HTMLDOC converts HTML files and web pages to PDF and PostScript.\n\n" "

    HTMLDOC is provided under the terms of the GNU General Public License " "and comes with absolutely no warranty. Please report problems on the " "Github issues page at:\n" "

    \n\n"
        "    https://github.com/michaelrsweet/htmldoc/issues\n"
        "
    \n" ); text->textsize(FL_NORMAL_SIZE); group->end(); button = new Fl_Button(480, 265, 60, 25, "Close"); button->callback((Fl_Callback *)aboutCloseCB); about->end(); about->show(); while (about->shown()) Fl::wait(); delete about; } #endif // HAVE_LIBFLTK htmldoc-1.9.7/htmldoc/gui.h000066400000000000000000000152611354715574200155730ustar00rootroot00000000000000/* * GUI definitions for HTMLDOC, an HTML document processing program. * * Copyright 2011-2018 by Michael R Sweet. * Copyright 1997-2010 by Easy Software Products. All rights reserved. * * This program is free software. Distribution and use rights are outlined in * the file "COPYING". */ /* * Include necessary headers. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* * Class definition for HTMLDOC dialog... */ class GUI { private: Fl_Double_Window *window; Fl_Group *controls; Fl_Tabs *tabs; Fl_Group *inputTab; Fl_Round_Button *typeBook, *typeContinuous, *typeWebPage; Fl_File_Browser *inputFiles; Fl_Button *addFile, *addURL, *editFile, *deleteFile, *moveUpFile, *moveDownFile; Fl_Input *logoImage; Fl_Button *logoBrowse; Fl_Input *titleImage; Fl_Button *titleBrowse; Fl_Group *outputTab; Fl_Round_Button *outputFile, *outputDirectory; Fl_Input *outputPath; Fl_Button *outputBrowse; Fl_Round_Button *typeEPUB, *typeHTML, *typeHTMLSep, *typePS, *typePDF; Fl_Check_Button *grayscale, *titlePage, *jpegCompress; Fl_Group *compGroup; Fl_Slider *compression; Fl_Group *jpegGroup; Fl_Value_Slider *jpegQuality; Fl_Group *pageTab; Fl_Input *pageSize; Fl_Menu_Button *pageSizeMenu; Fl_Check_Button *pageDuplex, *landscape; Fl_Input *pageTop, *pageLeft, *pageRight, *pageBottom; Fl_Choice *pageHeaderLeft, *pageHeaderCenter, *pageHeaderRight, *pageHeader1Left, *pageHeader1Center, *pageHeader1Right, *pageFooterLeft, *pageFooterCenter, *pageFooterRight; Fl_Choice *numberUp; Fl_Group *tocTab; Fl_Choice *tocLevels; Fl_Check_Button *numberedToc; Fl_Group *tocHeader; Fl_Choice *tocHeaderLeft, *tocHeaderCenter, *tocHeaderRight; Fl_Group *tocFooter; Fl_Choice *tocFooterLeft, *tocFooterCenter, *tocFooterRight; Fl_Input *tocTitle; Fl_Group *colorsTab; Fl_Input *bodyColor; Fl_Button *bodyLookup; Fl_Input *bodyImage; Fl_Button *bodyBrowse; Fl_Input *textColor; Fl_Button *textLookup; Fl_Input *linkColor; Fl_Button *linkLookup; Fl_Choice *linkStyle; Fl_Group *fontsTab; Fl_Choice *headingFont, *bodyFont, *headFootFont; Fl_Counter *fontBaseSize, *fontSpacing, *headFootSize; Fl_Choice *charset; Fl_Check_Button *embedFonts; Fl_Group *psTab; Fl_Group *psLevel; Fl_Round_Button *ps1, *ps2, *ps3; Fl_Check_Button *psCommands, *xrxComments; Fl_Group *pdfTab; Fl_Group *pdfVersion; Fl_Round_Button *pdf11, *pdf12, *pdf13, *pdf14; Fl_Choice *pageMode, *pageLayout, *firstPage, *pageEffect; Fl_Value_Slider *pageDuration, *effectDuration; Fl_Check_Button *links; Fl_Group *securityTab; Fl_Group *encryption; Fl_Round_Button *encryptionYes, *encryptionNo; Fl_Group *permissions; Fl_Check_Button *permPrint, *permModify, *permCopy, *permAnnotate; Fl_Secret_Input *ownerPassword, *userPassword; Fl_Group *optionsTab; Fl_Input *htmlEditor; Fl_Button *htmlBrowse; Fl_Value_Slider *browserWidth; Fl_Input *path; Fl_Input *proxy; Fl_Check_Button *tooltips; Fl_Check_Button *strict_html; Fl_Check_Button *overflow_errors; Fl_Button *showAbout, *showLicense, *saveOptions; Fl_Button *bookHelp, *bookNew, *bookOpen, *bookSave, *bookSaveAs, *bookGenerate, *bookClose; Fl_Progress *progressBar; char book_filename[1024]; int book_changed; char title_string[1024]; Fl_File_Chooser *fc; Fl_File_Icon *icon; Fl_Help_Dialog *help; Fl_Window *error_window; Fl_Browser *error_list; Fl_Button *error_ok; void loadSettings(); void title(const char *filename = NULL, int changed = 0); static void changeCB(Fl_Widget *w, GUI *gui); static void docTypeCB(Fl_Widget *w, GUI *gui); static void inputFilesCB(Fl_Widget *w, GUI *gui); static void addFileCB(Fl_Widget *w, GUI *gui); static void addURLCB(Fl_Widget *w, GUI *gui); static void editFilesCB(Fl_Widget *w, GUI *gui); static void deleteFilesCB(Fl_Widget *w, GUI *gui); static void moveUpFilesCB(Fl_Widget *w, GUI *gui); static void moveDownFilesCB(Fl_Widget *w, GUI *gui); static void logoImageCB(Fl_Widget *w, GUI *gui); static void titleImageCB(Fl_Widget *w, GUI *gui); static void outputTypeCB(Fl_Widget *w, GUI *gui); static void outputPathCB(Fl_Widget *w, GUI *gui); static void outputFormatCB(Fl_Widget *w, GUI *gui); static void jpegCB(Fl_Widget *w, GUI *gui); static void sizeCB(Fl_Widget *w, GUI *gui); static void tocCB(Fl_Widget *w, GUI *gui); static void bodyColorCB(Fl_Widget *w, GUI *gui); static void bodyImageCB(Fl_Widget *w, GUI *gui); static void textColorCB(Fl_Widget *w, GUI *gui); static void linkColorCB(Fl_Widget *w, GUI *gui); static void psCB(Fl_Widget *w, GUI *gui); static void pdfCB(Fl_Widget *w, GUI *gui); static void effectCB(Fl_Widget *w, GUI *gui); static void encryptionCB(Fl_Widget *w, GUI *gui); static void htmlEditorCB(Fl_Widget *w, GUI *gui); static void tooltipCB(Fl_Widget *w, GUI *gui); static void saveOptionsCB(Fl_Widget *w, GUI *gui); static void helpCB(Fl_Widget *w, GUI *gui); static void newBookCB(Fl_Widget *w, GUI *gui); static void openBookCB(Fl_Widget *w, GUI *gui); static void saveBookCB(Fl_Widget *w, GUI *gui); static void saveAsBookCB(Fl_Widget *w, GUI *gui); static void generateBookCB(Fl_Widget *w, GUI *gui); static void closeBookCB(Fl_Widget *w, GUI *gui); static void errorCB(Fl_Widget *w, GUI *gui); #ifdef __APPLE__ static void appleOpenCB(const char *f); #endif // __APPLE__ public: static const char *help_dir; static void showAboutCB(void); static void showLicenseCB(void); GUI(const char *filename = NULL); ~GUI(void); void add_error(const char *s) { error_list->add(s); } int checkSave(); void hide() { window->hide(); help->hide(); fc->hide(); }; int loadBook(const char *bookfile); int newBook(); void parseOptions(const char *line); void progress(int percent, const char *text = NULL); int saveBook(const char *bookfile); void show(); int visible() { return (window->visible()); } }; htmldoc-1.9.7/htmldoc/hdstring.h000066400000000000000000000044041354715574200166260ustar00rootroot00000000000000/* * String definitions for HTMLDOC, a HTML document processing program. * * Copyright 2011-2014 by Michael R Sweet. * Copyright 1997-2010 by Easy Software Products. All rights reserved. * * This program is free software. Distribution and use rights are outlined in * the file "COPYING". */ #ifndef _HDSTRING_H_ # define _HDSTRING_H_ /* * Include necessary headers... */ # include "config.h" # include # include # include # include # include # ifdef HAVE_STRINGS_H # include # endif /* HAVE_STRINGS_H */ # ifdef __cplusplus extern "C" { # endif /* __cplusplus */ /* * Define some compatibility macros for Microsoft Windows... */ # ifdef WIN32 # define strcasecmp(s,t) stricmp(s,t) # define strncasecmp(s,t,n) strnicmp(s,t,n) # define snprintf _snprintf # define vsnprintf _vsnprintf # endif /* WIN32 */ /* * Implementation of strcpy() that allows for overlapping buffers. */ extern void hd_strcpy(char *dst, const char *src); /* * Standard string functions that might not be available... */ # ifndef HAVE_STRDUP extern char *hd_strdup(const char *); # define strdup hd_strdup # endif /* !HAVE_STRDUP */ # ifndef HAVE_STRCASECMP extern int hd_strcasecmp(const char *, const char *); # define strcasecmp hd_strcasecmp # endif /* !HAVE_STRCASECMP */ # ifndef HAVE_STRNCASECMP extern int hd_strncasecmp(const char *, const char *, size_t n); # define strncasecmp hd_strncasecmp # endif /* !HAVE_STRNCASECMP */ # ifndef HAVE_STRLCAT extern size_t hd_strlcat(char *, const char *, size_t); # define strlcat hd_strlcat # endif /* !HAVE_STRLCAT */ # ifndef HAVE_STRLCPY extern size_t hd_strlcpy(char *, const char *, size_t); # define strlcpy hd_strlcpy # endif /* !HAVE_STRLCPY */ # ifndef HAVE_SNPRINTF extern int hd_snprintf(char *, size_t, const char *, ...) # ifdef __GNUC__ __attribute__ ((__format__ (__printf__, 3, 4))) # endif /* __GNUC__ */ ; # define snprintf hd_snprintf # endif /* !HAVE_SNPRINTF */ # ifndef HAVE_VSNPRINTF extern int hd_vsnprintf(char *, size_t, const char *, va_list); # define vsnprintf hd_vsnprintf # endif /* !HAVE_VSNPRINTF */ # ifdef __cplusplus } # endif /* __cplusplus */ #endif /* !_HDSTRING_H_ */ htmldoc-1.9.7/htmldoc/html.cxx000066400000000000000000000634241354715574200163320ustar00rootroot00000000000000/* * HTML exporting functions for HTMLDOC, a HTML document processing program. * * Copyright 2011-2019 by Michael R Sweet. * Copyright 1997-2010 by Easy Software Products. All rights reserved. * * This program is free software. Distribution and use rights are outlined in * the file "COPYING". */ /* * Include necessary headers. */ #include "htmldoc.h" #include "markdown.h" #include /* * Named link structure... */ typedef struct { uchar *filename; /* File for link */ uchar name[124]; /* Reference name */ } link_t; /* * Local globals... */ static size_t num_links = 0, alloc_links = 0; static link_t *links; /* * Local functions... */ extern "C" { typedef int (*compare_func_t)(const void *, const void *); } static void write_header(FILE **out, uchar *filename, uchar *title, uchar *author, uchar *copyright, uchar *docnumber, tree_t *t); static void write_footer(FILE **out, tree_t *t); static void write_title(FILE *out, uchar *title, uchar *author, uchar *copyright, uchar *docnumber); static int write_all(FILE *out, tree_t *t, int col); static int write_node(FILE *out, tree_t *t, int col); static int write_nodeclose(FILE *out, tree_t *t, int col); static int write_toc(FILE *out, tree_t *t, int col); static uchar *get_title(tree_t *doc); static void add_link(uchar *name, uchar *filename); static link_t *find_link(uchar *name); static int compare_links(link_t *n1, link_t *n2); static void scan_links(tree_t *t, uchar *filename); static void update_links(tree_t *t, uchar *filename); /* * 'html_export()' - Export to HTML... */ int /* O - 0 = success, -1 = failure */ html_export(tree_t *document, /* I - Document to export */ tree_t *toc) /* I - Table of contents for document */ { uchar *title, /* Title text */ *author, /* Author name */ *copyright, /* Copyright text */ *docnumber; /* Document number */ FILE *out; /* Output file */ /* * Copy logo and title images... */ if (OutputFiles) { if (LogoImage[0]) image_copy(LogoImage, file_find(LogoImage, Path), OutputPath); for (int hfi = 0; hfi < MAX_HF_IMAGES; hfi ++) if (HFImage[hfi][0]) image_copy(HFImage[hfi], file_find(HFImage[hfi], Path), OutputPath); } if (OutputFiles && TitleImage[0] && TitlePage && #ifdef WIN32 (stricmp(file_extension(TitleImage), "bmp") == 0 || stricmp(file_extension(TitleImage), "gif") == 0 || stricmp(file_extension(TitleImage), "jpg") == 0 || stricmp(file_extension(TitleImage), "png") == 0)) #else (strcmp(file_extension(TitleImage), "bmp") == 0 || strcmp(file_extension(TitleImage), "gif") == 0 || strcmp(file_extension(TitleImage), "jpg") == 0 || strcmp(file_extension(TitleImage), "png") == 0)) #endif // WIN32 image_copy(TitleImage, file_find(TitleImage, Path), OutputPath); /* * Get document strings... */ title = get_title(document); author = htmlGetMeta(document, (uchar *)"author"); copyright = htmlGetMeta(document, (uchar *)"copyright"); docnumber = htmlGetMeta(document, (uchar *)"docnumber"); if (!docnumber) docnumber = htmlGetMeta(document, (uchar *)"version"); /* * Scan for all links in the document, and then update them... */ num_links = 0; alloc_links = 0; links = NULL; scan_links(document, NULL); update_links(document, NULL); update_links(toc, NULL); /* * Generate title pages and a table of contents... */ out = NULL; if (TitlePage) { write_header(&out, (uchar *)"index.html", title, author, copyright, docnumber, NULL); if (out != NULL) write_title(out, title, author, copyright, docnumber); write_footer(&out, NULL); write_header(&out, (uchar *)"toc.html", title, author, copyright, docnumber, NULL); } else write_header(&out, (uchar *)"index.html", title, author, copyright, docnumber, NULL); if (out != NULL) write_toc(out, toc, 0); write_footer(&out, NULL); /* * Then write each output file... */ while (document != NULL) { write_header(&out, htmlGetVariable(document, (uchar *)"_HD_FILENAME"), title, author, copyright, docnumber, document); if (out != NULL) write_all(out, document->child, 0); write_footer(&out, document); document = document->next; } if (!OutputFiles && out != stdout && out != NULL) { fputs("\n", out); fputs("\n", out); progress_error(HD_ERROR_NONE, "BYTES: %ld", ftell(out)); fclose(out); } if (title != NULL) free(title); if (alloc_links) { free(links); num_links = 0; alloc_links = 0; links = NULL; } return (out == NULL); } /* * 'write_header()' - Output the standard "header" for a HTML file. */ static void write_header(FILE **out, /* IO - Output file */ uchar *filename, /* I - Output filename */ uchar *title, /* I - Title for document */ uchar *author, /* I - Author for document */ uchar *copyright, /* I - Copyright for document */ uchar *docnumber, /* I - ID number for document */ tree_t *t) /* I - Current document file */ { char realname[1024]; /* Real filename */ const char *basename; /* Filename without directory */ int newfile; /* Non-zero if this is a new file */ static const char *families[] =/* Typeface names */ { "monospace", "serif", "sans-serif", "monospace", "serif", "sans-serif", "symbol", "dingbats" }; if (OutputFiles) { newfile = 1; basename = file_basename((char *)filename); snprintf(realname, sizeof(realname), "%s/%s", OutputPath, basename); *out = fopen(realname, "wb"); } else if (OutputPath[0]) { if (*out == NULL) { *out = fopen(OutputPath, "wb"); newfile = 1; } else newfile = 0; } else { if (*out == NULL) { *out = stdout; newfile = 1; } else newfile = 0; } if (*out == NULL) { progress_error(HD_ERROR_WRITE_ERROR, "Unable to create output file \"%s\" - %s.\n", OutputFiles ? realname : OutputPath, strerror(errno)); return; } if (newfile) { fputs("\n", *out); fputs("\n", *out); fputs("\n", *out); if (title != NULL) fprintf(*out, "%s\n", title); if (author != NULL) fprintf(*out, "\n", author); if (copyright != NULL) fprintf(*out, "\n", copyright); if (docnumber != NULL) fprintf(*out, "\n", docnumber); fprintf(*out, "\n", _htmlCharSet); if (OutputFiles) { fputs("\n", *out); if (TitlePage) fputs("\n", *out); else fputs("\n", *out); if (t) { if (t->prev != NULL) fprintf(*out, "\n", file_basename((char *)htmlGetVariable(t->prev, (uchar *)"_HD_FILENAME"))); if (t->next != NULL) fprintf(*out, "\n", file_basename((char *)htmlGetVariable(t->next, (uchar *)"_HD_FILENAME"))); } } fputs("\n", *out); fputs("\n", *out); if (BodyImage[0]) fprintf(*out, "\n", *out); } else fputs("
    \n", *out); if (OutputFiles && t != NULL && (t->prev != NULL || t->next != NULL)) { if (LogoImage[0]) fprintf(*out, "\n", file_basename(LogoImage)); for (int hfi = 0; hfi < MAX_HF_IMAGES; ++hfi) if (HFImage[hfi][0]) fprintf(*out, "\n", file_basename(HFImage[hfi])); if (TitlePage) fputs("Contents\n", *out); else fputs("Contents\n", *out); if (t->prev != NULL) fprintf(*out, "Previous\n", file_basename((char *)htmlGetVariable(t->prev, (uchar *)"_HD_FILENAME"))); if (t->next != NULL) fprintf(*out, "Next\n", file_basename((char *)htmlGetVariable(t->next, (uchar *)"_HD_FILENAME"))); fputs("
    \n", *out); } } /* * 'write_footer()' - Output the standard "footer" for a HTML file. */ static void write_footer(FILE **out, /* IO - Output file pointer */ tree_t *t) /* I - Current document file */ { if (*out == NULL) return; if (OutputFiles && t != NULL && (t->prev != NULL || t->next != NULL)) { fputs("
    \n", *out); if (LogoImage[0]) fprintf(*out, "\n", file_basename(LogoImage)); for (int hfi = 0; hfi < MAX_HF_IMAGES; ++hfi) if (HFImage[hfi][0]) fprintf(*out, "\n", file_basename(HFImage[hfi])); if (TitlePage) fputs("Contents\n", *out); else fputs("Contents\n", *out); if (t->prev != NULL) fprintf(*out, "Previous\n", file_basename((char *)htmlGetVariable(t->prev, (uchar *)"_HD_FILENAME"))); if (t->next != NULL) fprintf(*out, "Next\n", file_basename((char *)htmlGetVariable(t->next, (uchar *)"_HD_FILENAME"))); } if (OutputFiles) { fputs("\n", *out); fputs("\n", *out); progress_error(HD_ERROR_NONE, "BYTES: %ld", ftell(*out)); fclose(*out); *out = NULL; } } /* * 'write_title()' - Write a title page... */ static void write_title(FILE *out, /* I - Output file */ uchar *title, /* I - Title for document */ uchar *author, /* I - Author for document */ uchar *copyright, /* I - Copyright for document */ uchar *docnumber) /* I - ID number for document */ { FILE *fp; /* Title file */ const char *title_ext, /* Extension of title file */ *title_file; /* Location of title file */ tree_t *t; /* Title file document tree */ if (out == NULL) return; title_ext = file_extension(TitleImage); #ifdef WIN32 if (TitleImage[0] && stricmp(title_ext, "bmp") != 0 && stricmp(title_ext, "gif") != 0 && stricmp(title_ext, "jpg") != 0 && stricmp(title_ext, "png") != 0) #else if (TitleImage[0] && strcmp(title_ext, "bmp") != 0 && strcmp(title_ext, "gif") != 0 && strcmp(title_ext, "jpg") != 0 && strcmp(title_ext, "png") != 0) #endif // WIN32 { // Find the title page file... if ((title_file = file_find(Path, TitleImage)) == NULL) { progress_error(HD_ERROR_FILE_NOT_FOUND, "Unable to find title file \"%s\"!", TitleImage); return; } // Write a title page from HTML source... if ((fp = fopen(title_file, "rb")) == NULL) { progress_error(HD_ERROR_FILE_NOT_FOUND, "Unable to open title file \"%s\" - %s!", TitleImage, strerror(errno)); return; } #ifdef _WIN32 if (!stricmp(title_ext, "md")) #else if (!strcmp(title_ext, "md")) #endif // _WIN32 t = mdReadFile(NULL, fp, file_directory(TitleImage)); else t = htmlReadFile(NULL, fp, file_directory(TitleImage)); htmlFixLinks(t, t, (uchar *)file_directory(TitleImage)); fclose(fp); write_all(out, t, 0); htmlDeleteTree(t); } else { // Write a "standard" title page with image... if (OutputFiles) fputs("
    ", out); else fputs("
    ", out); if (TitleImage[0]) { image_t *img = image_load(TitleImage, !OutputColor); if (OutputFiles) fprintf(out, "
    \n", file_basename((char *)TitleImage), img->width, img->height, title ? (char *)title : ""); else fprintf(out, "
    \n", TitleImage, img->width, img->height, title ? (char *)title : ""); } if (title != NULL) fprintf(out, "

    %s


    \n", title); else fputs("\n", out); if (docnumber != NULL) fprintf(out, "%s
    \n", docnumber); if (author != NULL) fprintf(out, "%s
    \n", author); if (copyright != NULL) fprintf(out, "%s
    \n", copyright); fputs("
    \n", out); } } /* * 'write_all()' - Write all markup text for the given tree. */ static int /* O - Current column */ write_all(FILE *out, /* I - Output file */ tree_t *t, /* I - Document tree */ int col) /* I - Current column */ { if (out == NULL) return (0); while (t != NULL) { col = write_node(out, t, col); if (t->markup != MARKUP_HEAD && t->markup != MARKUP_TITLE) col = write_all(out, t->child, col); col = write_nodeclose(out, t, col); t = t->next; } return (col); } /* * 'write_node()' - Write a single tree node. */ static int /* O - Current column */ write_node(FILE *out, /* I - Output file */ tree_t *t, /* I - Document tree node */ int col) /* I - Current column */ { int i; /* Looping var */ uchar *ptr, /* Pointer to output string */ *entity, /* Entity string */ *src, /* Source image */ *realsrc, /* Real source image */ newsrc[1024]; /* New source image filename */ if (out == NULL) return (0); switch (t->markup) { case MARKUP_NONE : if (t->data == NULL) break; if (t->preformatted) { for (ptr = t->data; *ptr; ptr ++) fputs((char *)iso8859(*ptr), out); if (t->data[strlen((char *)t->data) - 1] == '\n') col = 0; else col += strlen((char *)t->data); } else { if ((col + (int)strlen((char *)t->data)) > 72 && col > 0) { putc('\n', out); col = 0; } for (ptr = t->data; *ptr; ptr ++) fputs((char *)iso8859(*ptr), out); col += strlen((char *)t->data); if (col > 72) { putc('\n', out); col = 0; } } break; case MARKUP_COMMENT : case MARKUP_UNKNOWN : fputs("\n\n", out); col = 0; break; case MARKUP_AREA : case MARKUP_BODY : case MARKUP_DOCTYPE : case MARKUP_ERROR : case MARKUP_FILE : case MARKUP_HEAD : case MARKUP_HTML : case MARKUP_MAP : case MARKUP_META : case MARKUP_TITLE : break; case MARKUP_BR : case MARKUP_CENTER : case MARKUP_DD : case MARKUP_DL : case MARKUP_DT : case MARKUP_H1 : case MARKUP_H2 : case MARKUP_H3 : case MARKUP_H4 : case MARKUP_H5 : case MARKUP_H6 : case MARKUP_H7 : case MARKUP_H8 : case MARKUP_H9 : case MARKUP_H10 : case MARKUP_H11 : case MARKUP_H12 : case MARKUP_H13 : case MARKUP_H14 : case MARKUP_H15 : case MARKUP_HR : case MARKUP_LI : case MARKUP_OL : case MARKUP_P : case MARKUP_PRE : case MARKUP_TABLE : case MARKUP_TR : case MARKUP_UL : if (col > 0) { putc('\n', out); col = 0; } default : if (t->markup == MARKUP_IMG && OutputFiles && (src = htmlGetVariable(t, (uchar *)"SRC")) != NULL && (realsrc = htmlGetVariable(t, (uchar *)"REALSRC")) != NULL) { /* * Update and copy local images... */ if (file_method((char *)src) == NULL && src[0] != '/' && src[0] != '\\' && (!isalpha(src[0]) || src[1] != ':')) { image_copy((char *)src, (char *)realsrc, OutputPath); strlcpy((char *)newsrc, file_basename((char *)src), sizeof(newsrc)); htmlSetVariable(t, (uchar *)"SRC", newsrc); } } if (t->markup != MARKUP_EMBED) { col += fprintf(out, "<%s", _htmlMarkups[t->markup]); for (i = 0; i < t->nvars; i ++) { if (strcasecmp((char *)t->vars[i].name, "BREAK") == 0 && t->markup == MARKUP_HR) continue; if (strcasecmp((char *)t->vars[i].name, "REALSRC") == 0 && t->markup == MARKUP_IMG) continue; if (strncasecmp((char *)t->vars[i].name, "_HD_", 4) == 0) continue; if (col > 72 && !t->preformatted) { putc('\n', out); col = 0; } if (col > 0) { putc(' ', out); col ++; } if (t->vars[i].value == NULL) col += fprintf(out, "%s", t->vars[i].name); else { col += fprintf(out, "%s=\"", t->vars[i].name); for (ptr = t->vars[i].value; *ptr; ptr ++) { entity = iso8859(*ptr); fputs((char *)entity, out); col += strlen((char *)entity); } putc('\"', out); col ++; } } putc('>', out); col ++; if (col > 72 && !t->preformatted) { putc('\n', out); col = 0; } } break; } return (col); } /* * 'write_nodeclose()' - Close a single tree node. */ static int /* O - Current column */ write_nodeclose(FILE *out, /* I - Output file */ tree_t *t, /* I - Document tree node */ int col) /* I - Current column */ { if (out == NULL) return (0); if (t->markup != MARKUP_HEAD && t->markup != MARKUP_TITLE) { if (col > 72 && !t->preformatted) { putc('\n', out); col = 0; } switch (t->markup) { case MARKUP_BODY : case MARKUP_ERROR : case MARKUP_FILE : case MARKUP_HEAD : case MARKUP_HTML : case MARKUP_NONE : case MARKUP_TITLE : case MARKUP_APPLET : case MARKUP_AREA : case MARKUP_BR : case MARKUP_COMMENT : case MARKUP_DOCTYPE : case MARKUP_EMBED : case MARKUP_HR : case MARKUP_IMG : case MARKUP_INPUT : case MARKUP_ISINDEX : case MARKUP_LINK : case MARKUP_META : case MARKUP_NOBR : case MARKUP_SPACER : case MARKUP_WBR : case MARKUP_UNKNOWN : break; case MARKUP_CENTER : case MARKUP_DD : case MARKUP_DL : case MARKUP_DT : case MARKUP_H1 : case MARKUP_H2 : case MARKUP_H3 : case MARKUP_H4 : case MARKUP_H5 : case MARKUP_H6 : case MARKUP_H7 : case MARKUP_H8 : case MARKUP_H9 : case MARKUP_H10 : case MARKUP_H11 : case MARKUP_H12 : case MARKUP_H13 : case MARKUP_H14 : case MARKUP_H15 : case MARKUP_LI : case MARKUP_OL : case MARKUP_P : case MARKUP_PRE : case MARKUP_TABLE : case MARKUP_TR : case MARKUP_UL : fprintf(out, "\n", _htmlMarkups[t->markup]); col = 0; break; default : col += fprintf(out, "", _htmlMarkups[t->markup]); break; } } return (col); } /* * 'write_toc()' - Write all markup text for the given table-of-contents. */ static int /* O - Current column */ write_toc(FILE *out, /* I - Output file */ tree_t *t, /* I - Document tree */ int col) /* I - Current column */ { if (out == NULL) return (0); while (t != NULL) { if (htmlGetVariable(t, (uchar *)"_HD_OMIT_TOC") == NULL) { col = write_node(out, t, col); if (t->markup != MARKUP_HEAD && t->markup != MARKUP_TITLE) col = write_toc(out, t->child, col); col = write_nodeclose(out, t, col); } t = t->next; } return (col); } /* * 'get_title()' - Get the title string for the given document... */ static uchar * /* O - Title string */ get_title(tree_t *doc) /* I - Document tree */ { uchar *temp; /* Temporary pointer to title */ while (doc != NULL) { if (doc->markup == MARKUP_TITLE) return (htmlGetText(doc->child)); else if (doc->child != NULL) if ((temp = get_title(doc->child)) != NULL) return (temp); doc = doc->next; } return (NULL); } /* * 'add_link()' - Add a named link... */ static void add_link(uchar *name, /* I - Name of link */ uchar *filename) /* I - File for link */ { link_t *temp; /* New name */ if ((temp = find_link(name)) != NULL) temp->filename = filename; else { // See if we need to allocate memory for links... if (num_links >= alloc_links) { // Allocate more links... alloc_links += ALLOC_LINKS; if (num_links == 0) temp = (link_t *)malloc(sizeof(link_t) * alloc_links); else temp = (link_t *)realloc(links, sizeof(link_t) * alloc_links); if (temp == NULL) { progress_error(HD_ERROR_OUT_OF_MEMORY, "Unable to allocate memory for %d links - %s", alloc_links, strerror(errno)); alloc_links -= ALLOC_LINKS; return; } links = temp; } // Add a new link... temp = links + num_links; num_links ++; strlcpy((char *)temp->name, (char *)name, sizeof(temp->name)); temp->filename = filename; if (num_links > 1) qsort(links, num_links, sizeof(link_t), (compare_func_t)compare_links); } } /* * 'find_link()' - Find a named link... */ static link_t * find_link(uchar *name) /* I - Name to find */ { uchar *target; /* Pointer to target name portion */ link_t key, /* Search key */ *match; /* Matching name entry */ if (name == NULL || num_links == 0) return (NULL); if ((target = (uchar *)file_target((char *)name)) == NULL) return (NULL); strlcpy((char *)key.name, (char *)target, sizeof(key.name)); match = (link_t *)bsearch(&key, links, num_links, sizeof(link_t), (compare_func_t)compare_links); return (match); } /* * 'compare_links()' - Compare two named links. */ static int /* O - 0 = equal, -1 or 1 = not equal */ compare_links(link_t *n1, /* I - First name */ link_t *n2) /* I - Second name */ { return (strcasecmp((char *)n1->name, (char *)n2->name)); } /* * 'scan_links()' - Scan a document for link targets, and keep track of * the files they are in... */ static void scan_links(tree_t *t, /* I - Document tree */ uchar *filename) /* I - Filename */ { uchar *name; /* Name of link */ while (t != NULL) { if (t->markup == MARKUP_FILE) scan_links(t->child, (uchar *)file_basename((char *)htmlGetVariable(t, (uchar *)"_HD_FILENAME"))); else if (t->markup == MARKUP_A && (name = htmlGetVariable(t, (uchar *)"NAME")) != NULL) { add_link(name, filename); scan_links(t->child, filename); } else if (t->child != NULL) scan_links(t->child, filename); t = t->next; } } /* * 'update_links()' - Update links as needed. */ static void update_links(tree_t *t, /* I - Document tree */ uchar *filename) /* I - Current filename */ { link_t *link; /* Link */ uchar *href; /* Reference name */ uchar newhref[1024]; /* New reference name */ filename = (uchar *)file_basename((char *)filename); if (OutputFiles) { /* * Need to preserve/add filenames. */ while (t != NULL) { if (t->markup == MARKUP_A && (href = htmlGetVariable(t, (uchar *)"HREF")) != NULL) { /* * Update this link as needed... */ if (href[0] == '#' && (link = find_link(href)) != NULL) { #if defined(WIN32) || defined(__EMX__) if (filename == NULL || strcasecmp((char *)filename, (char *)link->filename) != 0) #else if (filename == NULL || strcmp((char *)filename, (char *)link->filename) != 0) #endif /* WIN32 || __EMX__ */ { snprintf((char *)newhref, sizeof(newhref), "%s%s", link->filename, href); htmlSetVariable(t, (uchar *)"HREF", newhref); } } } if (t->child != NULL) { if (t->markup == MARKUP_FILE) update_links(t->child, htmlGetVariable(t, (uchar *)"_HD_FILENAME")); else update_links(t->child, filename); } t = t->next; } } else { /* * Need to strip filenames. */ while (t != NULL) { if (t->markup == MARKUP_A && (href = htmlGetVariable(t, (uchar *)"HREF")) != NULL) { /* * Update this link as needed... */ if (href[0] != '#' && file_method((char *)href) == NULL && (link = find_link(href)) != NULL) { snprintf((char *)newhref, sizeof(newhref), "#%s", link->name); htmlSetVariable(t, (uchar *)"HREF", newhref); } } if (t->child != NULL) update_links(t->child, filename); t = t->next; } } } htmldoc-1.9.7/htmldoc/html.h000066400000000000000000000146431354715574200157560ustar00rootroot00000000000000/* * HTML parsing definitions for HTMLDOC, a HTML document processing program. * * Copyright 2011-2019 by Michael R Sweet. * Copyright 1997-2010 by Easy Software Products. All rights reserved. * * This program is free software. Distribution and use rights are outlined in * the file "COPYING". */ #ifndef _HTML_H_ # define _HTML_H_ /* * Include necessary headers... */ # include # include # include "file.h" # include "hdstring.h" # include "iso8859.h" # ifdef __cplusplus extern "C" { # endif /* __cplusplus */ /* * Define some compatibility macros for Microsoft Windows... */ # ifdef WIN32 # define strcasecmp(s,t) stricmp(s,t) # define strncasecmp(s,t,n) strnicmp(s,t,n) # endif /* WIN32 */ /* * Markup constants... */ typedef enum { MARKUP_FILE = -3, /* File Delimiter */ MARKUP_UNKNOWN = -2, /* Unknown element */ MARKUP_ERROR = -1, MARKUP_NONE = 0, MARKUP_COMMENT, MARKUP_DOCTYPE, MARKUP_A, MARKUP_ACRONYM, MARKUP_ADDRESS, MARKUP_APPLET, MARKUP_AREA, MARKUP_B, MARKUP_BASE, MARKUP_BASEFONT, MARKUP_BIG, MARKUP_BLINK, MARKUP_BLOCKQUOTE, MARKUP_BODY, MARKUP_BR, MARKUP_CAPTION, MARKUP_CENTER, MARKUP_CITE, MARKUP_CODE, MARKUP_COL, MARKUP_COLGROUP, MARKUP_DD, MARKUP_DEL, MARKUP_DFN, MARKUP_DIR, MARKUP_DIV, MARKUP_DL, MARKUP_DT, MARKUP_EM, MARKUP_EMBED, MARKUP_FONT, MARKUP_FORM, MARKUP_FRAME, MARKUP_FRAMESET, MARKUP_H1, MARKUP_H2, MARKUP_H3, MARKUP_H4, MARKUP_H5, MARKUP_H6, MARKUP_H7, MARKUP_H8, MARKUP_H9, MARKUP_H10, MARKUP_H11, MARKUP_H12, MARKUP_H13, MARKUP_H14, MARKUP_H15, MARKUP_HEAD, MARKUP_HR, MARKUP_HTML, MARKUP_I, MARKUP_IMG, MARKUP_INPUT, MARKUP_INS, MARKUP_ISINDEX, MARKUP_KBD, MARKUP_LI, MARKUP_LINK, MARKUP_MAP, MARKUP_MENU, MARKUP_META, MARKUP_MULTICOL, MARKUP_NOBR, MARKUP_NOFRAMES, MARKUP_OL, MARKUP_OPTION, MARKUP_P, MARKUP_PRE, MARKUP_S, MARKUP_SAMP, MARKUP_SCRIPT, MARKUP_SELECT, MARKUP_SMALL, MARKUP_SPACER, MARKUP_SPAN, MARKUP_STRIKE, MARKUP_STRONG, MARKUP_STYLE, MARKUP_SUB, MARKUP_SUP, MARKUP_TABLE, MARKUP_TBODY, MARKUP_TD, MARKUP_TEXTAREA, MARKUP_TFOOT, MARKUP_TH, MARKUP_THEAD, MARKUP_TITLE, MARKUP_TR, MARKUP_TT, MARKUP_U, MARKUP_UL, MARKUP_VAR, MARKUP_WBR } markup_t; /* * Horizontal alignment... */ typedef enum { ALIGN_LEFT = 0, ALIGN_CENTER, ALIGN_RIGHT, ALIGN_JUSTIFY } halignment_t; /* * Vertical alignment... */ typedef enum { ALIGN_TOP = 0, ALIGN_MIDDLE, ALIGN_BOTTOM } valignment_t; /* * Typeface... */ typedef enum { TYPE_COURIER = 0, TYPE_TIMES, TYPE_HELVETICA, TYPE_MONOSPACE, TYPE_SERIF, TYPE_SANS_SERIF, TYPE_SYMBOL, TYPE_DINGBATS } typeface_t; #define TYPE_MAX (typeface_t)(TYPE_DINGBATS + 1) /* * Style... */ typedef enum { STYLE_NORMAL = 0, STYLE_BOLD, STYLE_ITALIC, STYLE_BOLD_ITALIC } style_t; #define STYLE_MAX (style_t)(STYLE_BOLD_ITALIC + 1) /* * Sizes... */ # define SIZE_H1 6 # define SIZE_H2 5 # define SIZE_H3 4 # define SIZE_H4 3 # define SIZE_H5 2 # define SIZE_H6 1 # define SIZE_H7 0 # define SIZE_P 3 # define SIZE_PRE 2 # define SIZE_SUB -2 # define SIZE_SUP -2 /* * Markup variables... */ typedef struct { uchar *name, /* Variable name */ *value; /* Variable value */ } var_t; /* * Parsing tree... */ typedef struct tree_str { struct tree_str *parent, /* Parent tree entry */ *child, /* First child entry */ *last_child, /* Last child entry */ *prev, /* Previous entry on this level */ *next, /* Next entry on this level */ *link; /* Linked-to */ markup_t markup; /* Markup code */ uchar *data; /* Text (MARKUP_NONE or MARKUP_COMMENT) */ unsigned halignment:2, /* Horizontal alignment */ valignment:2, /* Vertical alignment */ typeface:3, /* Typeface code */ size:3, /* Size of text */ style:2, /* Style of text */ underline:1, /* Text is underlined? */ strikethrough:1,/* Text is struck-through? */ subscript:1, /* Text is subscripted? */ superscript:1, /* Text is superscripted? */ preformatted:1, /* Preformatted text? */ indent:4; /* Indentation level 0-15 */ uchar red, /* Color of this fragment */ green, blue; float width, /* Width of this fragment in points */ height; /* Height of this fragment in points */ int nvars; /* Number of variables... */ var_t *vars; /* Variables... */ } tree_t; /* * Globals... */ extern const char *_htmlCurrentFile; extern const char *_htmlMarkups[]; extern const char *_htmlData; extern float _htmlPPI; extern int _htmlGrayscale; extern uchar _htmlTextColor[]; extern float _htmlBrowserWidth; extern float _htmlSizes[], _htmlSpacings[]; extern typeface_t _htmlBodyFont, _htmlHeadingFont; extern int _htmlInitialized; extern char _htmlCharSet[]; extern int _htmlWidthsLoaded[TYPE_MAX][STYLE_MAX]; extern short _htmlWidths[TYPE_MAX][STYLE_MAX][256]; extern short _htmlWidthsAll[TYPE_MAX][STYLE_MAX][65536]; extern int _htmlUnicode[]; extern uchar _htmlCharacters[]; extern int _htmlUTF8; extern const char *_htmlGlyphs[]; extern const char *_htmlGlyphsAll[]; extern const char *_htmlFonts[TYPE_MAX][STYLE_MAX]; extern int _htmlStandardFonts[TYPE_MAX]; /* * Prototypes... */ extern tree_t *htmlReadFile(tree_t *parent, FILE *fp, const char *base); extern int htmlWriteFile(tree_t *parent, FILE *fp); extern tree_t *htmlAddTree(tree_t *parent, markup_t markup, uchar *data); extern int htmlDeleteTree(tree_t *parent); extern tree_t *htmlInsertTree(tree_t *parent, markup_t markup, uchar *data); extern tree_t *htmlNewTree(tree_t *parent, markup_t markup, uchar *data); extern tree_t *htmlFindFile(tree_t *doc, uchar *filename); extern tree_t *htmlFindTarget(tree_t *doc, uchar *name); extern void htmlFixLinks(tree_t *doc, tree_t *tree, uchar *base = 0); extern uchar *htmlGetText(tree_t *tree); extern uchar *htmlGetMeta(tree_t *tree, uchar *name); extern uchar *htmlGetVariable(tree_t *t, uchar *name); extern int htmlSetVariable(tree_t *t, uchar *name, uchar *value); extern uchar *htmlGetStyle(tree_t *t, uchar *name); extern void htmlSetBaseSize(double p, double s); extern void htmlSetCharSet(const char *cs); extern void htmlSetTextColor(uchar *color); extern void htmlLoadFontWidths(int typeface, int style); extern void htmlDebugStats(const char *title, tree_t *t); # ifdef __cplusplus } # endif /* __cplusplus */ #endif /* !_HTML_H_ */ htmldoc-1.9.7/htmldoc/htmldoc.cxx000066400000000000000000002224611354715574200170160ustar00rootroot00000000000000/* * Main entry for HTMLDOC, a HTML document processing program. * * Copyright 2011-2019 by Michael R Sweet. * Copyright 1997-2010 by Easy Software Products. All rights reserved. * * This program is free software. Distribution and use rights are outlined in * the file "COPYING". */ /* * Include necessary headers. */ #define _HTMLDOC_CXX_ #include "htmldoc.h" #include "markdown.h" #include "http.h" #include #include #ifdef HAVE_LOCALE_H # include #endif // HAVE_LOCALE_H #ifdef WIN32 # include # include #else # include # include # include #endif // WIN32 #ifdef __APPLE__ # include #endif // __APPLE__ #ifdef __EMX__ extern "C" { const char *__XOS2RedirRoot(const char *); } #endif /* * Local types... */ typedef int (*exportfunc_t)(tree_t *, tree_t *); /* * Local functions... */ static int compare_strings(const char *s, const char *t, int tmin); static double get_seconds(void); static int load_book(const char *filename, tree_t **document, exportfunc_t *exportfunc, int set_nolocal = 0); static void parse_options(const char *line, exportfunc_t *exportfunc); static const char *prefs_getrc(void); static int read_file(const char *filename, tree_t **document, const char *path); static void set_permissions(const char *p); #ifndef WIN32 extern "C" { static void term_handler(int signum); } #endif // !WIN32 static void usage(const char *arg = NULL); /* * 'main()' - Main entry for HTMLDOC. */ int main(int argc, /* I - Number of command-line arguments */ char *argv[]) /* I - Command-line arguments */ { int i, j; /* Looping vars */ tree_t *document, /* Master HTML document */ *file, /* HTML document file */ *toc; /* Table of contents */ exportfunc_t exportfunc; /* Export function */ const char *extension; /* Extension of output filename */ double fontsize, /* Base font size */ fontspacing; /* Base font spacing */ int num_files; /* Number of files provided on the command-line */ double start_time, /* Start time */ load_time, /* Load time */ end_time; /* End time */ const char *debug; /* HTMLDOC_DEBUG environment variable */ start_time = get_seconds(); #ifdef __APPLE__ /* * OSX passes an extra command-line option when run from the Finder. * If the first command-line argument is "-psn..." then skip it... */ if (argc > 1 && strncmp(argv[1], "-psn", 4) == 0) { argv ++; argc --; } #endif // __APPLE__ /* * Localize as needed... */ #ifdef HAVE_LOCALE_H setlocale(LC_TIME, ""); #endif // HAVE_LOCALE_H /* * Catch CTRL-C and term signals... */ #ifdef WIN32 #else signal(SIGTERM, term_handler); #endif // WIN32 /* * Set the location of data and help files... */ prefs_set_paths(); /* * Check if we are being executed as a CGI program... * * Note: We can't short-circuit this test to include a check for * PATH_INFO since that could lead to a remote execution hole. * Instead, we'll display an error message later if we can't find * a PATH_INFO variable and advise the administrator on how to * correct the problem... */ if (!getenv("HTMLDOC_NOCGI") && getenv("GATEWAY_INTERFACE") && getenv("SERVER_NAME") && getenv("SERVER_SOFTWARE")) { const char *path_translated; // PATH_TRANSLATED env var char bookfile[1024]; // Book filename // CGI mode implies the following options: // // --no-localfiles // --webpage // -t pdf // -f - // // Additional args cannot be provided on the command-line, however // we load directory-specific options from the ".book" file in the // current web server directory... CGIMode = 1; TocLevels = 0; TitlePage = 0; OutputPath[0] = '\0'; OutputType = OUTPUT_WEBPAGES; document = NULL; exportfunc = (exportfunc_t)pspdf_export; PSLevel = 0; PDFVersion = 14; PDFPageMode = PDF_DOCUMENT; PDFFirstPage = PDF_PAGE_1; file_cookies(getenv("HTTP_COOKIE")); file_referer(getenv("HTTP_REFERER")); progress_error(HD_ERROR_NONE, "INFO: HTMLDOC " SVERSION " starting in CGI mode."); #ifdef WIN32 progress_error(HD_ERROR_NONE, "INFO: TEMP is \"%s\"", getenv("TEMP")); #else progress_error(HD_ERROR_NONE, "INFO: TMPDIR is \"%s\"", getenv("TMPDIR")); #endif // WIN32 argc = 1; // Look for a book file in the following order: // // $PATH_TRANSLATED.book // `dirname $PATH_TRANSLATED`/.book // .book // // If we find one, use it... if ((path_translated = getenv("PATH_TRANSLATED")) != NULL) { // Try $PATH_TRANSLATED.book... snprintf(bookfile, sizeof(bookfile), "%s.book", path_translated); if (access(bookfile, 0)) { // Not found, try `dirname $PATH_TRANSLATED`/.book snprintf(bookfile, sizeof(bookfile), "%s/.book", file_directory(path_translated)); if (access(bookfile, 0)) strlcpy(bookfile, ".book", sizeof(bookfile)); } } else strlcpy(bookfile, ".book", sizeof(bookfile)); if (!access(bookfile, 0)) load_book(bookfile, &document, &exportfunc, 1); else file_nolocal(); } else { /* * Default to producing HTML files. */ document = NULL; exportfunc = (exportfunc_t)html_export; /* * Load preferences... */ prefs_load(); } /* * Parse command-line options... */ fontsize = 11.0f; fontspacing = 1.2f; num_files = 0; Errors = 0; for (i = 1; i < argc; i ++) { #ifdef DEBUG printf("argv[%d] = \"%s\"\n", i, argv[i]); #endif // DEBUG if (compare_strings(argv[i], "--batch", 4) == 0) { i ++; if (i < argc) { num_files ++; load_book(argv[i], &document, &exportfunc); } else usage(argv[i - 1]); } else if (compare_strings(argv[i], "--bodycolor", 7) == 0) { i ++; if (i < argc) strlcpy((char *)BodyColor, argv[i], sizeof(BodyColor)); else usage(argv[i - 1]); } else if (compare_strings(argv[i], "--bodyfont", 7) == 0 || compare_strings(argv[i], "--textfont", 7) == 0) { i ++; if (i < argc) { if (!strcasecmp(argv[i], "monospace")) _htmlBodyFont = TYPE_MONOSPACE; else if (!strcasecmp(argv[i], "serif")) _htmlBodyFont = TYPE_SERIF; else if (!strcasecmp(argv[i], "sans-serif") || !strcasecmp(argv[i], "sans")) _htmlBodyFont = TYPE_SANS_SERIF; else if (!strcasecmp(argv[i], "courier")) _htmlBodyFont = TYPE_COURIER; else if (!strcasecmp(argv[i], "times")) _htmlBodyFont = TYPE_TIMES; else if (!strcasecmp(argv[i], "helvetica") || !strcasecmp(argv[i], "arial")) _htmlBodyFont = TYPE_HELVETICA; } else usage(argv[i - 1]); } else if (compare_strings(argv[i], "--bodyimage", 7) == 0) { i ++; if (i < argc) strlcpy((char *)BodyImage, argv[i], sizeof(BodyImage)); else usage(argv[i - 1]); } else if (compare_strings(argv[i], "--book", 5) == 0) OutputType = OUTPUT_BOOK; else if (compare_strings(argv[i], "--bottom", 5) == 0) { i ++; if (i < argc) PageBottom = get_measurement(argv[i]); else usage(argv[i - 1]); } else if (compare_strings(argv[i], "--browserwidth", 4) == 0) { i ++; if (i < argc) { _htmlBrowserWidth = atof(argv[i]); if (_htmlBrowserWidth < 1.0f) { progress_error(HD_ERROR_INTERNAL_ERROR, "Bad browser width \"%s\"!", argv[i]); usage(); } } else usage(argv[i - 1]); } else if (compare_strings(argv[i], "--charset", 4) == 0) { i ++; if (i < argc) htmlSetCharSet(argv[i]); else usage(argv[i - 1]); } else if (compare_strings(argv[i], "--color", 5) == 0) { OutputColor = 1; _htmlGrayscale = 0; } else if (compare_strings(argv[i], "--compression", 5) == 0 || strncmp(argv[i], "--compression=", 14) == 0) { if (strlen(argv[i]) > 14 && PDFVersion >= 12) Compression = atoi(argv[i] + 14); else if (PDFVersion >= 12) Compression = 1; } else if (compare_strings(argv[i], "--continuous", 5) == 0) { TocLevels = 0; TitlePage = 0; OutputType = OUTPUT_CONTINUOUS; PDFPageMode = PDF_DOCUMENT; PDFFirstPage = PDF_PAGE_1; } else if (compare_strings(argv[i], "--cookies", 5) == 0) { i ++; if (i < argc) file_cookies(argv[i]); else usage(argv[i - 1]); } else if (compare_strings(argv[i], "--datadir", 4) == 0) { i ++; if (i < argc) _htmlData = argv[i]; else usage(argv[i - 1]); } #if defined(HAVE_LIBFLTK) && !WIN32 else if (compare_strings(argv[i], "-display", 3) == 0 || compare_strings(argv[i], "--display", 4) == 0) { // The X standard requires support for the -display option, but // we also support the GNU standard --display... i ++; if (i < argc) Fl::display(argv[i]); else usage(argv[i - 1]); } #endif // HAVE_LIBFLTK && !WIN32 else if (compare_strings(argv[i], "--duplex", 4) == 0) PageDuplex = 1; else if (compare_strings(argv[i], "--effectduration", 4) == 0) { i ++; if (i < argc) { PDFEffectDuration = atof(argv[i]); if (PDFEffectDuration < 0.0f) { progress_error(HD_ERROR_INTERNAL_ERROR, "Bad effect duration \"%s\"!", argv[i]); usage(); } } else usage(argv[i - 1]); } else if (compare_strings(argv[i], "--embedfonts", 4) == 0) EmbedFonts = 1; else if (compare_strings(argv[i], "--encryption", 4) == 0) Encryption = 1; else if (compare_strings(argv[i], "--firstpage", 4) == 0) { i ++; if (i >= argc) usage(argv[i - 1]); for (j = 0; j < (int)(sizeof(PDFPages) / sizeof(PDFPages[0])); j ++) if (strcasecmp(argv[i], PDFPages[j]) == 0) { PDFFirstPage = j; break; } } else if (compare_strings(argv[i], "--fontsize", 8) == 0) { i ++; if (i < argc) { fontsize = atof(argv[i]); if (fontsize < 4.0f) fontsize = 4.0f; else if (fontsize > 24.0f) fontsize = 24.0f; htmlSetBaseSize(fontsize, fontspacing); } else usage(argv[i - 1]); } else if (compare_strings(argv[i], "--fontspacing", 8) == 0) { i ++; if (i < argc) { fontspacing = atof(argv[i]); if (fontspacing < 1.0f) fontspacing = 1.0f; else if (fontspacing > 3.0f) fontspacing = 3.0f; htmlSetBaseSize(fontsize, fontspacing); } else usage(argv[i - 1]); } else if (compare_strings(argv[i], "--footer", 5) == 0) { i ++; if (i < argc) get_format(argv[i], Footer); else usage(argv[i - 1]); } else if (compare_strings(argv[i], "--format", 5) == 0 || strcmp(argv[i], "-t") == 0) { i ++; if (i < argc) { if (strcasecmp(argv[i], "epub") == 0) exportfunc = (exportfunc_t)epub_export; else if (strcasecmp(argv[i], "html") == 0) exportfunc = (exportfunc_t)html_export; else if (strcasecmp(argv[i], "htmlsep") == 0) exportfunc = (exportfunc_t)htmlsep_export; else if (strcasecmp(argv[i], "pdf14") == 0 || strcasecmp(argv[i], "pdf") == 0) { exportfunc = (exportfunc_t)pspdf_export; PSLevel = 0; PDFVersion = 14; } else if (strcasecmp(argv[i], "pdf13") == 0) { exportfunc = (exportfunc_t)pspdf_export; PSLevel = 0; PDFVersion = 13; } else if (strcasecmp(argv[i], "pdf12") == 0) { exportfunc = (exportfunc_t)pspdf_export; PSLevel = 0; PDFVersion = 12; } else if (strcasecmp(argv[i], "pdf11") == 0) { exportfunc = (exportfunc_t)pspdf_export; PSLevel = 0; PDFVersion = 11; Compression = 0; } else if (strcasecmp(argv[i], "ps1") == 0) { exportfunc = (exportfunc_t)pspdf_export; PSLevel = 1; } else if (strcasecmp(argv[i], "ps2") == 0 || strcasecmp(argv[i], "ps") == 0) { exportfunc = (exportfunc_t)pspdf_export; PSLevel = 2; } else if (strcasecmp(argv[i], "ps3") == 0) { exportfunc = (exportfunc_t)pspdf_export; PSLevel = 3; } else usage(argv[i - 1]); } else usage(argv[i - 1]); } else if (compare_strings(argv[i], "--grayscale", 3) == 0) { OutputColor = 0; _htmlGrayscale = 1; } else if (!strcmp(argv[i], "--header")) { i ++; if (i < argc) get_format(argv[i], Header); else usage(argv[i - 1]); } else if (!strcmp(argv[i], "--header1")) { i ++; if (i < argc) get_format(argv[i], Header1); else usage(argv[i - 1]); } else if (!compare_strings(argv[i], "--headfootfont", 11)) { i ++; if (i < argc) { if (!strcasecmp(argv[i], "courier")) { HeadFootType = TYPE_COURIER; HeadFootStyle = STYLE_NORMAL; } else if (!strcasecmp(argv[i], "courier-bold")) { HeadFootType = TYPE_COURIER; HeadFootStyle = STYLE_BOLD; } else if (!strcasecmp(argv[i], "courier-oblique")) { HeadFootType = TYPE_COURIER; HeadFootStyle = STYLE_ITALIC; } else if (!strcasecmp(argv[i], "courier-boldoblique")) { HeadFootType = TYPE_COURIER; HeadFootStyle = STYLE_BOLD_ITALIC; } else if (!strcasecmp(argv[i], "times") || !strcasecmp(argv[i], "times-roman")) { HeadFootType = TYPE_TIMES; HeadFootStyle = STYLE_NORMAL; } else if (!strcasecmp(argv[i], "times-bold")) { HeadFootType = TYPE_TIMES; HeadFootStyle = STYLE_BOLD; } else if (!strcasecmp(argv[i], "times-italic")) { HeadFootType = TYPE_TIMES; HeadFootStyle = STYLE_ITALIC; } else if (!strcasecmp(argv[i], "times-bolditalic")) { HeadFootType = TYPE_TIMES; HeadFootStyle = STYLE_BOLD_ITALIC; } else if (!strcasecmp(argv[i], "helvetica")) { HeadFootType = TYPE_HELVETICA; HeadFootStyle = STYLE_NORMAL; } else if (!strcasecmp(argv[i], "helvetica-bold")) { HeadFootType = TYPE_HELVETICA; HeadFootStyle = STYLE_BOLD; } else if (!strcasecmp(argv[i], "helvetica-oblique")) { HeadFootType = TYPE_HELVETICA; HeadFootStyle = STYLE_ITALIC; } else if (!strcasecmp(argv[i], "helvetica-boldoblique")) { HeadFootType = TYPE_HELVETICA; HeadFootStyle = STYLE_BOLD_ITALIC; } else if (!strcasecmp(argv[i], "monospace")) { HeadFootType = TYPE_MONOSPACE; HeadFootStyle = STYLE_NORMAL; } else if (!strcasecmp(argv[i], "monospace-bold")) { HeadFootType = TYPE_MONOSPACE; HeadFootStyle = STYLE_BOLD; } else if (!strcasecmp(argv[i], "monospace-oblique")) { HeadFootType = TYPE_MONOSPACE; HeadFootStyle = STYLE_ITALIC; } else if (!strcasecmp(argv[i], "monospace-boldoblique")) { HeadFootType = TYPE_MONOSPACE; HeadFootStyle = STYLE_BOLD_ITALIC; } else if (!strcasecmp(argv[i], "serif") || !strcasecmp(argv[i], "serif-roman")) { HeadFootType = TYPE_SERIF; HeadFootStyle = STYLE_NORMAL; } else if (!strcasecmp(argv[i], "serif-bold")) { HeadFootType = TYPE_SERIF; HeadFootStyle = STYLE_BOLD; } else if (!strcasecmp(argv[i], "serif-italic")) { HeadFootType = TYPE_SERIF; HeadFootStyle = STYLE_ITALIC; } else if (!strcasecmp(argv[i], "serif-bolditalic")) { HeadFootType = TYPE_SERIF; HeadFootStyle = STYLE_BOLD_ITALIC; } else if (!strcasecmp(argv[i], "sans-serif") || !strcasecmp(argv[i], "sans")) { HeadFootType = TYPE_SANS_SERIF; HeadFootStyle = STYLE_NORMAL; } else if (!strcasecmp(argv[i], "sans-serif-bold") || !strcasecmp(argv[i], "sans-bold")) { HeadFootType = TYPE_SANS_SERIF; HeadFootStyle = STYLE_BOLD; } else if (!strcasecmp(argv[i], "sans-serif-oblique") || !strcasecmp(argv[i], "sans-oblique")) { HeadFootType = TYPE_SANS_SERIF; HeadFootStyle = STYLE_ITALIC; } else if (!strcasecmp(argv[i], "sans-serif-boldoblique") || !strcasecmp(argv[i], "sans-boldoblique")) { HeadFootType = TYPE_SANS_SERIF; HeadFootStyle = STYLE_BOLD_ITALIC; } } else usage(argv[i - 1]); } else if (compare_strings(argv[i], "--headfootsize", 11) == 0) { i ++; if (i < argc) { HeadFootSize = atof(argv[i]); if (HeadFootSize < 6.0f) HeadFootSize = 6.0f; else if (HeadFootSize > 24.0f) HeadFootSize = 24.0f; } else usage(argv[i - 1]); } else if (!compare_strings(argv[i], "--headingfont", 7)) { i ++; if (i < argc) { if (!strcasecmp(argv[i], "courier")) _htmlHeadingFont = TYPE_COURIER; else if (!strcasecmp(argv[i], "times")) _htmlHeadingFont = TYPE_TIMES; else if (!strcasecmp(argv[i], "helvetica") || !strcasecmp(argv[i], "arial")) _htmlHeadingFont = TYPE_HELVETICA; else if (!strcasecmp(argv[i], "monospace")) _htmlHeadingFont = TYPE_MONOSPACE; else if (!strcasecmp(argv[i], "serif")) _htmlHeadingFont = TYPE_SERIF; else if (!strcasecmp(argv[i], "sans-serif") || !strcasecmp(argv[i], "sans")) _htmlHeadingFont = TYPE_SANS_SERIF; } else usage(argv[i - 1]); } else if (compare_strings(argv[i], "--help", 6) == 0) usage(argv[i - 1]); #ifdef HAVE_LIBFLTK else if (compare_strings(argv[i], "--helpdir", 7) == 0) { i ++; if (i < argc) GUI::help_dir = argv[i]; else usage(argv[i - 1]); } #endif // HAVE_LIBFLTK else if (strncmp(argv[i], "--hfimage", 9) == 0) { int hfimgnum; // Image number char *hfptr; // Pointer into option if (strlen(argv[i]) > 9) { hfimgnum = strtol(argv[i] + 9, &hfptr, 10); if (hfimgnum < 0 || hfimgnum >= MAX_HF_IMAGES || *hfptr) usage(argv[i]); } else hfimgnum = 0; i ++; if (i >= argc) usage(argv[i - 1]); strlcpy(HFImage[hfimgnum], argv[i], sizeof(HFImage[0])); } else if (compare_strings(argv[i], "--jpeg", 3) == 0 || strncmp(argv[i], "--jpeg=", 7) == 0) { if (strlen(argv[i]) > 7) OutputJPEG = atoi(argv[i] + 7); else OutputJPEG = 90; } else if (compare_strings(argv[i], "--landscape", 4) == 0) Landscape = 1; else if (compare_strings(argv[i], "--left", 4) == 0) { i ++; if (i < argc) PageLeft = get_measurement(argv[i]); else usage(argv[i - 1]); } else if (compare_strings(argv[i], "--linkcolor", 7) == 0) { i ++; if (i < argc) strlcpy(LinkColor, argv[i], sizeof(LinkColor)); else usage(argv[i - 1]); } else if (strcmp(argv[i], "--links") == 0) Links = 1; else if (compare_strings(argv[i], "--linkstyle", 8) == 0) { i ++; if (i < argc) { if (strcmp(argv[i], "plain") == 0) LinkStyle = 0; else if (strcmp(argv[i], "underline") == 0) LinkStyle = 1; else usage(argv[i - 1]); } else usage(argv[i - 1]); } else if (compare_strings(argv[i], "--logoimage", 5) == 0) { i ++; if (i < argc) strlcpy(LogoImage, argv[i], sizeof(LogoImage)); else usage(argv[i - 1]); } else if (compare_strings(argv[i], "--no-compression", 6) == 0) Compression = 0; else if (compare_strings(argv[i], "--no-duplex", 4) == 0) PageDuplex = 0; else if (compare_strings(argv[i], "--no-embedfonts", 7) == 0) EmbedFonts = 0; else if (compare_strings(argv[i], "--no-encryption", 7) == 0) Encryption = 0; else if (compare_strings(argv[i], "--no-jpeg", 6) == 0) OutputJPEG = 0; else if (compare_strings(argv[i], "--no-links", 7) == 0) Links = 0; else if (compare_strings(argv[i], "--no-localfiles", 7) == 0) file_nolocal(); else if (compare_strings(argv[i], "--no-numbered", 6) == 0) TocNumbers = 0; else if (compare_strings(argv[i], "--no-overflow", 6) == 0) OverflowErrors = 0; else if (compare_strings(argv[i], "--no-pscommands", 6) == 0) PSCommands = 0; else if (compare_strings(argv[i], "--no-strict", 6) == 0) StrictHTML = 0; else if (compare_strings(argv[i], "--no-title", 7) == 0) TitlePage = 0; else if (compare_strings(argv[i], "--no-toc", 7) == 0) TocLevels = 0; else if (compare_strings(argv[i], "--no-truetype", 7) == 0) { fputs("htmldoc: Warning, --no-truetype option superseded by --no-embedfonts!\n", stderr); EmbedFonts = 0; } else if (compare_strings(argv[i], "--no-xrxcomments", 6) == 0) XRXComments = 0; else if (compare_strings(argv[i], "--numbered", 5) == 0) TocNumbers = 1; else if (compare_strings(argv[i], "--nup", 5) == 0) { i ++; if (i >= argc) usage(argv[i - 1]); NumberUp = atoi(argv[i]); if (NumberUp != 1 && NumberUp != 2 && NumberUp != 4 && NumberUp != 6 && NumberUp != 9 && NumberUp != 16) usage(argv[i - 1]); } else if (compare_strings(argv[i], "--outdir", 6) == 0 || strcmp(argv[i], "-d") == 0) { i ++; if (i < argc) { strlcpy(OutputPath, argv[i], sizeof(OutputPath)); OutputFiles = 1; } else usage(argv[i - 1]); } else if (compare_strings(argv[i], "--outfile", 6) == 0 || strcmp(argv[i], "-f") == 0) { i ++; if (i < argc) { strlcpy(OutputPath, argv[i], sizeof(OutputPath)); OutputFiles = 0; if ((extension = file_extension(argv[i])) != NULL) { if (strcasecmp(extension, "epub") == 0) exportfunc = (exportfunc_t)epub_export; else if (strcasecmp(extension, "html") == 0) exportfunc = (exportfunc_t)html_export; else if (strcasecmp(extension, "pdf") == 0) { exportfunc = (exportfunc_t)pspdf_export; PSLevel = 0; } else if (strcasecmp(extension, "ps") == 0) { exportfunc = (exportfunc_t)pspdf_export; if (PSLevel == 0) PSLevel = 2; } } } else usage(argv[i - 1]); } else if (compare_strings(argv[i], "--overflow", 4) == 0) OverflowErrors = 1; else if (compare_strings(argv[i], "--owner-password", 4) == 0) { i ++; if (i < argc) strlcpy(OwnerPassword, argv[i], sizeof(OwnerPassword)); else usage(argv[i - 1]); } else if (compare_strings(argv[i], "--pageduration", 7) == 0) { i ++; if (i < argc) { PDFPageDuration = atof(argv[i]); if (PDFPageDuration < 1.0f) { progress_error(HD_ERROR_INTERNAL_ERROR, "Bad page duration \"%s\"!", argv[i]); usage(); } } else usage(argv[i - 1]); } else if (compare_strings(argv[i], "--pageeffect", 7) == 0) { i ++; if (i >= argc) usage(argv[i - 1]); for (j = 0; j < (int)(sizeof(PDFEffects) / sizeof(PDFEffects[0])); j ++) if (strcasecmp(argv[i], PDFEffects[j]) == 0) { PDFEffect = j; break; } } else if (compare_strings(argv[i], "--pagelayout", 7) == 0) { i ++; if (i >= argc) usage(argv[i - 1]); for (j = 0; j < (int)(sizeof(PDFLayouts) / sizeof(PDFLayouts[0])); j ++) if (strcasecmp(argv[i], PDFLayouts[j]) == 0) { PDFPageLayout = j; break; } } else if (compare_strings(argv[i], "--pagemode", 7) == 0) { i ++; if (i >= argc) usage(argv[i - 1]); for (j = 0; j < (int)(sizeof(PDFModes) / sizeof(PDFModes[0])); j ++) if (strcasecmp(argv[i], PDFModes[j]) == 0) { PDFPageMode = j; break; } } else if (compare_strings(argv[i], "--path", 5) == 0) { i ++; if (i < argc) strlcpy(Path, argv[i], sizeof(Path)); else usage(argv[i - 1]); } else if (compare_strings(argv[i], "--permissions", 4) == 0) { i ++; if (i >= argc) usage(argv[i - 1]); set_permissions(argv[i]); } else if (compare_strings(argv[i], "--portrait", 4) == 0) Landscape = 0; else if (compare_strings(argv[i], "--proxy", 4) == 0) { i ++; if (i < argc) { strlcpy(Proxy, argv[i], sizeof(Proxy)); file_proxy(Proxy); } else usage(argv[i - 1]); } else if (compare_strings(argv[i], "--pscommands", 3) == 0) PSCommands = 1; else if (compare_strings(argv[i], "--quiet", 3) == 0) Verbosity = -1; else if (!compare_strings(argv[i], "--referer", 4)) { i ++; if (i < argc) file_referer(argv[i]); else usage(argv[i - 1]); } else if (compare_strings(argv[i], "--right", 4) == 0) { i ++; if (i < argc) PageRight = get_measurement(argv[i]); else usage(argv[i - 1]); } else if (compare_strings(argv[i], "--size", 4) == 0) { i ++; if (i < argc) set_page_size(argv[i]); else usage(argv[i - 1]); } else if (compare_strings(argv[i], "--strict", 4) == 0) StrictHTML = 1; else if (compare_strings(argv[i], "--textcolor", 7) == 0) { i ++; if (i < argc) htmlSetTextColor((uchar *)argv[i]); else usage(argv[i - 1]); } else if (compare_strings(argv[i], "--title", 7) == 0) TitlePage = 1; else if (compare_strings(argv[i], "--titlefile", 8) == 0 || compare_strings(argv[i], "--titleimage", 8) == 0) { i ++; if (i < argc) strlcpy(TitleImage, argv[i], sizeof(TitleImage)); else usage(argv[i - 1]); TitlePage = 1; } else if (compare_strings(argv[i], "--tocfooter", 6) == 0) { i ++; if (i < argc) get_format(argv[i], TocFooter); else usage(argv[i - 1]); } else if (compare_strings(argv[i], "--tocheader", 6) == 0) { i ++; if (i < argc) get_format(argv[i], TocHeader); else usage(argv[i - 1]); } else if (compare_strings(argv[i], "--toclevels", 6) == 0) { i ++; if (i < argc) TocLevels = atoi(argv[i]); else usage(argv[i - 1]); } else if (compare_strings(argv[i], "--toctitle", 6) == 0) { i ++; if (i < argc) strlcpy(TocTitle, argv[i], sizeof(TocTitle)); else usage(argv[i - 1]); } else if (compare_strings(argv[i], "--top", 5) == 0) { i ++; if (i < argc) PageTop = get_measurement(argv[i]); else usage(argv[i - 1]); } else if (compare_strings(argv[i], "--user-password", 4) == 0) { i ++; if (i < argc) strlcpy(UserPassword, argv[i], sizeof(UserPassword)); else usage(argv[i - 1]); } else if (compare_strings(argv[i], "--truetype", 4) == 0) { fputs("htmldoc: Warning, --truetype option superseded by --embedfonts!\n", stderr); EmbedFonts = 1; } else if (compare_strings(argv[i], "--verbose", 6) == 0 || strcmp(argv[i], "-v") == 0) { Verbosity ++; } else if (compare_strings(argv[i], "--version", 6) == 0) { puts(SVERSION); return (0); } else if (compare_strings(argv[i], "--webpage", 3) == 0) { TocLevels = 0; TitlePage = 0; OutputType = OUTPUT_WEBPAGES; PDFPageMode = PDF_DOCUMENT; PDFFirstPage = PDF_PAGE_1; } else if (compare_strings(argv[i], "--xrxcomments", 3) == 0) XRXComments = 1; else if (strcmp(argv[i], "-") == 0) { /* * Read from stdin... */ num_files ++; _htmlPPI = 72.0f * _htmlBrowserWidth / (PageWidth - PageLeft - PageRight); file = htmlAddTree(NULL, MARKUP_FILE, NULL); htmlSetVariable(file, (uchar *)"_HD_FILENAME", (uchar *)""); htmlSetVariable(file, (uchar *)"_HD_BASE", (uchar *)"."); #ifdef WIN32 // Make sure stdin is in binary mode. // (I hate Microsoft... I hate Microsoft... Everybody join in!) setmode(0, O_BINARY); #elif defined(__EMX__) // OS/2 has a setmode for FILE's... fflush(stdin); _fsetmode(stdin, "b"); #endif // WIN32 || __EMX__ _htmlCurrentFile = "(stdin)"; htmlReadFile(file, stdin, "."); if (document == NULL) document = file; else { while (document->next != NULL) document = document->next; document->next = file; file->prev = document; } } else if (argv[i][0] == '-') usage(argv[i]); #ifdef HAVE_LIBFLTK else if (strlen(argv[i]) > 5 && strcmp(argv[i] + strlen(argv[i]) - 5, ".book") == 0) { /* * GUI mode... */ if (BookGUI == NULL) BookGUI = new GUI(argv[i]); else BookGUI->loadBook(argv[i]); } #endif /* HAVE_LIBFLTK */ else { num_files ++; read_file(argv[i], &document, Path); } } if (CGIMode) { char url[1024]; // URL const char *https, // HTTPS env var, if any *path_info, // Path info, if any *query, // Query string, if any *server_name, // Server name *server_port; // Server port https = getenv("HTTPS"); path_info = getenv("PATH_INFO"); query = getenv("QUERY_STRING"); server_name = getenv("SERVER_NAME"); server_port = getenv("SERVER_PORT"); if (server_port && path_info && *path_info) { // Read the referenced file from the local server... if (https && strcmp(https, "off")) httpAssembleURI(HTTP_URI_CODING_ALL, url, sizeof(url), "https", NULL, server_name, atoi(server_port), path_info); else httpAssembleURI(HTTP_URI_CODING_ALL, url, sizeof(url), "http", NULL, server_name, atoi(server_port), path_info); if (query && *query && *query != '-') { // Include query string on end of URL, which is already URI encoded... strlcat(url, "?", sizeof(url)); strlcat(url, query, sizeof(url)); } progress_error(HD_ERROR_NONE, "INFO: HTMLDOC converting \"%s\".", url); num_files ++; read_file(url, &document, Path); } else progress_error(HD_ERROR_FILE_NOT_FOUND, "PATH_INFO is not set in the environment!"); } /* * Display the GUI if necessary... */ #ifdef HAVE_LIBFLTK if (num_files == 0 && BookGUI == NULL) BookGUI = new GUI(); if (BookGUI != NULL) { Fl_File_Icon::load_system_icons(); BookGUI->show(); i = Fl::run(); delete BookGUI; return (i); } #endif /* HAVE_LIBFLTK */ /* * We *must* have a document to process... */ if (num_files == 0 || document == NULL) usage("No HTML files!"); /* * Find the first one in the list... */ while (document && document->prev != NULL) document = document->prev; // Fix links... htmlFixLinks(document, document); load_time = get_seconds(); // Show debug info... htmlDebugStats("Document Tree", document); /* * Build a table of contents for the documents if necessary... */ if (OutputType == OUTPUT_BOOK && TocLevels > 0) toc = toc_build(document); else toc = NULL; htmlDebugStats("Table of Contents Tree", toc); /* * Generate the output file(s). */ (*exportfunc)(document, toc); end_time = get_seconds(); /* * Report running time statistics as needed... */ if ((debug = getenv("HTMLDOC_DEBUG")) != NULL && (strstr(debug, "all") != NULL || strstr(debug, "timing") != NULL)) progress_error(HD_ERROR_NONE, "TIMING: %.3f %.3f %.3f", load_time - start_time, end_time - load_time, end_time - start_time); /* * Cleanup... */ htmlDeleteTree(document); htmlDeleteTree(toc); file_cleanup(); image_flush_cache(); return (Errors); } /* * 'prefs_getrc()' - Get the rc file for preferences... */ static const char * prefs_getrc(void) { #ifdef WIN32 HKEY key; // Registry key DWORD size; // Size of string char home[1024]; // Home (profile) directory #else const char *home; // Home directory #endif // WIN32 static char htmldocrc[1024];// HTMLDOC RC file // Find the home directory... #ifdef WIN32 // Open the registry... if (RegOpenKeyEx(HKEY_CURRENT_USER, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders", 0, KEY_READ, &key)) { // Use the install directory... strlcpy(home, _htmlData, sizeof(home)); } else { // Grab the current user's AppData directory... size = sizeof(home); if (RegQueryValueEx(key, "AppData", NULL, NULL, (unsigned char *)home, &size)) strlcpy(home, _htmlData, sizeof(home)); RegCloseKey(key); } #else if ((home = getenv("HOME")) == NULL) home = _htmlData; #endif // WIN32 // Format the rc filename and return... snprintf(htmldocrc, sizeof(htmldocrc), "%s/.htmldocrc", home); return (htmldocrc); } /* * 'prefs_load()' - Load HTMLDOC preferences... */ void prefs_load(void) { int pos; // Header/footer position char line[2048]; // Line from RC file FILE *fp; // File pointer // // Read the preferences file... // if ((fp = fopen(prefs_getrc(), "r")) != NULL) { while (fgets(line, sizeof(line), fp) != NULL) { if (line[strlen(line) - 1] == '\n') line[strlen(line) - 1] = '\0'; if (strncasecmp(line, "TEXTCOLOR=", 10) == 0) htmlSetTextColor((uchar *)(line + 10)); else if (strncasecmp(line, "BODYCOLOR=", 10) == 0) strlcpy(BodyColor, line + 10, sizeof(BodyColor)); else if (strncasecmp(line, "BODYIMAGE=", 10) == 0) strlcpy(BodyImage, line + 10, sizeof(BodyImage)); else if (strncasecmp(line, "LINKCOLOR=", 10) == 0) strlcpy(LinkColor, line + 10, sizeof(LinkColor)); else if (strncasecmp(line, "LINKSTYLE=", 10) == 0) LinkStyle = atoi(line + 10); else if (strncasecmp(line, "BROWSERWIDTH=", 13) == 0) _htmlBrowserWidth = atof(line + 13); else if (strncasecmp(line, "PAGEWIDTH=", 10) == 0) PageWidth = atoi(line + 10); else if (strncasecmp(line, "PAGELENGTH=", 11) == 0) PageLength = atoi(line + 11); else if (strncasecmp(line, "PAGELEFT=", 9) == 0) PageLeft = atoi(line + 9); else if (strncasecmp(line, "PAGERIGHT=", 10) == 0) PageRight = atoi(line + 10); else if (strncasecmp(line, "PAGETOP=", 8) == 0) PageTop = atoi(line + 8); else if (strncasecmp(line, "PAGEBOTTOM=", 11) == 0) PageBottom = atoi(line + 11); else if (strncasecmp(line, "PAGEDUPLEX=", 11) == 0) PageDuplex = atoi(line + 11); else if (strncasecmp(line, "LANDSCAPE=", 10) == 0) Landscape = atoi(line + 10); else if (strncasecmp(line, "COMPRESSION=", 12) == 0) Compression = atoi(line + 12); else if (strncasecmp(line, "OUTPUTCOLOR=", 12) == 0) { OutputColor = atoi(line + 12); _htmlGrayscale = !OutputColor; } else if (strncasecmp(line, "TOCNUMBERS=", 11) == 0) TocNumbers = atoi(line + 11); else if (strncasecmp(line, "TOCLEVELS=", 10) == 0) TocLevels = atoi(line + 10); else if (strncasecmp(line, "JPEG=", 5) == 0) OutputJPEG = atoi(line + 1); else if (strncasecmp(line, "PAGEHEADER=", 11) == 0) get_format(line + 11, Header); else if (strncasecmp(line, "PAGEFOOTER=", 11) == 0) get_format(line + 11, Footer); else if (strncasecmp(line, "NUMBERUP=", 9) == 0) NumberUp = atoi(line + 9); else if (strncasecmp(line, "TOCHEADER=", 10) == 0) get_format(line + 10, TocHeader); else if (strncasecmp(line, "TOCFOOTER=", 10) == 0) get_format(line + 10, TocFooter); else if (strncasecmp(line, "TOCTITLE=", 9) == 0) strlcpy(TocTitle, line + 9, sizeof(TocTitle)); else if (strncasecmp(line, "BODYFONT=", 9) == 0) _htmlBodyFont = (typeface_t)atoi(line + 9); else if (strncasecmp(line, "HEADINGFONT=", 12) == 0) _htmlHeadingFont = (typeface_t)atoi(line + 12); else if (strncasecmp(line, "FONTSIZE=", 9) == 0) htmlSetBaseSize(atof(line + 9), _htmlSpacings[SIZE_P] / _htmlSizes[SIZE_P]); else if (strncasecmp(line, "FONTSPACING=", 12) == 0) htmlSetBaseSize(_htmlSizes[SIZE_P], atof(line + 12)); else if (strncasecmp(line, "HEADFOOTTYPE=", 13) == 0) HeadFootType = (typeface_t)atoi(line + 13); else if (strncasecmp(line, "HEADFOOTSTYLE=", 14) == 0) HeadFootStyle = (style_t)atoi(line + 14); else if (strncasecmp(line, "HEADFOOTSIZE=", 13) == 0) HeadFootSize = atof(line + 13); else if (strncasecmp(line, "PDFVERSION=", 11) == 0) { if (strchr(line + 11, '.') != NULL) PDFVersion = (int)(atof(line + 11) * 10.0 + 0.5); else PDFVersion = atoi(line + 11); } else if (strncasecmp(line, "PSLEVEL=", 8) == 0) PSLevel = atoi(line + 8); else if (strncasecmp(line, "PSCOMMANDS=", 11) == 0) PSCommands = atoi(line + 11); else if (strncasecmp(line, "XRXCOMMENTS=", 12) == 0) XRXComments = atoi(line + 12); else if (strncasecmp(line, "CHARSET=", 8) == 0) htmlSetCharSet(line + 8); else if (strncasecmp(line, "PAGEMODE=", 9) == 0) PDFPageMode = atoi(line + 9); else if (strncasecmp(line, "PAGELAYOUT=", 11) == 0) PDFPageLayout = atoi(line + 11); else if (strncasecmp(line, "FIRSTPAGE=", 10) == 0) PDFFirstPage = atoi(line + 10); else if (strncasecmp(line, "PAGEEFFECT=", 11) == 0) PDFEffect = atoi(line + 11); else if (strncasecmp(line, "PAGEDURATION=", 14) == 0) PDFPageDuration = atof(line + 14); else if (strncasecmp(line, "EFFECTDURATION=", 16) == 0) PDFEffectDuration = atof(line + 16); else if (strncasecmp(line, "ENCRYPTION=", 11) == 0) Encryption = atoi(line + 11); else if (strncasecmp(line, "PERMISSIONS=", 12) == 0) Permissions = atoi(line + 12); else if (strncasecmp(line, "OWNERPASSWORD=", 14) == 0) strlcpy(OwnerPassword, line + 14, sizeof(OwnerPassword)); else if (strncasecmp(line, "USERPASSWORD=", 13) == 0) strlcpy(UserPassword, line + 13, sizeof(UserPassword)); else if (strncasecmp(line, "LINKS=", 6) == 0) Links = atoi(line + 6); else if (strncasecmp(line, "TRUETYPE=", 9) == 0) EmbedFonts = atoi(line + 9); else if (strncasecmp(line, "EMBEDFONTS=", 11) == 0) EmbedFonts = atoi(line + 11); else if (strncasecmp(line, "PATH=", 5) == 0) strlcpy(Path, line + 5, sizeof(Path)); else if (strncasecmp(line, "PROXY=", 6) == 0) strlcpy(Proxy, line + 6, sizeof(Proxy)); else if (strncasecmp(line, "STRICTHTML=", 11) == 0) StrictHTML = atoi(line + 11); # ifdef HAVE_LIBFLTK else if (strncasecmp(line, "EDITOR=", 7) == 0) strlcpy(HTMLEditor, line + 7, sizeof(HTMLEditor)); else if (strncasecmp(line, "TOOLTIPS=", 9) == 0) Tooltips = atoi(line + 9); # endif // HAVE_LIBFLTK } fclose(fp); } // Check header/footer formats... for (pos = 0; pos < 3; pos ++) if (Header[pos]) break; if (pos == 3) get_format(".t.", Header); for (pos = 0; pos < 3; pos ++) if (Footer[pos]) break; if (pos == 3) get_format("h.1", Footer); for (pos = 0; pos < 3; pos ++) if (TocHeader[pos]) break; if (pos == 3) get_format(".t.", TocHeader); for (pos = 0; pos < 3; pos ++) if (TocFooter[pos]) break; if (pos == 3) get_format("..i", TocFooter); } /* * 'prefs_save()' - Save HTMLDOC preferences... */ void prefs_save(void) { FILE *fp; // File pointer if ((fp = fopen(prefs_getrc(), "w")) != NULL) { fputs("#HTMLDOCRC " SVERSION "\n", fp); fprintf(fp, "TEXTCOLOR=%s\n", _htmlTextColor); fprintf(fp, "BODYCOLOR=%s\n", BodyColor); fprintf(fp, "BODYIMAGE=%s\n", BodyImage); fprintf(fp, "LINKCOLOR=%s\n", LinkColor); fprintf(fp, "LINKSTYLE=%d\n", LinkStyle); fprintf(fp, "BROWSERWIDTH=%.0f\n", _htmlBrowserWidth); fprintf(fp, "PAGEWIDTH=%d\n", PageWidth); fprintf(fp, "PAGELENGTH=%d\n", PageLength); fprintf(fp, "PAGELEFT=%d\n", PageLeft); fprintf(fp, "PAGERIGHT=%d\n", PageRight); fprintf(fp, "PAGETOP=%d\n", PageTop); fprintf(fp, "PAGEBOTTOM=%d\n", PageBottom); fprintf(fp, "PAGEDUPLEX=%d\n", PageDuplex); fprintf(fp, "LANDSCAPE=%d\n", Landscape); fprintf(fp, "COMPRESSION=%d\n", Compression); fprintf(fp, "OUTPUTCOLOR=%d\n", OutputColor); fprintf(fp, "TOCNUMBERS=%d\n", TocNumbers); fprintf(fp, "TOCLEVELS=%d\n", TocLevels); fprintf(fp, "JPEG=%d\n", OutputJPEG); fprintf(fp, "PAGEHEADER=%s\n", get_fmt(Header)); fprintf(fp, "PAGEFOOTER=%s\n", get_fmt(Footer)); fprintf(fp, "NUMBERUP=%d\n", NumberUp); fprintf(fp, "TOCHEADER=%s\n", get_fmt(TocHeader)); fprintf(fp, "TOCFOOTER=%s\n", get_fmt(TocFooter)); fprintf(fp, "TOCTITLE=%s\n", TocTitle); fprintf(fp, "BODYFONT=%d\n", _htmlBodyFont); fprintf(fp, "HEADINGFONT=%d\n", _htmlHeadingFont); fprintf(fp, "FONTSIZE=%.2f\n", _htmlSizes[SIZE_P]); fprintf(fp, "FONTSPACING=%.2f\n", _htmlSpacings[SIZE_P] / _htmlSizes[SIZE_P]); fprintf(fp, "HEADFOOTTYPE=%d\n", HeadFootType); fprintf(fp, "HEADFOOTSTYLE=%d\n", HeadFootStyle); fprintf(fp, "HEADFOOTSIZE=%.2f\n", HeadFootSize); fprintf(fp, "PDFVERSION=%d\n", PDFVersion); fprintf(fp, "PSLEVEL=%d\n", PSLevel); fprintf(fp, "PSCOMMANDS=%d\n", PSCommands); fprintf(fp, "XRXCOMMENTS=%d\n", XRXComments); fprintf(fp, "CHARSET=%s\n", _htmlCharSet); fprintf(fp, "PAGEMODE=%d\n", PDFPageMode); fprintf(fp, "PAGELAYOUT=%d\n", PDFPageLayout); fprintf(fp, "FIRSTPAGE=%d\n", PDFFirstPage); fprintf(fp, "PAGEEFFECT=%d\n", PDFEffect); fprintf(fp, "PAGEDURATION=%.0f\n", PDFPageDuration); fprintf(fp, "EFFECTDURATION=%.1f\n", PDFEffectDuration); fprintf(fp, "ENCRYPTION=%d\n", Encryption); fprintf(fp, "PERMISSIONS=%d\n", Permissions); fprintf(fp, "OWNERPASSWORD=%s\n", OwnerPassword); fprintf(fp, "USERPASSWORD=%s\n", UserPassword); fprintf(fp, "LINKS=%d\n", Links); fprintf(fp, "EMBEDFONTS=%d\n", EmbedFonts); fprintf(fp, "PATH=%s\n", Path); fprintf(fp, "PROXY=%s\n", Proxy); fprintf(fp, "STRICTHTML=%d\n", StrictHTML); #ifdef HAVE_LIBFLTK fprintf(fp, "EDITOR=%s\n", HTMLEditor); fprintf(fp, "TOOLTIPS=%d\n", Tooltips); #endif // HAVE_LIBFLTK fclose(fp); } } /* * 'prefs_set_paths()' - Set HTMLDOC data/help paths... */ void prefs_set_paths(void) { // // Get the installed directories... // #ifdef WIN32 //// Do registry magic... HKEY key; // Registry key DWORD size; // Size of string static char data[1024]; // Data directory static char doc[1024]; // Documentation directory static char path[4096]; // PATH environment variable // Open the registry... if (!RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\HTMLDOC", 0, KEY_READ, &key)) { // Grab the installed directories... size = sizeof(data); if (!RegQueryValueEx(key, "data", NULL, NULL, (unsigned char *)data, &size)) _htmlData = data; else progress_error(HD_ERROR_FILE_NOT_FOUND, "Unable to read \"data\" value from registry!"); # ifdef HAVE_LIBFLTK size = sizeof(doc); if (!RegQueryValueEx(key, "doc", NULL, NULL, (unsigned char *)doc, &size)) GUI::help_dir = doc; # endif // HAVE_LIBFLTK RegCloseKey(key); } else progress_error(HD_ERROR_FILE_NOT_FOUND, "Unable to read HTMLDOC installation from registry!"); // See if the HTMLDOC program folder is in the system execution path... if (!RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Environment", 0, KEY_READ | KEY_WRITE, &key)) { // Grab the current path... size = sizeof(path); if (!RegQueryValueEx(key, "Path", NULL, NULL, (unsigned char *)path, &size)) if (strstr(path, _htmlData) == NULL) { // The data directory is not in the path, so add it... strlcat(path, ";", sizeof(path)); strlcat(path, _htmlData, sizeof(path)); RegSetValueEx(key, "Path", 0, REG_EXPAND_SZ, (unsigned char *)path, strlen(path) + 1); } } #elif defined(__EMX__) && defined(HAVE_LIBFLTK) // If being installed within XFree86 OS/2 Environment // we can use those values which are overwritten by // the according environment variables. _htmlData = strdup(__XOS2RedirRoot("/XFree86/lib/X11/htmldoc")); GUI::help_dir = strdup(__XOS2RedirRoot("/XFree86/lib/X11/htmldoc/doc")); #elif defined(__APPLE__) && defined(HAVE_LIBFLTK) char path[PROC_PIDPATHINFO_MAXSIZE + 1]; // Process path int pathlen; // Length of path string static char resources[1024]; // Resources directory if ((pathlen = proc_pidpath(getpid(), path, sizeof(path) - 1)) >= 0) { char *ptr; // Pointer into path path[pathlen] = '\0'; // printf("proc_pidpath returned \"%s\"\n", path); if ((ptr = strstr(path, "/Contents/MacOS")) != NULL) { *ptr = '\0'; // printf("Bundle path is \"%s\"\n", path); snprintf(resources, sizeof(resources), "%s/Contents/Resources", path); _htmlData = resources; GUI::help_dir = resources; } } // else // perror("proc_pidpath failed"); #elif defined(__linux) const char *snap; // SNAP environment variable // Support HTMLDOC as a snap package... if ((snap = getenv("SNAP")) != NULL) { static char datadir[1024]; // Data directory snprintf(datadir, sizeof(datadir), "%s/share/htmldoc", snap); _htmlData = datadir; # ifdef HAVE_LIBFLTK static char docdir[1024]; // Documentation directory snprintf(docdir, sizeof(docdir), "%s/share/doc/htmldoc", snap); GUI::help_dir = docdir; # endif // HAVE_LIBFLTK } #endif // WIN32 // // See if the installed directories have been overridden by // environment variables... // if (getenv("HTMLDOC_DATA") != NULL) _htmlData = getenv("HTMLDOC_DATA"); #ifdef HAVE_LIBFLTK if (getenv("HTMLDOC_HELP") != NULL) GUI::help_dir = getenv("HTMLDOC_HELP"); #endif // HAVE_LIBFLTK } /* * 'compare_strings()' - Compare two command-line strings. */ static int /* O - -1 or 1 = no match, 0 = match */ compare_strings(const char *s, /* I - Command-line string */ const char *t, /* I - Option string */ int tmin) /* I - Minimum number of unique chars in option */ { size_t slen; /* Length of command-line string */ slen = strlen(s); if (slen < (size_t)tmin) return (-1); else return (strncmp(s, t, slen)); } /* * 'get_seconds()' - Get the current fractional time in seconds. */ static double /* O - Number of seconds */ get_seconds(void) { #ifdef WIN32 return (GetTickCount() * 0.001); #else struct timeval curtime; /* Current time */ gettimeofday(&curtime, NULL); return (curtime.tv_sec + curtime.tv_usec * 0.000001); #endif /* WIN32 */ } // // 'load_book()' - Load a book file... // static int // O - 1 = success, 0 = failure load_book(const char *filename, // I - Book file tree_t **document, // IO - Document tree exportfunc_t *exportfunc, // O - Export function int set_nolocal) // I - Set file_nolocal() after lookup? { FILE *fp; // File to read from char line[10240]; // Line from file const char *dir; // Directory const char *local; // Local filename char path[2048]; // Current path // See if the filename contains a path... dir = file_directory(filename); if (dir != NULL) snprintf(path, sizeof(path), "%s;%s", dir, Path); else strlcpy(path, Path, sizeof(path)); // Open the file... local = file_find(Path, filename); if (set_nolocal) file_nolocal(); if (!local) return (0); if ((fp = fopen(local, "rb")) == NULL) { progress_error(HD_ERROR_READ_ERROR, "Unable to open book file \"%s\": %s", local, strerror(errno)); return (0); } // Get the header... file_gets(line, sizeof(line), fp); if (strncmp(line, "#HTMLDOC", 8) != 0) { fclose(fp); progress_error(HD_ERROR_BAD_FORMAT, "Bad or missing #HTMLDOC header in \"%s\".", filename); return (0); } // Read the second line from the book file; for older book files, this will // be the file count; for new files this will be the options... do { file_gets(line, sizeof(line), fp); if (line[0] == '-') { parse_options(line, exportfunc); if (dir != NULL) snprintf(path, sizeof(path), "%s;%s", dir, Path); else strlcpy(path, Path, sizeof(path)); } } while (!line[0]); // Skip blank lines // Get input files/options... while (file_gets(line, sizeof(line), fp) != NULL) { if (!line[0]) continue; // Skip blank lines else if (line[0] == '-') { parse_options(line, exportfunc); if (dir != NULL) snprintf(path, sizeof(path), "%s;%s", dir, Path); else strlcpy(path, Path, sizeof(path)); } else if (line[0] == '\\') read_file(line + 1, document, path); else read_file(line, document, path); } // Close the book file and return... fclose(fp); return (1); } // // 'parse_options()' - Parse options from a book file... // static void parse_options(const char *line, // I - Options from book file exportfunc_t *exportfunc) // O - Export function { int i; // Looping var const char *lineptr; // Pointer into line char temp[1024], // Option name temp2[1024], // Option value *tempptr; // Pointer into option double fontsize, // Size of body text fontspacing; // Spacing between lines // Parse the input line... for (lineptr = line; *lineptr != '\0';) { while (*lineptr == ' ') lineptr ++; for (tempptr = temp; *lineptr != '\0' && *lineptr != ' '; lineptr ++) if (tempptr < (temp + sizeof(temp) - 1)) *tempptr++ = *lineptr; *tempptr = '\0'; while (*lineptr == ' ') lineptr ++; if (strcmp(temp, "--duplex") == 0) { PageDuplex = 1; continue; } else if (strcmp(temp, "--landscape") == 0) { Landscape = 1; continue; } else if (strcmp(temp, "--portrait") == 0) { Landscape = 0; continue; } else if (strncmp(temp, "--jpeg", 6) == 0) { if (strlen(temp) > 7) OutputJPEG = atoi(temp + 7); else OutputJPEG = 90; continue; } else if (strcmp(temp, "--grayscale") == 0) { OutputColor = 0; continue; } else if (strcmp(temp, "--color") == 0) { OutputColor = 1; continue; } else if (strcmp(temp, "--links") == 0) { Links = 1; continue; } else if (strcmp(temp, "--no-links") == 0) { Links = 0; continue; } else if (strcmp(temp, "--embedfonts") == 0 || strcmp(temp, "--truetype") == 0) { EmbedFonts = 1; continue; } else if (strcmp(temp, "--no-embedfonts") == 0 || strcmp(temp, "--no-truetype") == 0) { EmbedFonts = 0; continue; } else if (strcmp(temp, "--pscommands") == 0) { PSCommands = 1; continue; } else if (strcmp(temp, "--no-pscommands") == 0) { PSCommands = 0; continue; } else if (strcmp(temp, "--xrxcomments") == 0) { XRXComments = 1; continue; } else if (strcmp(temp, "--no-xrxcomments") == 0) { XRXComments = 0; continue; } else if (strncmp(temp, "--compression", 13) == 0) { if (strlen(temp) > 14) Compression = atoi(temp + 14); else Compression = 1; continue; } else if (strcmp(temp, "--no-compression") == 0) { Compression = 0; continue; } else if (strcmp(temp, "--no-jpeg") == 0) { OutputJPEG = 0; continue; } else if (strcmp(temp, "--numbered") == 0) { TocNumbers = 1; continue; } else if (strcmp(temp, "--no-numbered") == 0) { TocNumbers = 0; continue; } else if (strcmp(temp, "--no-toc") == 0) { TocLevels = 0; continue; } else if (strcmp(temp, "--title") == 0) { TitlePage = 1; continue; } else if (strcmp(temp, "--no-title") == 0) { TitlePage = 0; continue; } else if (strcmp(temp, "--book") == 0) { OutputType = OUTPUT_BOOK; continue; } else if (strcmp(temp, "--continuous") == 0) { OutputType = OUTPUT_CONTINUOUS; continue; } else if (strcmp(temp, "--webpage") == 0) { OutputType = OUTPUT_WEBPAGES; continue; } else if (strcmp(temp, "--encryption") == 0) { Encryption = 1; continue; } else if (strcmp(temp, "--no-encryption") == 0) { Encryption = 0; continue; } else if (strcmp(temp, "--strict") == 0) StrictHTML = 1; else if (strcmp(temp, "--no-strict") == 0) StrictHTML = 0; else if (strcmp(temp, "--overflow") == 0) OverflowErrors = 1; else if (strcmp(temp, "--no-overflow") == 0) OverflowErrors = 0; if (*lineptr == '\"') { lineptr ++; for (tempptr = temp2; *lineptr != '\0' && *lineptr != '\"'; lineptr ++) if (tempptr < (temp2 + sizeof(temp2) - 1)) *tempptr++ = *lineptr; if (*lineptr == '\"') lineptr ++; } else { for (tempptr = temp2; *lineptr != '\0' && *lineptr != ' '; lineptr ++) if (tempptr < (temp2 + sizeof(temp2) - 1)) *tempptr++ = *lineptr; } *tempptr = '\0'; if (strcmp(temp, "-t") == 0 && !CGIMode) { if (strcmp(temp2, "epub") == 0) *exportfunc = (exportfunc_t)epub_export; else if (strcmp(temp2, "html") == 0) *exportfunc = (exportfunc_t)html_export; else if (strcmp(temp2, "htmlsep") == 0) *exportfunc = (exportfunc_t)htmlsep_export; else if (strcmp(temp2, "pdf11") == 0) { *exportfunc = (exportfunc_t)pspdf_export; PSLevel = 0; PDFVersion = 11; } else if (strcmp(temp2, "pdf12") == 0) { *exportfunc = (exportfunc_t)pspdf_export; PSLevel = 0; PDFVersion = 12; } else if (strcmp(temp2, "pdf13") == 0) { *exportfunc = (exportfunc_t)pspdf_export; PSLevel = 0; PDFVersion = 13; } else if (strcmp(temp2, "pdf") == 0 || strcmp(temp2, "pdf14") == 0) { *exportfunc = (exportfunc_t)pspdf_export; PSLevel = 0; PDFVersion = 14; } else if (strcmp(temp2, "ps1") == 0) { *exportfunc = (exportfunc_t)pspdf_export; PSLevel = 1; } else if (strcmp(temp2, "ps") == 0 || strcmp(temp2, "ps2") == 0) { *exportfunc = (exportfunc_t)pspdf_export; PSLevel = 2; } else if (strcmp(temp2, "ps3") == 0) { *exportfunc = (exportfunc_t)pspdf_export; PSLevel = 3; } } else if (strcmp(temp, "--logo") == 0 || strcmp(temp, "--logoimage") == 0) strlcpy(LogoImage, temp2, sizeof(LogoImage)); else if (strcmp(temp, "--titlefile") == 0 || strcmp(temp, "--titleimage") == 0) { TitlePage = 1; strlcpy(TitleImage, temp2, sizeof(TitleImage)); } else if (strcmp(temp, "-f") == 0 && !CGIMode) { OutputFiles = 0; strlcpy(OutputPath, temp2, sizeof(OutputPath)); } else if (strcmp(temp, "-d") == 0 && !CGIMode) { OutputFiles = 1; strlcpy(OutputPath, temp2, sizeof(OutputPath)); } else if (strcmp(temp, "--browserwidth") == 0) _htmlBrowserWidth = atof(temp2); else if (strcmp(temp, "--nup") == 0) NumberUp = atoi(temp2); else if (strcmp(temp, "--size") == 0) set_page_size(temp2); else if (strcmp(temp, "--left") == 0) PageLeft = get_measurement(temp2); else if (strcmp(temp, "--right") == 0) PageRight = get_measurement(temp2); else if (strcmp(temp, "--top") == 0) PageTop = get_measurement(temp2); else if (strcmp(temp, "--bottom") == 0) PageBottom = get_measurement(temp2); else if (strcmp(temp, "--header") == 0) get_format(temp2, Header); else if (strcmp(temp, "--header1") == 0) get_format(temp2, Header1); else if (strcmp(temp, "--footer") == 0) get_format(temp2, Footer); else if (strcmp(temp, "--bodycolor") == 0) strlcpy(BodyColor, temp2, sizeof(BodyColor)); else if (strcmp(temp, "--bodyimage") == 0) strlcpy(BodyImage, temp2, sizeof(BodyImage)); else if (strcmp(temp, "--textcolor") == 0) htmlSetTextColor((uchar *)temp2); else if (strcmp(temp, "--linkcolor") == 0) strlcpy(LinkColor, temp2, sizeof(LinkColor)); else if (strcmp(temp, "--linkstyle") == 0) { if (strcmp(temp2, "plain") == 0) LinkStyle = 0; else LinkStyle = 1; } else if (strcmp(temp, "--toclevels") == 0) TocLevels = atoi(temp2); else if (strcmp(temp, "--tocheader") == 0) get_format(temp2, TocHeader); else if (strcmp(temp, "--tocfooter") == 0) get_format(temp2, TocFooter); else if (strcmp(temp, "--toctitle") == 0) strlcpy(TocTitle, temp2, sizeof(TocTitle)); else if (strcmp(temp, "--fontsize") == 0) { fontsize = atof(temp2); fontspacing = _htmlSpacings[SIZE_P] / _htmlSizes[SIZE_P]; if (fontsize < 4.0f) fontsize = 4.0f; else if (fontsize > 24.0f) fontsize = 24.0f; htmlSetBaseSize(fontsize, fontspacing); } else if (strcmp(temp, "--fontspacing") == 0) { fontsize = _htmlSizes[SIZE_P]; fontspacing = atof(temp2); if (fontspacing < 1.0f) fontspacing = 1.0f; else if (fontspacing > 3.0f) fontspacing = 3.0f; htmlSetBaseSize(fontsize, fontspacing); } else if (!strcmp(temp, "--headingfont")) { if (!strcasecmp(temp2, "courier")) _htmlHeadingFont = TYPE_COURIER; else if (!strcasecmp(temp2, "times")) _htmlHeadingFont = TYPE_TIMES; else if (!strcasecmp(temp2, "helvetica") || !strcasecmp(temp2, "arial")) _htmlHeadingFont = TYPE_HELVETICA; else if (!strcasecmp(temp2, "monospace")) _htmlHeadingFont = TYPE_MONOSPACE; else if (!strcasecmp(temp2, "serif")) _htmlHeadingFont = TYPE_SERIF; else if (!strcasecmp(temp2, "sans")) _htmlHeadingFont = TYPE_SANS_SERIF; } else if (!strcmp(temp, "--bodyfont")) { if (!strcasecmp(temp2, "monospace")) _htmlBodyFont = TYPE_MONOSPACE; else if (!strcasecmp(temp2, "serif")) _htmlBodyFont = TYPE_SERIF; else if (!strcasecmp(temp2, "sans")) _htmlBodyFont = TYPE_SANS_SERIF; else if (!strcasecmp(temp2, "courier")) _htmlBodyFont = TYPE_COURIER; else if (!strcasecmp(temp2, "times")) _htmlBodyFont = TYPE_TIMES; else if (!strcasecmp(temp2, "helvetica") || !strcasecmp(temp2, "arial")) _htmlBodyFont = TYPE_HELVETICA; } else if (strcmp(temp, "--headfootsize") == 0) HeadFootSize = atof(temp2); else if (!strcmp(temp, "--headfootfont")) { if (!strcasecmp(temp2, "courier")) { HeadFootType = TYPE_COURIER; HeadFootStyle = STYLE_NORMAL; } else if (!strcasecmp(temp2, "courier-bold")) { HeadFootType = TYPE_COURIER; HeadFootStyle = STYLE_BOLD; } else if (!strcasecmp(temp2, "courier-oblique")) { HeadFootType = TYPE_COURIER; HeadFootStyle = STYLE_ITALIC; } else if (!strcasecmp(temp2, "courier-boldoblique")) { HeadFootType = TYPE_COURIER; HeadFootStyle = STYLE_BOLD_ITALIC; } else if (!strcasecmp(temp2, "times") || !strcasecmp(temp2, "times-roman")) { HeadFootType = TYPE_TIMES; HeadFootStyle = STYLE_NORMAL; } else if (!strcasecmp(temp2, "times-bold")) { HeadFootType = TYPE_TIMES; HeadFootStyle = STYLE_BOLD; } else if (!strcasecmp(temp2, "times-italic")) { HeadFootType = TYPE_TIMES; HeadFootStyle = STYLE_ITALIC; } else if (!strcasecmp(temp2, "times-bolditalic")) { HeadFootType = TYPE_TIMES; HeadFootStyle = STYLE_BOLD_ITALIC; } else if (!strcasecmp(temp2, "helvetica")) { HeadFootType = TYPE_HELVETICA; HeadFootStyle = STYLE_NORMAL; } else if (!strcasecmp(temp2, "helvetica-bold")) { HeadFootType = TYPE_HELVETICA; HeadFootStyle = STYLE_BOLD; } else if (!strcasecmp(temp2, "helvetica-oblique")) { HeadFootType = TYPE_HELVETICA; HeadFootStyle = STYLE_ITALIC; } else if (!strcasecmp(temp2, "helvetica-boldoblique")) { HeadFootType = TYPE_HELVETICA; HeadFootStyle = STYLE_BOLD_ITALIC; } else if (!strcasecmp(temp2, "monospace")) { HeadFootType = TYPE_MONOSPACE; HeadFootStyle = STYLE_NORMAL; } else if (!strcasecmp(temp2, "monospace-bold")) { HeadFootType = TYPE_MONOSPACE; HeadFootStyle = STYLE_BOLD; } else if (!strcasecmp(temp2, "monospace-oblique")) { HeadFootType = TYPE_MONOSPACE; HeadFootStyle = STYLE_ITALIC; } else if (!strcasecmp(temp2, "monospace-boldoblique")) { HeadFootType = TYPE_MONOSPACE; HeadFootStyle = STYLE_BOLD_ITALIC; } else if (!strcasecmp(temp2, "serif") || !strcasecmp(temp2, "serif-roman")) { HeadFootType = TYPE_SERIF; HeadFootStyle = STYLE_NORMAL; } else if (!strcasecmp(temp2, "serif-bold")) { HeadFootType = TYPE_SERIF; HeadFootStyle = STYLE_BOLD; } else if (!strcasecmp(temp2, "serif-italic")) { HeadFootType = TYPE_SERIF; HeadFootStyle = STYLE_ITALIC; } else if (!strcasecmp(temp2, "serif-bolditalic")) { HeadFootType = TYPE_SERIF; HeadFootStyle = STYLE_BOLD_ITALIC; } else if (!strcasecmp(temp2, "sans")) { HeadFootType = TYPE_SANS_SERIF; HeadFootStyle = STYLE_NORMAL; } else if (!strcasecmp(temp2, "sans-bold")) { HeadFootType = TYPE_SANS_SERIF; HeadFootStyle = STYLE_BOLD; } else if (!strcasecmp(temp2, "sans-oblique")) { HeadFootType = TYPE_SANS_SERIF; HeadFootStyle = STYLE_ITALIC; } else if (!strcasecmp(temp2, "sans-boldoblique")) { HeadFootType = TYPE_SANS_SERIF; HeadFootStyle = STYLE_BOLD_ITALIC; } } else if (strcmp(temp, "--charset") == 0) htmlSetCharSet(temp2); else if (strcmp(temp, "--pagemode") == 0) { for (i = 0; i < (int)(sizeof(PDFModes) / sizeof(PDFModes[0])); i ++) if (strcasecmp(temp2, PDFModes[i]) == 0) { PDFPageMode = i; break; } } else if (strcmp(temp, "--pagelayout") == 0) { for (i = 0; i < (int)(sizeof(PDFLayouts) / sizeof(PDFLayouts[0])); i ++) if (strcasecmp(temp2, PDFLayouts[i]) == 0) { PDFPageLayout = i; break; } } else if (strcmp(temp, "--firstpage") == 0) { for (i = 0; i < (int)(sizeof(PDFPages) / sizeof(PDFPages[0])); i ++) if (strcasecmp(temp2, PDFPages[i]) == 0) { PDFFirstPage = i; break; } } else if (strcmp(temp, "--pageeffect") == 0) { for (i = 0; i < (int)(sizeof(PDFEffects) / sizeof(PDFEffects[0])); i ++) if (strcasecmp(temp2, PDFEffects[i]) == 0) { PDFEffect = i; break; } } else if (strcmp(temp, "--pageduration") == 0) PDFPageDuration = atof(temp2); else if (strcmp(temp, "--effectduration") == 0) PDFEffectDuration = atof(temp2); else if (strcmp(temp, "--permissions") == 0) set_permissions(temp2); else if (strcmp(temp, "--user-password") == 0) strlcpy(UserPassword, temp2, sizeof(UserPassword)); else if (strcmp(temp, "--owner-password") == 0) strlcpy(OwnerPassword, temp2, sizeof(OwnerPassword)); else if (strcmp(temp, "--path") == 0) strlcpy(Path, temp2, sizeof(Path) - 1); else if (strcmp(temp, "--proxy") == 0) { strlcpy(Proxy, temp2, sizeof(Proxy)); file_proxy(Proxy); } else if (strcmp(temp, "--cookies") == 0) file_cookies(temp2); } } // // 'read_file()' - Read a file into the current document. // static int // O - 1 on success, 0 on failure read_file(const char *filename, // I - File/URL to read tree_t **document, // IO - Current document const char *path) // I - Search path { FILE *docfile; // Document file tree_t *file; // HTML document file const char *realname, // Real name of file *ext; // Extension of filename char base[1024]; // Base directory name of file DEBUG_printf(("read_file(filename=\"%s\", document=%p, path=\"%s\")\n", filename, (void *)document, path)); if ((realname = file_find(path, filename)) != NULL) { if ((docfile = fopen(realname, "rb")) != NULL) { // Prepare to read the file... if (Verbosity > 0) progress_error(HD_ERROR_NONE, "INFO: Reading %s...", filename); _htmlPPI = 72.0f * _htmlBrowserWidth / (PageWidth - PageLeft - PageRight); strlcpy(base, file_directory(filename), sizeof(base)); ext = file_extension(filename); file = htmlAddTree(NULL, MARKUP_FILE, NULL); htmlSetVariable(file, (uchar *)"_HD_URL", (uchar *)filename); htmlSetVariable(file, (uchar *)"_HD_FILENAME", (uchar *)file_basename(filename)); htmlSetVariable(file, (uchar *)"_HD_BASE", (uchar *)base); if (ext && !strcmp(ext, "md")) { // Read markdown from a file... mdReadFile(file, docfile, base); } else { // Read HTML from a file... _htmlCurrentFile = filename; htmlReadFile(file, docfile, base); } fclose(docfile); if (*document == NULL) *document = file; else { while ((*document)->next != NULL) *document = (*document)->next; (*document)->next = file; file->prev = *document; } } else { file = NULL; progress_error(HD_ERROR_FILE_NOT_FOUND, "Unable to open \"%s\" for reading...", filename); } } else { file = NULL; progress_error(HD_ERROR_FILE_NOT_FOUND, "Unable to find \"%s\"...", filename); } return (file != NULL); } // // 'set_permissions()' - Set the PDF permission bits. // void set_permissions(const char *p) // I - Permission string { char *copyp, // Copy of string *start, // Start of current keyword *ptr; // Pointer into string // Range check input... if (!p || !*p) return; // Make a copy of the string and parse it... copyp = strdup(p); if (!copyp) return; for (start = copyp; *start; start = ptr) { for (ptr = start; *ptr; ptr ++) if (*ptr == ',') { *ptr++ = '\0'; break; } if (!strcasecmp(start, "all")) Permissions = -4; else if (!strcasecmp(start, "none")) Permissions = -64; else if (!strcasecmp(start, "print")) Permissions |= PDF_PERM_PRINT; else if (!strcasecmp(start, "no-print")) Permissions &= ~PDF_PERM_PRINT; else if (!strcasecmp(start, "modify")) Permissions |= PDF_PERM_MODIFY; else if (!strcasecmp(start, "no-modify")) Permissions &= ~PDF_PERM_MODIFY; else if (!strcasecmp(start, "copy")) Permissions |= PDF_PERM_COPY; else if (!strcasecmp(start, "no-copy")) Permissions &= ~PDF_PERM_COPY; else if (!strcasecmp(start, "annotate")) Permissions |= PDF_PERM_ANNOTATE; else if (!strcasecmp(start, "no-annotate")) Permissions &= ~PDF_PERM_ANNOTATE; } if (Permissions != -4) Encryption = 1; free(copyp); } #ifndef WIN32 // // 'term_handler()' - Handle CTRL-C or kill signals... // static void term_handler(int signum) // I - Signal number { REF(signum); file_cleanup(); image_flush_cache(); exit(1); } #endif // !WIN32 /* * 'usage()' - Show program version and command-line options. */ static void usage(const char *arg) // I - Bad argument string { if (CGIMode) puts("Content-Type: text/plain\r\n\r"); puts("HTMLDOC Version " SVERSION " Copyright 2011-2019 by Michael R Sweet."); puts("HTMLDOC is provided under the terms of the GNU General Public License and"); puts("comes with absolutely no warranty. This software is based in part on the work"); puts("of the Independent JPEG Group."); puts(""); #ifdef HAVE_SSL puts("This copy of HTMLDOC has been built to support both http: and https: URLs."); #else puts("This copy of HTMLDOC has been built to support http: URLs only."); #endif /* HAVE_SSL */ puts(""); if (CGIMode) { puts("HTMLDOC is running in CGI mode. To disable CGI mode when running"); puts("from a server-side script/page, set the HTMLDOC_NOCGI environment"); puts("variable prior to running HTMLDOC."); puts(""); puts("If you are trying to use CGI mode, make sure that the ServerName"); puts("for the web server is accessible from the local system. If you"); puts("are using Apache 2.0.30 or later, make sure you set 'AcceptPathInfo'"); puts("to 'On' for the HTMLDOC/cgi-bin directory."); } else { if (arg && arg[0] == '-') printf("ERROR: Bad option argument \"%s\"!\n\n", arg); else printf("ERROR: %s\n", arg); puts(""); puts("Usage:"); puts(" htmldoc [options] filename1.html [ ... filenameN.html ]"); #ifdef HAVE_LIBFLTK puts(" htmldoc filename.book"); #endif // HAVE_LIBFLTK puts(""); puts("Options:"); puts(""); puts(" --batch filename.book"); puts(" --bodycolor color"); puts(" --bodyfont {courier,helvetica,monospace,sans,serif,times}"); puts(" --bodyimage filename.{bmp,gif,jpg,png}"); puts(" --book"); puts(" --bottom margin{in,cm,mm}"); puts(" --browserwidth pixels"); puts(" --charset {cp-874...1258,iso-8859-1...-15,koi8-r,utf-8}"); puts(" --color"); puts(" --compression[=level]"); puts(" --continuous"); puts(" --cookies 'name=\"value with space\"; name=value'"); puts(" --datadir directory"); puts(" --duplex"); puts(" --effectduration {0.1..10.0}"); puts(" --embedfonts"); puts(" --encryption"); puts(" --firstpage {p1,toc,c1}"); puts(" --fontsize {4.0..24.0}"); puts(" --fontspacing {1.0..3.0}"); puts(" --footer fff"); puts(" {--format, -t} {epub,html,htmlsep,pdf11,pdf12,pdf13,pdf14,ps1,ps2,ps3}"); puts(" --gray"); puts(" --header fff"); puts(" --header1 fff"); puts(" --headfootfont {courier{-bold,-oblique,-boldoblique},\n" " helvetica{-bold,-oblique,-boldoblique},\n" " monospace{-bold,-oblique,-boldoblique},\n" " sans{-bold,-oblique,-boldoblique},\n" " serif{-bold,-italic,-bolditalic},\n" " times{-roman,-bold,-italic,-bolditalic}}\n"); puts(" --headfootsize {6.0..24.0}"); puts(" --headingfont {courier,helvetica,monospace,sans,serif,times}"); puts(" --help"); #ifdef HAVE_LIBFLTK puts(" --helpdir directory"); #endif // HAVE_LIBFLTK for (int i = 0; i < MAX_HF_IMAGES; i ++) printf(" --hfimage%d filename.{bmp,gif,jpg,png}\n", i); puts(" --jpeg[=quality]"); puts(" --landscape"); puts(" --left margin{in,cm,mm}"); puts(" --linkcolor color"); puts(" --links"); puts(" --linkstyle {plain,underline}"); puts(" --logoimage filename.{bmp,gif,jpg,png}"); puts(" --no-compression"); puts(" --no-duplex"); puts(" --no-embedfonts"); puts(" --no-encryption"); puts(" --no-links"); puts(" --no-localfiles"); puts(" --no-numbered"); puts(" --no-overflow"); puts(" --no-pscommands"); puts(" --no-strict"); puts(" --no-title"); puts(" --no-toc"); puts(" --numbered"); puts(" --nup {1,2,4,6,9,16}"); puts(" {--outdir, -d} dirname"); puts(" {--outfile, -f} filename.{epub,html,pdf,ps}"); puts(" --overflow"); puts(" --owner-password password"); puts(" --pageduration {1.0..60.0}"); puts(" --pageeffect {none,bi,bo,d,gd,gdr,gr,hb,hsi,hso,vb,vsi,vso,wd,wl,wr,wu}"); puts(" --pagelayout {single,one,twoleft,tworight}"); puts(" --pagemode {document,outline,fullscreen}"); puts(" --path \"dir1;dir2;dir3;...;dirN\""); puts(" --permissions {all,annotate,copy,modify,print,no-annotate,no-copy,no-modify,no-print,none}"); puts(" --portrait"); puts(" --proxy http://host:port"); puts(" --pscommands"); puts(" --quiet"); puts(" --referer url"); puts(" --right margin{in,cm,mm}"); puts(" --size {letter,a4,WxH{in,cm,mm},etc}"); puts(" --strict"); puts(" --textcolor color"); puts(" --textfont {courier,times,helvetica}"); puts(" --title"); puts(" --titlefile filename.{htm,html,shtml}"); puts(" --titleimage filename.{bmp,gif,jpg,png}"); puts(" --tocfooter fff"); puts(" --tocheader fff"); puts(" --toclevels levels"); puts(" --toctitle string"); puts(" --top margin{in,cm,mm}"); puts(" --user-password password"); puts(" {--verbose, -v}"); puts(" --version"); puts(" --webpage"); puts(""); puts(" fff = heading format string; each \'f\' can be one of:"); puts(""); puts(" . = blank"); puts(" / = n/N arabic page numbers (1/3, 2/3, 3/3)"); puts(" : = c/C arabic chapter page numbers (1/2, 2/2, 1/4, 2/4, ...)"); puts(" 1 = arabic numbers (1, 2, 3, ...)"); puts(" a = lowercase letters"); puts(" A = uppercase letters"); puts(" c = current chapter heading"); puts(" C = current chapter page number (arabic)"); puts(" d = current date"); puts(" D = current date and time"); puts(" h = current heading"); puts(" i = lowercase roman numerals"); puts(" I = uppercase roman numerals"); puts(" l = logo image"); puts(" t = title text"); puts(" T = current time"); puts(" u = current file/URL"); } exit(1); } htmldoc-1.9.7/htmldoc/htmldoc.h000066400000000000000000000161431354715574200164410ustar00rootroot00000000000000/* * Header file for HTMLDOC, a HTML document processing program. * * Copyright 2011-2017 by Michael R Sweet. * Copyright 1997-2010 by Easy Software Products. All rights reserved. * * This program is free software. Distribution and use rights are outlined in * the file "COPYING". */ /* * Include necessary headers. */ #include #include #include #include "html.h" #include "image.h" #include "debug.h" #include "progress.h" #ifdef HAVE_LIBFLTK # include "gui.h" #endif /* HAVE_LIBFLTK */ #ifdef WIN32 /* Include all 8 million Windows header files... */ # include #endif /* WIN32 */ #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ /* * Macro to get rid of "unreferenced variable xyz" warnings... */ #define REF(x) (void)x; /* * Output type... */ enum { OUTPUT_BOOK, OUTPUT_CONTINUOUS, OUTPUT_WEBPAGES }; /* * PDF constants... */ enum /* PDF page mode */ { PDF_DOCUMENT, PDF_OUTLINE, PDF_FULLSCREEN }; enum /* PDF page layout */ { PDF_SINGLE, PDF_ONE_COLUMN, PDF_TWO_COLUMN_LEFT, PDF_TWO_COLUMN_RIGHT }; enum /* PDF first page */ { PDF_PAGE_1, PDF_TOC, PDF_CHAPTER_1 }; enum /* PDF transition effect */ { PDF_NONE, PDF_BOX_INWARD, PDF_BOX_OUTWARD, PDF_DISSOLVE, PDF_GLITTER_DOWN, PDF_GLITTER_DOWN_RIGHT, PDF_GLITTER_RIGHT, PDF_HORIZONTAL_BLINDS, PDF_HORIZONTAL_SWEEP_INWARD, PDF_HORIZONTAL_SWEEP_OUTWARD, PDF_VERTICAL_BLINDS, PDF_VERTICAL_SWEEP_INWARD, PDF_VERTICAL_SWEEP_OUTWARD, PDF_WIPE_DOWN, PDF_WIPE_LEFT, PDF_WIPE_RIGHT, PDF_WIPE_UP }; enum /* PDF document permissions */ { PDF_PERM_PRINT = 4, PDF_PERM_MODIFY = 8, PDF_PERM_COPY = 16, PDF_PERM_ANNOTATE = 32 }; /* * Globals... */ #ifdef _HTMLDOC_CXX_ # define VAR # define VALUE(x) =x # define NULL3 ={0,0,0} #else # define VAR extern # define VALUE(x) # define NULL3 #endif /* _HTML_DOC_CXX_ */ VAR int Verbosity VALUE(0); /* Verbosity */ VAR int OverflowErrors VALUE(0); /* Show errors on overflow */ VAR int StrictHTML VALUE(0); /* Do strict HTML checking */ VAR int CGIMode VALUE(0); /* Running as CGI? */ VAR int Errors VALUE(0); /* Number of errors */ VAR int Compression VALUE(1); /* Non-zero means compress PDFs */ VAR int TitlePage VALUE(1), /* Need a title page */ TocLevels VALUE(3), /* Number of table-of-contents levels */ TocLinks VALUE(1), /* Generate links */ TocNumbers VALUE(0), /* Generate heading numbers */ TocDocCount VALUE(0); /* Number of chapters */ VAR int OutputType VALUE(OUTPUT_BOOK); /* Output a "book", etc. */ VAR char OutputPath[1024] VALUE(""); /* Output directory/name */ VAR int OutputFiles VALUE(0), /* Generate multiple files? */ OutputColor VALUE(1); /* Output color images */ VAR int OutputJPEG VALUE(0); /* JPEG compress images? */ VAR int PDFVersion VALUE(13); /* Version of PDF to support */ VAR int PDFPageMode VALUE(PDF_OUTLINE), /* PageMode attribute */ PDFPageLayout VALUE(PDF_SINGLE), /* PageLayout attribute */ PDFFirstPage VALUE(PDF_CHAPTER_1), /* First page */ PDFEffect VALUE(PDF_NONE);/* Page transition effect */ VAR double PDFEffectDuration VALUE(1.0), /* Page effect duration */ PDFPageDuration VALUE(10.0); /* Page duration */ VAR int Encryption VALUE(0), /* Encrypt the PDF file? */ Permissions VALUE(-4); /* File permissions? */ VAR char OwnerPassword[33] VALUE(""), /* Owner password */ UserPassword[33] VALUE(""); /* User password */ VAR int EmbedFonts VALUE(1); /* Embed fonts? */ VAR int PSLevel VALUE(2), /* Language level (0 for PDF) */ PSCommands VALUE(0), /* Output PostScript commands? */ XRXComments VALUE(0); /* Output Xerox comments? */ VAR int PageWidth VALUE(595), /* Page width in points */ PageLength VALUE(792), /* Page length in points */ PageLeft VALUE(72), /* Left margin */ PageRight VALUE(36), /* Right margin */ PageTop VALUE(36), /* Top margin */ PageBottom VALUE(36), /* Bottom margin */ PagePrintWidth, /* Printable width */ PagePrintLength, /* Printable length */ PageDuplex VALUE(0), /* Adjust margins/pages for duplexing? */ Landscape VALUE(0), /* Landscape orientation? */ NumberUp VALUE(1); /* Number-up pages */ VAR typeface_t HeadFootType VALUE(TYPE_HELVETICA); /* Typeface for header & footer */ VAR style_t HeadFootStyle VALUE(STYLE_NORMAL); /* Type style */ VAR double HeadFootSize VALUE(11.0f); /* Size of header & footer */ VAR char *Header[3] NULL3, /* Header for regular pages */ *Header1[3] NULL3, /* Header for first pages */ *TocHeader[3] NULL3, /* Header for TOC pages */ *Footer[3] NULL3, /* Regular page footer */ *TocFooter[3] NULL3, /* Footer for TOC pages */ TocTitle[1024] VALUE("Table of Contents"); /* TOC title string */ VAR char TitleImage[1024] VALUE(""), /* Title page image */ LogoImage[1024] VALUE(""), /* Logo image */ BodyColor[255] VALUE(""), /* Body color */ BodyImage[1024] VALUE(""), /* Body image */ LinkColor[255] VALUE(""); /* Link color */ VAR char HFImage[MAX_HF_IMAGES][1024] /* Header/footer images */ # ifdef _HTMLDOC_CXX_ = { "" } # endif /* _HTMLDOC_CXX_ */ ; VAR int LinkStyle VALUE(1); /* 1 = underline, 0 = plain */ VAR int Links VALUE(1); /* 1 = generate links, 0 = no links */ VAR char Path[2048] VALUE(""), /* Search path */ Proxy[1024] VALUE(""); /* Proxy URL */ VAR const char *PDFModes[3] /* Mode strings */ # ifdef _HTMLDOC_CXX_ = { "document", "outline", "fullscreen" } # endif /* _HTMLDOC_CXX_ */ ; VAR const char *PDFLayouts[4] /* Layout strings */ # ifdef _HTMLDOC_CXX_ = { "single", "one", "twoleft", "tworight" } # endif /* _HTMLDOC_CXX_ */ ; VAR const char *PDFPages[3] /* First page strings */ # ifdef _HTMLDOC_CXX_ = { "p1", "toc", "c1" } # endif /* _HTMLDOC_CXX_ */ ; VAR const char *PDFEffects[17] /* Effect strings */ # ifdef _HTMLDOC_CXX_ = { "none", "bi", "bo", "d", "gd", "gdr", "gr", "hb", "hsi", "hso", "vb", "vsi", "vso", "wd", "wl", "wr", "wu" } # endif /* _HTMLDOC_CXX_ */ ; #ifdef HAVE_LIBFLTK VAR GUI *BookGUI VALUE(NULL); /* GUI for book files */ # ifdef WIN32 /* Editor for HTML files */ VAR char HTMLEditor[1024] VALUE("notepad.exe \"%s\""); # elif defined(__APPLE__) VAR char HTMLEditor[1024] VALUE("bbedit %s"); # elif defined(__linux) VAR char HTMLEditor[1024] VALUE("gedit %s"); # else VAR char HTMLEditor[1024] VALUE("nedit %s"); # endif /* WIN32 */ VAR int Tooltips VALUE(0); /* Show tooltips? */ #endif /* HAVE_LIBFLTK */ /* * Prototypes... */ extern int pspdf_export(tree_t *document, tree_t *toc); extern int epub_export(tree_t *document, tree_t *toc); extern int html_export(tree_t *document, tree_t *toc); extern int htmlsep_export(tree_t *document, tree_t *toc); extern tree_t *toc_build(tree_t *tree); extern void get_color(const uchar *c, float *rgb, int defblack = 1); extern const char *get_fmt(char **formats); extern void get_format(const char *fmt, char **formats); extern int get_measurement(const char *s, float mul = 1.0f); extern void set_page_size(const char *size); extern void prefs_load(void); extern void prefs_save(void); extern void prefs_set_paths(void); extern char *format_number(int n, char f); #ifdef __cplusplus } #endif /* __cplusplus */ htmldoc-1.9.7/htmldoc/htmllib.cxx000066400000000000000000002566651354715574200170340ustar00rootroot00000000000000/* * HTML parsing routines for HTMLDOC, a HTML document processing program. * * Copyright 2011-2019 by Michael R Sweet. * Copyright 1997-2010 by Easy Software Products. All rights reserved. * * This program is free software. Distribution and use rights are outlined in * the file "COPYING". */ /* * Include necessary headers. */ #include "htmldoc.h" #include /* * Markup strings... */ const char *_htmlMarkups[] = { "", /* MARKUP_NONE */ "!--", /* MARKUP_COMMENT */ "!DOCTYPE", "a", "acronym", "address", "applet", "area", "b", "base", "basefont", "big", "blink", "blockquote", "body", "br", "caption", "center", "cite", "code", "col", "colgroup", "dd", "del", "dfn", "dir", "div", "dl", "dt", "em", "embed", "font", "form", "frame", "frameset", "h1", "h2", "h3", "h4", "h5", "h6", "h7", "h8", "h9", "h10", "h11", "h12", "h13", "h14", "h15", "head", "hr", "html", "i", "img", "input", "ins", "isindex", "kbd", "li", "link", "map", "menu", "meta", "multicol", "nobr", "noframes", "ol", "option", "p", "pre", "s", "samp", "script", "select", "small", "spacer", "span", "strike", "strong", "style", "sub", "sup", "table", "tbody", "td", "textarea", "tfoot", "th", "thead", "title", "tr", "tt", "u", "ul", "var", "wbr" }; const char *_htmlCurrentFile = "UNKNOWN"; /* Current file */ const char *_htmlData = HTML_DATA; /* Data directory */ float _htmlPPI = 80.0f; /* Image resolution */ int _htmlGrayscale = 0; /* Grayscale output? */ uchar _htmlTextColor[255] = /* Default text color */ { 0 }; float _htmlBrowserWidth = 680.0f; /* Browser width for pixel scaling */ float _htmlSizes[8] = /* Point size for each HTML size */ { 6.0f, 8.0f, 9.0f, 11.0f, 14.0f, 17.0f, 20.0f, 24.0f }; float _htmlSpacings[8] = /* Line height for each HTML size */ { 7.2f, 9.6f, 10.8f, 13.2f, 16.8f, 20.4f, 24.0f, 28.8f }; typeface_t _htmlBodyFont = TYPE_TIMES, _htmlHeadingFont = TYPE_HELVETICA; int _htmlInitialized = 0; /* Initialized glyphs yet? */ char _htmlCharSet[256] = "iso-8859-1"; /* Character set name */ extern int _htmlWidthsLoaded[TYPE_MAX][STYLE_MAX] = { /* Have the widths been loaded? */ { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 } }; short _htmlWidths[TYPE_MAX][STYLE_MAX][256]; /* Character widths of fonts */ short _htmlWidthsAll[TYPE_MAX][STYLE_MAX][65536]; /* Unicode widths of fonts */ int _htmlUnicode[256]; /* Character to Unicode mapping */ uchar _htmlCharacters[65536]; /* Unicode to character mapping */ int _htmlUTF8 = 0; /* Doing UTF-8? */ const char *_htmlGlyphsAll[65536]; /* Character glyphs for Unicode */ const char *_htmlGlyphs[256]; /* Character glyphs for charset */ int _htmlNumSorted = 0; /* Number of sorted glyphs */ const char *_htmlSorted[256]; /* Sorted character glyphs for charset */ uchar _htmlSortedChars[256]; /* Sorted character indices */ const char *_htmlFonts[TYPE_MAX][STYLE_MAX] = { { "Courier", "Courier-Bold", "Courier-Oblique", "Courier-BoldOblique" }, { "Times-Roman", "Times-Bold", "Times-Italic", "Times-BoldItalic" }, { "Helvetica", "Helvetica-Bold", "Helvetica-Oblique", "Helvetica-BoldOblique" }, { "Monospace", "Monospace-Bold", "Monospace-Oblique", "Monospace-BoldOblique" }, { "Serif-Roman", "Serif-Bold", "Serif-Oblique", "Serif-BoldOblique" }, { "Sans", "Sans-Bold", "Sans-Oblique", "Sans-BoldOblique" }, { "Symbol", "Symbol", "Symbol", "Symbol" }, { "Dingbats", "Dingbats", "Dingbats", "Dingbats" } }; int _htmlStandardFonts[TYPE_MAX] = { 1, // Courier 1, // Times 1, // Helvetica 0, // Monospace 0, // Sans 0, // Serif 1, // Symbol 1 // Dingbats }; /* * Local functions. */ extern "C" { typedef int (*compare_func_t)(const void *, const void *); } static int write_file(tree_t *t, FILE *fp, int col); static int compare_variables(var_t *v0, var_t *v1); static int compare_markups(uchar **m0, uchar **m1); static void delete_node(tree_t *t); static void insert_space(tree_t *parent, tree_t *t); static int parse_markup(tree_t *t, FILE *fp, int *linenum); static int parse_variable(tree_t *t, FILE *fp, int *linenum); static int compute_size(tree_t *t); static int compute_color(tree_t *t, uchar *color); static int get_alignment(tree_t *t); static const char *fix_filename(char *path, char *base); static int utf8_getc(int ch, FILE *fp); #define issuper(x) ((x) == MARKUP_CENTER || (x) == MARKUP_DIV ||\ (x) == MARKUP_BLOCKQUOTE) #define isblock(x) ((x) == MARKUP_ADDRESS || \ (x) == MARKUP_P || (x) == MARKUP_PRE ||\ ((x) >= MARKUP_H1 && (x) <= MARKUP_H6) ||\ (x) == MARKUP_HR || (x) == MARKUP_TABLE) #define islist(x) ((x) == MARKUP_DL || (x) == MARKUP_OL ||\ (x) == MARKUP_UL || (x) == MARKUP_DIR ||\ (x) == MARKUP_MENU) #define islentry(x) ((x) == MARKUP_LI || (x) == MARKUP_DD ||\ (x) == MARKUP_DT) #define istable(x) ((x) == MARKUP_TBODY || (x) == MARKUP_THEAD ||\ (x) == MARKUP_TFOOT || (x) == MARKUP_TR) #define istentry(x) ((x) == MARKUP_TD || (x) == MARKUP_TH) #ifdef DEBUG static uchar indent[255] = ""; #endif /* DEBUG */ /* * 'htmlReadFile()' - Read a file for HTML markup codes. */ tree_t * // O - Pointer to top of file tree htmlReadFile(tree_t *parent, // I - Parent tree entry FILE *fp, // I - File pointer const char *base) // I - Base directory for file { int ch; // Character from file uchar *ptr, // Pointer in string entity[16], // Character entity name (&#nnn; or &name;) *eptr; // Pointer in entity string tree_t *tree, // "top" of this tree *t, // New tree entry *prev, // Previous tree entry *temp; // Temporary looping var int descend; // Descend into node? FILE *embed; // File pointer for EMBED char newbase[1024]; // New base directory for EMBED uchar *filename, // Filename for EMBED tag *face, // Typeface for FONT tag *color, // Color for FONT tag *size, // Size for FONT tag *type, // Type for EMBED tag *span; // Value for SPAN tag int sizeval; // Size value from FONT tag int linenum; // Line number in file static uchar s[10240]; // String from file static int have_whitespace = 0; // Non-zero if there was leading whitespace DEBUG_printf(("htmlReadFile(parent=%p, fp=%p, base=\"%s\")\n", (void *)parent, (void *)fp, base ? base : "(null)")); #ifdef DEBUG indent[0] = '\0'; #endif // DEBUG /* * Start off with no previous tree entry... */ prev = NULL; tree = NULL; /* * Parse data until we hit end-of-file... */ linenum = 1; while ((ch = getc(fp)) != EOF) { /* * Ignore leading whitespace... */ if (parent == NULL || !parent->preformatted) { while (isspace(ch)) { if (ch == '\n') linenum ++; have_whitespace = 1; ch = getc(fp); } if (ch == EOF) break; } /* * Allocate a new tree entry - use calloc() to get zeroed data... */ t = (tree_t *)calloc(sizeof(tree_t), 1); if (t == NULL) { #ifndef DEBUG progress_error(HD_ERROR_OUT_OF_MEMORY, "Unable to allocate memory for HTML tree node!"); #endif /* !DEBUG */ break; } /* * Set/copy font characteristics... */ if (parent == NULL) { t->halignment = ALIGN_LEFT; t->valignment = ALIGN_BOTTOM; t->typeface = _htmlBodyFont; t->size = SIZE_P; compute_color(t, _htmlTextColor); } else { t->link = parent->link; t->halignment = parent->halignment; t->valignment = parent->valignment; t->typeface = parent->typeface; t->size = parent->size; t->style = parent->style; t->superscript = parent->superscript; t->subscript = parent->subscript; t->preformatted = parent->preformatted; t->indent = parent->indent; t->red = parent->red; t->green = parent->green; t->blue = parent->blue; t->underline = parent->underline; t->strikethrough = parent->strikethrough; } /* * See what the character was... */ if (ch == '<') { /* * Markup char; grab the next char to see if this is a /... */ ch = getc(fp); if (isspace(ch) || ch == '=' || ch == '<') { /* * Sigh... "<" followed by anything but an element name is * invalid HTML, but so many people have asked for this to * be supported that we have added this hack... */ progress_error(HD_ERROR_HTML_ERROR, "Unquoted < on line %d of %s.", linenum, _htmlCurrentFile); if (ch == '\n') linenum ++; ptr = s; if (have_whitespace) { *ptr++ = ' '; have_whitespace = 0; } *ptr++ = '<'; if (ch == '=') *ptr++ = '='; else if (ch == '<') ungetc(ch, fp); else have_whitespace = 1; *ptr++ = '\0'; t->markup = MARKUP_NONE; t->data = (uchar *)strdup((char *)s); } else { /* * Start of a markup... */ if (ch != '/') ungetc(ch, fp); if (parse_markup(t, fp, &linenum) == MARKUP_ERROR) { #ifndef DEBUG progress_error(HD_ERROR_READ_ERROR, "Unable to parse HTML element on line %d of %s!", linenum, _htmlCurrentFile); #endif /* !DEBUG */ delete_node(t); break; } /* * Eliminate extra whitespace... */ if (issuper(t->markup) || isblock(t->markup) || islist(t->markup) || islentry(t->markup) || istable(t->markup) || istentry(t->markup) || t->markup == MARKUP_TITLE) have_whitespace = 0; /* * If this is the matching close mark, or if we are starting the same * markup, or if we've completed a list, we're done! */ if (ch == '/') { /* * Close markup; find matching markup... */ for (temp = parent; temp != NULL; temp = temp->parent) if (temp->markup == t->markup) break; else if (temp->markup == MARKUP_EMBED) { temp = NULL; break; } } else if (t->markup == MARKUP_BODY || t->markup == MARKUP_HEAD) { /* * Make sure we aren't inside an existing HEAD or BODY... */ for (temp = parent; temp != NULL; temp = temp->parent) if (temp->markup == MARKUP_BODY || temp->markup == MARKUP_HEAD) break; else if (temp->markup == MARKUP_EMBED) { temp = NULL; break; } } else if (t->markup == MARKUP_EMBED) { /* * Close any text blocks... */ for (temp = parent; temp != NULL; temp = temp->parent) if (isblock(temp->markup) || islentry(temp->markup)) break; else if (istentry(temp->markup) || islist(temp->markup) || issuper(temp->markup) || temp->markup == MARKUP_EMBED) { temp = NULL; break; } } else if (issuper(t->markup)) { for (temp = parent; temp != NULL; temp = temp->parent) if (istentry(temp->markup) || temp->markup == MARKUP_EMBED) { temp = NULL; break; } } else if (islist(t->markup)) { for (temp = parent; temp != NULL; temp = temp->parent) if (isblock(temp->markup)) break; else if (islentry(temp->markup) || istentry(temp->markup) || issuper(temp->markup) || temp->markup == MARKUP_EMBED) { temp = NULL; break; } } else if (islentry(t->markup)) { for (temp = parent; temp != NULL; temp = temp->parent) if (islentry(temp->markup)) break; else if (islist(temp->markup) || issuper(temp->markup) || istentry(temp->markup) || temp->markup == MARKUP_EMBED) { temp = NULL; break; } } else if (isblock(t->markup)) { for (temp = parent; temp != NULL; temp = temp->parent) if (isblock(temp->markup)) break; else if (istentry(temp->markup) || islist(temp->markup) || islentry(temp->markup) || issuper(temp->markup) || temp->markup == MARKUP_EMBED) { temp = NULL; break; } } else if (t->markup == MARKUP_THEAD || t->markup == MARKUP_TBODY || t->markup == MARKUP_TFOOT) { for (temp = parent; temp != NULL; temp = temp->parent) if (temp->markup == MARKUP_TABLE || temp->markup == MARKUP_EMBED) { temp = NULL; break; } } else if (istentry(t->markup)) { for (temp = parent; temp != NULL; temp = temp->parent) if (istentry(temp->markup)) break; else if (temp->markup == MARKUP_TABLE || istable(temp->markup) || temp->markup == MARKUP_EMBED) { if (temp->markup != MARKUP_TR) { // Strictly speaking, this is an error - TD/TH can only // be found under TR, but web browsers automatically // inject a TR... progress_error(HD_ERROR_HTML_ERROR, "No TR element before %s element on line %d of %s.", _htmlMarkups[t->markup], linenum, _htmlCurrentFile); parent = htmlAddTree(temp, MARKUP_TR, NULL); prev = NULL; DEBUG_printf(("%str (inserted) under %s, line %d\n", indent, _htmlMarkups[temp->markup], linenum)); } temp = NULL; break; } } else temp = NULL; if (temp != NULL) { DEBUG_printf(("%s>>>> Auto-ascend <<<\n", indent)); if (ch != '/' && temp->markup != MARKUP_BODY && temp->markup != MARKUP_DD && temp->markup != MARKUP_DT && temp->markup != MARKUP_HEAD && temp->markup != MARKUP_HTML && temp->markup != MARKUP_LI && temp->markup != MARKUP_OPTION && temp->markup != MARKUP_P && temp->markup != MARKUP_TBODY && temp->markup != MARKUP_TD && temp->markup != MARKUP_TFOOT && temp->markup != MARKUP_TH && temp->markup != MARKUP_THEAD && temp->markup != MARKUP_TR) { // Log this condition as an error... progress_error(HD_ERROR_HTML_ERROR, "No /%s element before %s element on line %d of %s.", _htmlMarkups[temp->markup], _htmlMarkups[t->markup], linenum, _htmlCurrentFile); DEBUG_printf(("%sNo /%s element before %s element on line %d.\n", indent, _htmlMarkups[temp->markup], _htmlMarkups[t->markup], linenum)); } #ifdef DEBUG for (tree_t *p = parent; p && p != temp && indent[0]; p = p->parent) indent[strlen((char *)indent) - 4] = '\0'; if (indent[0]) indent[strlen((char *)indent) - 4] = '\0'; #endif // DEBUG // Safety check; should never happen, since MARKUP_FILE is // the root node created by the caller... if (temp->parent) { parent = temp->parent; prev = parent->last_child; } else { for (prev = temp; prev->next; prev = prev->next); parent = NULL; } if (ch == '/') { // Closing element, so delete this node... delete_node(t); continue; } else { // Reparent the node... if (parent == NULL) { t->halignment = ALIGN_LEFT; t->valignment = ALIGN_BOTTOM; t->typeface = _htmlBodyFont; t->size = SIZE_P; compute_color(t, _htmlTextColor); } else { t->link = parent->link; t->halignment = parent->halignment; t->valignment = parent->valignment; t->typeface = parent->typeface; t->size = parent->size; t->style = parent->style; t->superscript = parent->superscript; t->subscript = parent->subscript; t->preformatted = parent->preformatted; t->indent = parent->indent; t->red = parent->red; t->green = parent->green; t->blue = parent->blue; t->underline = parent->underline; t->strikethrough = parent->strikethrough; } } } else if (ch == '/') { // Log this condition as an error... if (t->markup != MARKUP_UNKNOWN && t->markup != MARKUP_COMMENT) { progress_error(HD_ERROR_HTML_ERROR, "Dangling /%s element on line %d of %s.", _htmlMarkups[t->markup], linenum, _htmlCurrentFile); DEBUG_printf(("%sDangling /%s element on line %d.\n", indent, _htmlMarkups[t->markup], linenum)); } delete_node(t); continue; } } } else if (t->preformatted) { /* * Read a pre-formatted string into the current tree entry... */ ptr = s; while (ch != '<' && ch != EOF && ptr < (s + sizeof(s) - 1)) { if (ch == '&') { // Possibly a character entity... eptr = entity; while (eptr < (entity + sizeof(entity) - 1) && (ch = getc(fp)) != EOF) if (!isalnum(ch) && ch != '#') break; else *eptr++ = (uchar)ch; if (ch != ';') { ungetc(ch, fp); ch = 0; } *eptr = '\0'; if (!ch) { progress_error(HD_ERROR_HTML_ERROR, "Unquoted & on line %d of %s.", linenum, _htmlCurrentFile); if (ptr < (s + sizeof(s) - 1)) *ptr++ = '&'; strlcpy((char *)ptr, (char *)entity, sizeof(s) - (size_t)(ptr - s)); ptr += strlen((char *)ptr); } else if ((ch = iso8859(entity)) == 0) { progress_error(HD_ERROR_HTML_ERROR, "Unknown character entity \"&%s;\" on line %d of %s.", entity, linenum, _htmlCurrentFile); if (ptr < (s + sizeof(s) - 1)) *ptr++ = '&'; strlcpy((char *)ptr, (char *)entity, sizeof(s) - (size_t)(ptr - s)); ptr += strlen((char *)ptr); if (ptr < (s + sizeof(s) - 1)) *ptr++ = ';'; } else *ptr++ = (uchar)ch; } else if ((ch & 0x80) && _htmlUTF8) { // Collect UTF-8 value... ch = utf8_getc(ch, fp); if (ch) *ptr++ = (uchar)ch; } else if (ch != 0 && ch != '\r') { *ptr++ = (uchar)ch; if (ch == '\n') { linenum ++; break; } } ch = getc(fp); } *ptr = '\0'; if (ch == '<') ungetc(ch, fp); t->markup = MARKUP_NONE; t->data = (uchar *)strdup((char *)s); DEBUG_printf(("%sfragment \"%s\", line %d\n", indent, s, linenum)); } else { /* * Read the next string fragment... */ ptr = s; if (have_whitespace) { *ptr++ = ' '; have_whitespace = 0; } while (!isspace(ch) && ch != '<' && ch != EOF && ptr < (s + sizeof(s) - 1)) { if (ch == '&') { // Possibly a character entity... eptr = entity; while (eptr < (entity + sizeof(entity) - 1) && (ch = getc(fp)) != EOF) if (!isalnum(ch) && ch != '#') break; else *eptr++ = (uchar)ch; *eptr = '\0'; if (ch != ';') { ungetc(ch, fp); ch = 0; } if (!ch) { progress_error(HD_ERROR_HTML_ERROR, "Unquoted & on line %d of %s.", linenum, _htmlCurrentFile); if (ptr < (s + sizeof(s) - 1)) *ptr++ = '&'; strlcpy((char *)ptr, (char *)entity, sizeof(s) - (size_t)(ptr - s)); ptr += strlen((char *)ptr); } else if ((ch = iso8859(entity)) == 0) { progress_error(HD_ERROR_HTML_ERROR, "Unknown character entity \"&%s;\" on line %d of %s.", entity, linenum, _htmlCurrentFile); if (ptr < (s + sizeof(s) - 1)) *ptr++ = '&'; strlcpy((char *)ptr, (char *)entity, sizeof(s) - (size_t)(ptr - s)); ptr += strlen((char *)ptr); if (ptr < (s + sizeof(s) - 1)) *ptr++ = ';'; } else *ptr++ = (uchar)ch; } else { if ((ch & 0x80) && _htmlUTF8) { // Collect UTF-8 value... ch = utf8_getc(ch, fp); } if (ch) *ptr++ = (uchar)ch; } if ((_htmlUTF8 && ch == _htmlCharacters[173]) || (!_htmlUTF8 && ch == 173)) break; ch = getc(fp); } if (ch == '\n') linenum ++; if (isspace(ch)) have_whitespace = 1; *ptr = '\0'; if (ch == '<') ungetc(ch, fp); t->markup = MARKUP_NONE; t->data = (uchar *)strdup((char *)s); DEBUG_printf(("%sfragment \"%s\" (len=%d), line %d\n", indent, s, (int)(ptr - s), linenum)); } /* * If the parent tree pointer is not null and this is the first * entry we've read, set the child pointer... */ DEBUG_printf(("%sADDING %s node to %s parent!\n", indent, _htmlMarkups[t->markup], parent ? _htmlMarkups[parent->markup] : "ROOT")); if (parent != NULL && prev == NULL) parent->child = t; if (parent != NULL) parent->last_child = t; /* * Do the prev/next links... */ t->parent = parent; t->prev = prev; if (prev != NULL) prev->next = t; if (tree == NULL) tree = t; prev = t; /* * Do markup-specific stuff... */ descend = 0; switch (t->markup) { case MARKUP_BODY : /* * Update the text color as necessary... */ if ((color = htmlGetVariable(t, (uchar *)"TEXT")) != NULL) compute_color(t, color); else compute_color(t, _htmlTextColor); if ((color = htmlGetVariable(t, (uchar *)"BGCOLOR")) != NULL && !BodyColor[0]) strlcpy(BodyColor, (char *)color, sizeof(BodyColor)); // Update the background image as necessary... if ((filename = htmlGetVariable(t, (uchar *)"BACKGROUND")) != NULL) htmlSetVariable(t, (uchar *)"BACKGROUND", (uchar *)fix_filename((char *)filename, (char *)base)); descend = 1; break; case MARKUP_IMG : if (have_whitespace) { // Insert a space before this image... insert_space(parent, t); have_whitespace = 0; } // Get the image alignment... t->valignment = ALIGN_BOTTOM; get_alignment(t); // Update the image source as necessary... if ((filename = htmlGetVariable(t, (uchar *)"SRC")) != NULL) htmlSetVariable(t, (uchar *)"REALSRC", (uchar *)fix_filename((char *)filename, (char *)base)); case MARKUP_BR : case MARKUP_NONE : case MARKUP_SPACER : /* * Figure out the width & height of this markup... */ compute_size(t); break; case MARKUP_H1 : case MARKUP_H2 : case MARKUP_H3 : case MARKUP_H4 : case MARKUP_H5 : case MARKUP_H6 : case MARKUP_H7 : case MARKUP_H8 : case MARKUP_H9 : case MARKUP_H10 : case MARKUP_H11 : case MARKUP_H12 : case MARKUP_H13 : case MARKUP_H14 : case MARKUP_H15 : get_alignment(t); t->typeface = _htmlHeadingFont; t->subscript = 0; t->superscript = 0; t->strikethrough = 0; t->preformatted = 0; if (t->markup > MARKUP_H6) { t->size = SIZE_H7; t->style = STYLE_ITALIC; } else { t->size = (unsigned)(SIZE_H1 - t->markup + MARKUP_H1); t->style = STYLE_BOLD; } descend = 1; break; case MARKUP_P : get_alignment(t); t->typeface = _htmlBodyFont; t->size = SIZE_P; t->style = STYLE_NORMAL; t->subscript = 0; t->superscript = 0; t->strikethrough = 0; t->preformatted = 0; descend = 1; break; case MARKUP_PRE : t->typeface = _htmlBodyFont >= TYPE_MONOSPACE ? TYPE_MONOSPACE : TYPE_COURIER; t->size = SIZE_PRE; t->style = STYLE_NORMAL; t->subscript = 0; t->superscript = 0; t->strikethrough = 0; t->preformatted = 1; descend = 1; break; case MARKUP_BLOCKQUOTE : case MARKUP_DIR : case MARKUP_MENU : case MARKUP_UL : case MARKUP_OL : case MARKUP_DL : t->indent ++; descend = 1; break; case MARKUP_DIV : get_alignment(t); descend = 1; break; case MARKUP_HR : t->halignment = ALIGN_CENTER; get_alignment(t); break; case MARKUP_DOCTYPE : case MARKUP_AREA : case MARKUP_COMMENT : case MARKUP_INPUT : case MARKUP_ISINDEX : case MARKUP_LINK : case MARKUP_META : case MARKUP_WBR : case MARKUP_COL : break; case MARKUP_EMBED : if ((type = htmlGetVariable(t, (uchar *)"TYPE")) != NULL && strncasecmp((const char *)type, "text/html", 9) != 0) break; if ((filename = htmlGetVariable(t, (uchar *)"SRC")) != NULL) { const char *save_name = _htmlCurrentFile; filename = (uchar *)fix_filename((char *)filename, (char *)base); if ((embed = fopen((char *)filename, "r")) != NULL) { strlcpy(newbase, file_directory((char *)filename), sizeof(newbase)); _htmlCurrentFile = (char *)filename; htmlReadFile(t, embed, newbase); fclose(embed); _htmlCurrentFile = save_name; } #ifndef DEBUG else progress_error(HD_ERROR_FILE_NOT_FOUND, "Unable to embed \"%s\" - %s", filename, strerror(errno)); #endif /* !DEBUG */ } break; case MARKUP_TH : if (htmlGetVariable(t->parent, (uchar *)"ALIGN") != NULL) t->halignment = t->parent->halignment; else t->halignment = ALIGN_CENTER; if (htmlGetVariable(t->parent, (uchar *)"VALIGN") != NULL) t->valignment = t->parent->valignment; else t->valignment = ALIGN_MIDDLE; get_alignment(t); t->style = STYLE_BOLD; descend = 1; break; case MARKUP_TD : if (htmlGetVariable(t->parent, (uchar *)"ALIGN") != NULL) t->halignment = t->parent->halignment; else t->halignment = ALIGN_LEFT; if (htmlGetVariable(t->parent, (uchar *)"VALIGN") != NULL) t->valignment = t->parent->valignment; else t->valignment = ALIGN_MIDDLE; get_alignment(t); t->style = STYLE_NORMAL; descend = 1; break; case MARKUP_SPAN : // Pull style data, if present... if (have_whitespace) { // Insert a space before this element... insert_space(parent, t); have_whitespace = 0; } get_alignment(t); if ((color = htmlGetStyle(t, (uchar *)"color:")) != NULL) compute_color(t, color); if ((face = htmlGetStyle(t, (uchar *)"font-family:")) != NULL) { char font[255], // Font name *fontptr; // Pointer into font name for (ptr = face; *ptr;) { while (isspace(*ptr) || *ptr == ',') ptr ++; if (!*ptr) break; for (fontptr = font; *ptr && *ptr != ',' && !isspace(*ptr); ptr ++) if (fontptr < (font + sizeof(font) - 1)) *fontptr++ = (char)*ptr; *fontptr = '\0'; if (!strcasecmp(font, "serif")) { t->typeface = TYPE_SERIF; break; } else if (!strcasecmp(font, "sans-serif") || !strcasecmp(font, "sans")) { t->typeface = TYPE_SANS_SERIF; break; } else if (!strcasecmp(font, "monospace")) { t->typeface = TYPE_MONOSPACE; break; } else if (!strcasecmp(font, "arial") || !strcasecmp(font, "helvetica")) { t->typeface = TYPE_HELVETICA; break; } else if (!strcasecmp(font, "times")) { t->typeface = TYPE_TIMES; break; } else if (!strcasecmp(font, "courier")) { t->typeface = TYPE_COURIER; break; } else if (!strcasecmp(font, "symbol")) { t->typeface = TYPE_SYMBOL; break; } else if (!strcasecmp(font, "dingbat")) { t->typeface = TYPE_DINGBATS; break; } } } if ((size = htmlGetStyle(t, (uchar *)"font-size:")) != NULL) { // Find the closest size to the fixed sizes... unsigned i; double fontsize = atof((char *)size); for (i = 0; i < 7; i ++) if (fontsize <= _htmlSizes[i]) break; t->size = i; } if ((span = htmlGetStyle(t, (uchar *)"font-style:")) != NULL) { if (!strcmp((char *)span, "normal")) t->style &= ~STYLE_ITALIC; else if (!strcmp((char *)span, "italic") || !strcmp((char *)span, "oblique")) t->style |= STYLE_ITALIC; } if ((span = htmlGetStyle(t, (uchar *)"font-weight:")) != NULL) { if (!strcmp((char *)span, "bold") || !strcmp((char *)span, "bolder") || !strcmp((char *)span, "700") || !strcmp((char *)span, "800") || !strcmp((char *)span, "900")) t->style |= STYLE_BOLD; else if (strcmp((char *)span, "inherit")) t->style &= ~STYLE_BOLD; } if ((span = htmlGetStyle(t, (uchar *)"text-decoration:")) != NULL) { if (!strcmp((char *)span, "underline")) t->underline = 1; else if (!strcmp((char *)span, "line-through")) t->strikethrough = 1; else if (strcmp((char *)span, "inherit")) t->underline = t->strikethrough = 0; } if ((span = htmlGetStyle(t, (uchar *)"vertical-align:")) != NULL) { if (!strcmp((char *)span, "sub")) t->subscript = 1; else if (!strcmp((char *)span, "super")) t->superscript = 1; else if (strcmp((char *)span, "inherit")) t->subscript = t->superscript = 0; } descend = 1; break; case MARKUP_FONT : if (have_whitespace) { // Insert a space before this element... insert_space(parent, t); have_whitespace = 0; } if ((face = htmlGetVariable(t, (uchar *)"FACE")) != NULL) { char font[255], // Font name *fontptr; // Pointer into font name for (ptr = face; *ptr;) { while (isspace(*ptr) || *ptr == ',') ptr ++; if (!*ptr) break; for (fontptr = font; *ptr && *ptr != ',' && !isspace(*ptr); ptr ++) if (fontptr < (font + sizeof(font) - 1)) *fontptr++ = (char)*ptr; *fontptr = '\0'; if (!strcasecmp(font, "serif")) { t->typeface = TYPE_SERIF; break; } else if (!strcasecmp(font, "sans-serif") || !strcasecmp(font, "sans")) { t->typeface = TYPE_SANS_SERIF; break; } else if (!strcasecmp(font, "mono")) { t->typeface = TYPE_MONOSPACE; break; } else if (!strcasecmp(font, "arial") || !strcasecmp(font, "helvetica")) { t->typeface = TYPE_HELVETICA; break; } else if (!strcasecmp(font, "times")) { t->typeface = TYPE_TIMES; break; } else if (!strcasecmp(font, "courier")) { t->typeface = TYPE_COURIER; break; } else if (!strcasecmp(font, "symbol")) { t->typeface = TYPE_SYMBOL; break; } else if (!strcasecmp(font, "dingbat")) { t->typeface = TYPE_DINGBATS; break; } } } if ((color = htmlGetVariable(t, (uchar *)"COLOR")) != NULL) compute_color(t, color); if ((size = htmlGetVariable(t, (uchar *)"SIZE")) != NULL) { if (have_whitespace) { // Insert a space before sized text... insert_space(parent, t); have_whitespace = 0; } if (isdigit(size[0])) sizeval = atoi((char *)size); else sizeval = t->size + atoi((char *)size); if (sizeval < 0) t->size = 0; else if (sizeval > 7) t->size = 7; else t->size = (unsigned)sizeval; } descend = 1; break; case MARKUP_BIG : if (have_whitespace) { // Insert a space before big text... insert_space(parent, t); have_whitespace = 0; } if (t->size < 6) t->size += 2; else t->size = 7; descend = 1; break; case MARKUP_SMALL : if (have_whitespace) { // Insert a space before small text... insert_space(parent, t); have_whitespace = 0; } if (t->size > 2) t->size -= 2; else t->size = 0; descend = 1; break; case MARKUP_SUP : if (have_whitespace) { // Insert a space before superscript text... insert_space(parent, t); have_whitespace = 0; } t->superscript = 1; if ((sizeval = t->size + SIZE_SUP) < 0) t->size = 0; else t->size = (unsigned)sizeval; descend = 1; break; case MARKUP_SUB : if (have_whitespace) { // Insert a space before subscript text... insert_space(parent, t); have_whitespace = 0; } t->subscript = 1; if ((sizeval = t->size + SIZE_SUB) < 0) t->size = 0; else t->size = (unsigned)sizeval; descend = 1; break; case MARKUP_KBD : t->style = STYLE_BOLD; case MARKUP_TT : case MARKUP_CODE : case MARKUP_SAMP : if (isspace(ch = getc(fp))) have_whitespace = 1; else ungetc(ch, fp); if (have_whitespace) { // Insert a space before monospaced text... insert_space(parent, t); have_whitespace = 0; } t->typeface = _htmlBodyFont >= TYPE_MONOSPACE ? TYPE_MONOSPACE : TYPE_COURIER; descend = 1; break; case MARKUP_STRONG : case MARKUP_B : t->style = (style_t)(t->style | STYLE_BOLD); descend = 1; break; case MARKUP_DD : t->indent ++; descend = 1; break; case MARKUP_VAR : t->style = (style_t)(t->style | STYLE_ITALIC); case MARKUP_DFN : t->typeface = _htmlBodyFont >= TYPE_MONOSPACE ? TYPE_SANS_SERIF : TYPE_HELVETICA; descend = 1; break; case MARKUP_CITE : case MARKUP_EM : case MARKUP_I : t->style = (style_t)(t->style | STYLE_ITALIC); descend = 1; break; case MARKUP_U : case MARKUP_INS : if (have_whitespace) { // Insert a space before underlined text... insert_space(parent, t); have_whitespace = 0; } t->underline = 1; descend = 1; break; case MARKUP_STRIKE : case MARKUP_S : case MARKUP_DEL : if (have_whitespace) { // Insert a space before struck-through text... insert_space(parent, t); have_whitespace = 0; } t->strikethrough = 1; descend = 1; break; case MARKUP_CENTER : t->halignment = ALIGN_CENTER; descend = 1; break; case MARKUP_A : if (have_whitespace) { // Insert a space before this link... insert_space(parent, t); have_whitespace = 0; } descend = 1; break; default : /* * All other markup types should be using ... */ get_alignment(t); descend = 1; break; } if (descend) { #ifdef DEBUG strlcat((char *)indent, " ", sizeof(indent)); #endif // DEBUG parent = t; prev = NULL; } } return (tree); } /* * 'write_file()' - Write a tree entry to a file... */ static int /* I - New column */ write_file(tree_t *t, /* I - Tree entry */ FILE *fp, /* I - File to write to */ int col) /* I - Current column */ { int i; /* Looping var */ uchar *ptr; /* Character pointer */ while (t != NULL) { if (t->markup == MARKUP_NONE) { if (t->preformatted) { for (ptr = t->data; *ptr != '\0'; ptr ++) fputs((char *)iso8859(*ptr), fp); if (t->data[strlen((char *)t->data) - 1] == '\n') col = 0; else col += strlen((char *)t->data); } else { if ((col + (int)strlen((char *)t->data)) > 72 && col > 0) { putc('\n', fp); col = 0; } for (ptr = t->data; *ptr != '\0'; ptr ++) fputs((char *)iso8859(*ptr), fp); col += strlen((char *)t->data); if (col > 72) { putc('\n', fp); col = 0; } } } else if (t->markup == MARKUP_COMMENT) fprintf(fp, "\n\n", t->data); else if (t->markup > 0) { switch (t->markup) { case MARKUP_AREA : case MARKUP_BR : case MARKUP_CENTER : case MARKUP_COMMENT : case MARKUP_DD : case MARKUP_DL : case MARKUP_DT : case MARKUP_H1 : case MARKUP_H2 : case MARKUP_H3 : case MARKUP_H4 : case MARKUP_H5 : case MARKUP_H6 : case MARKUP_HEAD : case MARKUP_HR : case MARKUP_LI : case MARKUP_MAP : case MARKUP_OL : case MARKUP_P : case MARKUP_PRE : case MARKUP_TABLE : case MARKUP_TITLE : case MARKUP_TR : case MARKUP_UL : case MARKUP_DIR : case MARKUP_MENU : if (col > 0) { putc('\n', fp); col = 0; } default : break; } col += fprintf(fp, "<%s", _htmlMarkups[t->markup]); for (i = 0; i < t->nvars; i ++) { if (col > 72 && !t->preformatted) { putc('\n', fp); col = 0; } if (col > 0) { putc(' ', fp); col ++; } if (t->vars[i].value == NULL) col += fprintf(fp, "%s", t->vars[i].name); else if (strchr((char *)t->vars[i].value, '\"') != NULL) col += fprintf(fp, "%s=\'%s\'", t->vars[i].name, t->vars[i].value); else col += fprintf(fp, "%s=\"%s\"", t->vars[i].name, t->vars[i].value); } putc('>', fp); col ++; if (col > 72 && !t->preformatted) { putc('\n', fp); col = 0; } if (t->child != NULL) { col = write_file(t->child, fp, col); if (col > 72 && !t->preformatted) { putc('\n', fp); col = 0; } col += fprintf(fp, "", _htmlMarkups[t->markup]); switch (t->markup) { case MARKUP_AREA : case MARKUP_BR : case MARKUP_CENTER : case MARKUP_COMMENT : case MARKUP_DD : case MARKUP_DL : case MARKUP_DT : case MARKUP_H1 : case MARKUP_H2 : case MARKUP_H3 : case MARKUP_H4 : case MARKUP_H5 : case MARKUP_H6 : case MARKUP_HEAD : case MARKUP_HR : case MARKUP_LI : case MARKUP_MAP : case MARKUP_OL : case MARKUP_P : case MARKUP_PRE : case MARKUP_TABLE : case MARKUP_TITLE : case MARKUP_TR : case MARKUP_UL : case MARKUP_DIR : case MARKUP_MENU : putc('\n', fp); col = 0; default : break; } } } t = t->next; } return (col); } /* * 'htmlWriteFile()' - Write an HTML markup tree to a file. */ int /* O - Write status: 0 = success, -1 = fail */ htmlWriteFile(tree_t *parent, /* I - Parent tree entry */ FILE *fp) /* I - File to write to */ { if (write_file(parent, fp, 0) < 0) return (-1); else return (0); } /* * 'htmlAddTree()' - Add a tree node to the parent. */ tree_t * /* O - New entry */ htmlAddTree(tree_t *parent, /* I - Parent entry */ markup_t markup, /* I - Markup code */ uchar *data) /* I - Data/text */ { tree_t *t; /* New tree entry */ if ((t = htmlNewTree(parent, markup, data)) == NULL) return (NULL); /* * Add the tree entry to the end of the chain of children... */ if (parent != NULL) { if (parent->last_child != NULL) { parent->last_child->next = t; t->prev = parent->last_child; } else parent->child = t; parent->last_child = t; } return (t); } /* * 'htmlDeleteTree()' - Free all memory associated with a tree... */ int /* O - 0 for success, -1 for failure */ htmlDeleteTree(tree_t *parent) /* I - Parent to delete */ { tree_t *next; /* Next tree entry */ if (parent == NULL) return (-1); while (parent != NULL) { next = parent->next; if (parent->child != NULL) if (htmlDeleteTree(parent->child)) return (-1); delete_node(parent); parent = next; } return (0); } /* * 'htmlInsertTree()' - Insert a tree node under the parent. */ tree_t * /* O - New entry */ htmlInsertTree(tree_t *parent,/* I - Parent entry */ markup_t markup, /* I - Markup code */ uchar *data) /* I - Data/text */ { tree_t *t; /* New tree entry */ if ((t = htmlNewTree(parent, markup, data)) == NULL) return (NULL); /* * Insert the tree entry at the beginning of the chain of children... */ if (parent != NULL) { if (parent->child != NULL) { parent->child->prev = t; t->next = parent->child; } else parent->last_child = t; parent->child = t; } return (t); } /* * 'htmlNewTree()' - Create a new tree node for the parent. */ tree_t * /* O - New entry */ htmlNewTree(tree_t *parent, /* I - Parent entry */ markup_t markup, /* I - Markup code */ uchar *data) /* I - Data/text */ { tree_t *t; /* New tree entry */ /* * Allocate a new tree entry - use calloc() to get zeroed data... */ t = (tree_t *)calloc(sizeof(tree_t), 1); if (t == NULL) return (NULL); /* * Set the markup code and copy the data if necessary... */ t->markup = markup; if (data != NULL) t->data = (uchar *)strdup((char *)data); /* * Set/copy font characteristics... */ if (parent == NULL) { t->halignment = ALIGN_LEFT; t->valignment = ALIGN_BOTTOM; t->typeface = _htmlBodyFont; t->size = SIZE_P; compute_color(t, _htmlTextColor); } else { t->link = parent->link; t->halignment = parent->halignment; t->valignment = parent->valignment; t->typeface = parent->typeface; t->size = parent->size; t->style = parent->style; t->preformatted = parent->preformatted; t->indent = parent->indent; t->red = parent->red; t->green = parent->green; t->blue = parent->blue; t->underline = parent->underline; t->strikethrough = parent->strikethrough; } switch (t->markup) { case MARKUP_NONE : case MARKUP_IMG : /* * Figure out the width & height of this fragment... */ compute_size(t); break; case MARKUP_H1 : case MARKUP_H2 : case MARKUP_H3 : case MARKUP_H4 : case MARKUP_H5 : case MARKUP_H6 : get_alignment(t); t->typeface = _htmlHeadingFont; t->size = (unsigned)(SIZE_H1 - t->markup + MARKUP_H1); t->subscript = 0; t->superscript = 0; t->strikethrough = 0; t->preformatted = 0; t->style = STYLE_BOLD; break; case MARKUP_P : get_alignment(t); t->typeface = _htmlBodyFont; t->size = SIZE_P; t->style = STYLE_NORMAL; t->subscript = 0; t->superscript = 0; t->strikethrough = 0; t->preformatted = 0; break; case MARKUP_PRE : t->typeface = _htmlBodyFont >= TYPE_MONOSPACE ? TYPE_MONOSPACE : TYPE_COURIER; t->size = SIZE_PRE; t->style = STYLE_NORMAL; t->subscript = 0; t->superscript = 0; t->strikethrough = 0; t->preformatted = 1; break; case MARKUP_DIV : get_alignment(t); break; case MARKUP_BLOCKQUOTE : t->style = STYLE_ITALIC; case MARKUP_UL : case MARKUP_DIR : case MARKUP_MENU : case MARKUP_OL : case MARKUP_DL : t->indent ++; break; case MARKUP_AREA : case MARKUP_BR : case MARKUP_COMMENT : case MARKUP_HR : case MARKUP_INPUT : case MARKUP_ISINDEX : case MARKUP_META : case MARKUP_WBR : break; case MARKUP_TH : t->style = STYLE_BOLD; case MARKUP_TD : get_alignment(t); break; case MARKUP_SUP : t->superscript = 1; t->size = SIZE_P + SIZE_SUP; break; case MARKUP_SUB : t->subscript = 1; t->size = SIZE_P + SIZE_SUB; break; case MARKUP_B : t->style = (style_t)(t->style | STYLE_BOLD); break; case MARKUP_DD : t->indent ++; break; case MARKUP_DT : case MARKUP_I : t->style = (style_t)(t->style | STYLE_ITALIC); break; case MARKUP_U : case MARKUP_INS : t->underline = 1; break; case MARKUP_STRIKE : case MARKUP_DEL : t->strikethrough = 1; break; default : break; } t->parent = parent; return (t); } /* * 'htmlGetText()' - Get all text from the given tree. */ uchar * /* O - String containing text nodes */ htmlGetText(tree_t *t) /* I - Tree to pick */ { uchar *s, // String *s2, // New string *tdata = NULL, // Temporary string data *talloc = NULL; // Allocated string data size_t slen, // Length of string tlen; // Length of node string // Loop through all of the nodes in the tree and collect text... slen = 0; s = NULL; while (t != NULL) { if (t->child) tdata = talloc = htmlGetText(t->child); else tdata = t->data; if (tdata != NULL) { // Add the text to this string... tlen = strlen((char *)tdata); if (s) s2 = (uchar *)realloc(s, 1 + slen + tlen); else s2 = (uchar *)malloc(1 + tlen); if (!s2) break; s = s2; memcpy((char *)s + slen, (char *)tdata, tlen); slen += tlen; if (talloc) { free(talloc); talloc = NULL; } } t = t->next; } if (slen) s[slen] = '\0'; if (talloc) free(talloc); return (s); } /* * 'htmlGetMeta()' - Get document "meta" data... */ uchar * /* O - Content string */ htmlGetMeta(tree_t *tree, /* I - Document tree */ uchar *name) /* I - Metadata name */ { uchar *tname, /* Name value from tree entry */ *tcontent; /* Content value from tree entry */ while (tree != NULL) { /* * Check this tree entry... */ if (tree->markup == MARKUP_META && (tname = htmlGetVariable(tree, (uchar *)"NAME")) != NULL && (tcontent = htmlGetVariable(tree, (uchar *)"CONTENT")) != NULL) { if (strcasecmp((char *)name, (char *)tname) == 0) return (tcontent); } else if (tree->markup == MARKUP_HTML && !strcasecmp((char *)name, "LANG") && (tcontent = htmlGetVariable(tree, (uchar *)"LANG")) != NULL) { return (tcontent); } /* * Check child entries... */ if (tree->child != NULL) if ((tcontent = htmlGetMeta(tree->child, name)) != NULL) return (tcontent); /* * Next tree entry... */ tree = tree->next; } return (NULL); } /* * 'htmlGetStyle()' - Get a style value from a node's STYLE attribute. */ uchar * // O - Value or NULL htmlGetStyle(tree_t *t, // I - Node uchar *name) // I - Name (including ":") { uchar *ptr, // Pointer in STYLE attribute *bufptr; // Pointer in buffer size_t ptrlen, // Length of STYLE attribute namelen; // Length of name static uchar buffer[1024]; // Buffer for value // See if we have a STYLE attribute... if ((ptr = htmlGetVariable(t, (uchar *)"STYLE")) == NULL) return (NULL); // Loop through the STYLE attribute looking for the name... for (namelen = strlen((char *)name), ptrlen = strlen((char *)ptr); ptrlen > namelen; ptr ++, ptrlen --) if (strncasecmp((char *)name, (char *)ptr, namelen) == 0) { for (ptr += namelen; isspace(*ptr); ptr ++); for (bufptr = buffer; *ptr && *ptr != ';' && bufptr < (buffer + sizeof(buffer) - 1); *bufptr++ = *ptr++); *bufptr = '\0'; return (buffer); } return (NULL); } /* * 'htmlGetVariable()' - Get a variable value from a markup entry. */ uchar * /* O - Value or NULL if variable does not exist */ htmlGetVariable(tree_t *t, /* I - Tree entry */ uchar *name) /* I - Variable name */ { var_t *v, /* Matching variable */ key; /* Search key */ if (t == NULL || name == NULL || t->nvars == 0) return (NULL); key.name = name; v = (var_t *)bsearch(&key, t->vars, (size_t)t->nvars, sizeof(var_t), (compare_func_t)compare_variables); if (v == NULL) return (NULL); else if (v->value == NULL) return ((uchar *)""); else return (v->value); } /* * 'htmlLoadFontWidths()' - Load all of the font width files. */ void htmlLoadFontWidths(int typeface, int style) { char filename[1024]; /* Filenames */ FILE *fp; /* Files */ int ch; /* Character */ float width; /* Width value */ char glyph[64]; /* Glyph name */ char line[1024]; /* Line from AFM file */ /* * Now read all of the font widths... */ for (ch = 0; ch < 256; ch ++) _htmlWidths[typeface][style][ch] = 600; if (_htmlUTF8) { for (ch = 0; ch < 65536; ch ++) _htmlWidthsAll[typeface][style][ch] = 600; } snprintf(filename, sizeof(filename), "%s/fonts/%s.afm", _htmlData, _htmlFonts[typeface][style]); if ((fp = fopen(filename, "r")) == NULL) { #ifndef DEBUG progress_error(HD_ERROR_FILE_NOT_FOUND, "Unable to open font width file %s!", filename); #endif /* !DEBUG */ return; } while (fgets(line, sizeof(line), fp) != NULL) { if (strncmp(line, "C ", 2) != 0) continue; if (typeface < TYPE_SYMBOL) { /* * Handle encoding of regular fonts using assigned charset... */ if (sscanf(line, "%*s%*s%*s%*s%f%*s%*s%63s", &width, glyph) != 2) continue; for (ch = 0; ch < 256; ch ++) { if (_htmlGlyphs[ch] && !strcmp(_htmlGlyphs[ch], glyph)) { _htmlWidths[typeface][style][ch] = (short)width; break; } } if (_htmlUTF8) { for (ch = 0; ch < 65536; ch ++) { if (_htmlGlyphsAll[ch] && !strcmp(_htmlGlyphsAll[ch], glyph)) { _htmlWidthsAll[typeface][style][ch] = (short)width; break; } } } } else { /* * Symbol and Dingbats fonts uses their own encoding... */ if (sscanf(line, "%*s%d%*s%*s%f", &ch, &width) != 2) continue; if (ch < 256 && ch >= 0) { _htmlWidths[typeface][style][ch] = (short)width; _htmlWidthsAll[typeface][style][ch] = (short)width; } } } fclose(fp); // Make sure that non-breaking space has the same width as a breaking space... _htmlWidths[typeface][style][160] = _htmlWidths[typeface][style][32]; _htmlWidthsAll[typeface][style][160] = _htmlWidthsAll[typeface][style][32]; _htmlWidthsLoaded[typeface][style] = 1; } /* * 'htmlSetVariable()' - Set a variable for a markup entry. */ int /* O - Set status: 0 = success, -1 = fail */ htmlSetVariable(tree_t *t, /* I - Tree entry */ uchar *name, /* I - Variable name */ uchar *value) /* I - Variable value */ { var_t *v, /* Matching variable */ key; /* Search key */ DEBUG_printf(("%shtmlSetVariable(%p, \"%s\", \"%s\")\n", indent, (void *)t, name, value ? (const char *)value : "(null)")); if (t->nvars == 0) v = NULL; else { key.name = name; v = (var_t *)bsearch(&key, t->vars, (size_t)t->nvars, sizeof(var_t), (compare_func_t)compare_variables); } if (v == NULL) { if (t->nvars == 0) v = (var_t *)malloc(sizeof(var_t)); else v = (var_t *)realloc(t->vars, sizeof(var_t) * (size_t)(t->nvars + 1)); if (v == NULL) { DEBUG_printf(("%s==== MALLOC/REALLOC FAILED! ====\n", indent)); return (-1); } t->vars = v; v += t->nvars; t->nvars ++; v->name = (uchar *)strdup((char *)name); if (value != NULL) v->value = (uchar *)strdup((char *)value); else v->value = NULL; if (strcasecmp((char *)name, "HREF") == 0) { DEBUG_printf(("%s---- Set link to %s ----\n", indent, value)); t->link = t; } if (t->nvars > 1) qsort(t->vars, (size_t)t->nvars, sizeof(var_t), (compare_func_t)compare_variables); } else if (v->value != value) { if (v->value != NULL) free(v->value); if (value != NULL) v->value = (uchar *)strdup((char *)value); else v->value = NULL; } return (0); } /* * 'htmlSetBaseSize()' - Set the font sizes and spacings... */ void htmlSetBaseSize(double p, /* I - Point size of paragraph font */ double s) /* I - Spacing */ { int i; /* Looping var */ p /= 1.2 * 1.2 * 1.2; for (i = 0; i < 8; i ++, p *= 1.2) { _htmlSizes[i] = p; _htmlSpacings[i] = p * s; } } /* * 'htmlSetCharSet()' - Set the character set for output. */ void htmlSetCharSet(const char *cs) /* I - Character set file to load */ { int i; /* Looping var */ char filename[1024]; /* Filenames */ FILE *fp; /* Files */ int ch, unicode; /* Character values */ char glyph[64]; /* Glyph name */ char line[1024]; /* Line from charset file */ int chars[256]; /* Character encoding array */ strlcpy(_htmlCharSet, cs, sizeof(_htmlCharSet)); if (!_htmlInitialized) { /* * Load the PostScript glyph names for all of Unicode... */ memset(_htmlGlyphsAll, 0, sizeof(_htmlGlyphsAll)); snprintf(line, sizeof(line), "%s/data/psglyphs", _htmlData); if ((fp = fopen(line, "r")) != NULL) { while (fscanf(fp, "%x%63s", &unicode, glyph) == 2) _htmlGlyphsAll[unicode] = strdup(glyph); fclose(fp); _htmlInitialized = 1; } #ifndef DEBUG else progress_error(HD_ERROR_FILE_NOT_FOUND, "Unable to open psglyphs data file!"); #endif /* !DEBUG */ } memset(_htmlGlyphs, 0, sizeof(_htmlGlyphs)); if (!strcmp(cs, "utf-8")) { // Generate a dynamic mapping of Unicode to an 8-bit charset with the // bottom 128 characters matching US ASCII... _htmlUTF8 = 0x80; for (i = 0; i < 128; i ++) { /* * Add the glyph to the charset array... */ _htmlGlyphs[i] = _htmlGlyphsAll[i]; _htmlUnicode[i] = i; } memset(_htmlWidthsLoaded, 0, sizeof(_htmlWidthsLoaded)); return; } if (strncmp(cs, "8859-", 5) == 0) snprintf(filename, sizeof(filename), "%s/data/iso-%s", _htmlData, cs); else snprintf(filename, sizeof(filename), "%s/data/%s", _htmlData, cs); if ((fp = fopen(filename, "r")) == NULL) { /* * Can't open charset file; use ISO-8859-1... */ #ifndef DEBUG progress_error(HD_ERROR_FILE_NOT_FOUND, "Unable to open character set file %s!", cs); #endif /* !DEBUG */ for (i = 0; i < 256; i ++) chars[i] = i; } else { /* * Read the lines from the file... */ memset(chars, 0, sizeof(chars)); while (fscanf(fp, "%x%x", &ch, &unicode) == 2) chars[ch] = unicode; fclose(fp); } /* * Build the glyph array... */ for (i = 0; i < 256; i ++) { /* * Add the glyph to the charset array... */ if (chars[i] == 0) { _htmlGlyphs[i] = NULL; continue; } else _htmlGlyphs[i] = _htmlGlyphsAll[chars[i]]; if (_htmlGlyphs[i]) _htmlUnicode[i] = chars[i]; } memset(_htmlWidthsLoaded, 0, sizeof(_htmlWidthsLoaded)); } /* * 'htmlSetTextColor()' - Set the default text color. */ void htmlSetTextColor(uchar *color) /* I - Text color */ { strlcpy((char *)_htmlTextColor, (char *)color, sizeof(_htmlTextColor)); } /* * 'compare_variables()' - Compare two markup variables. */ static int /* O - -1 if v0 < v1, 0 if v0 == v1, 1 if v0 > v1 */ compare_variables(var_t *v0, /* I - First variable */ var_t *v1) /* I - Second variable */ { return (strcasecmp((char *)v0->name, (char *)v1->name)); } /* * 'compare_markups()' - Compare two markup strings... */ static int /* O - -1 if m0 < m1, 0 if m0 == m1, 1 if m0 > m1 */ compare_markups(uchar **m0, /* I - First markup */ uchar **m1) /* I - Second markup */ { if (tolower((*m0)[0]) == 'h' && isdigit((*m0)[1]) && tolower((*m1)[0]) == 'h' && isdigit((*m1)[1])) return (atoi((char *)*m0 + 1) - atoi((char *)*m1 + 1)); else return (strcasecmp((char *)*m0, (char *)*m1)); } /* * 'delete_node()' - Free all memory associated with a node... */ static void delete_node(tree_t *t) /* I - Node to delete */ { int i; /* Looping var */ var_t *var; /* Current variable */ if (t == NULL) return; if (t->data != NULL) free(t->data); for (i = t->nvars, var = t->vars; i > 0; i --, var ++) { free(var->name); if (var->value != NULL) free(var->value); } if (t->vars != NULL) free(t->vars); free(t); } // // 'insert_space()' - Insert a whitespace character before the // specified node. // static void insert_space(tree_t *parent, // I - Parent node tree_t *t) // I - Node to insert before { tree_t *space; // Space node // Allocate memory for the whitespace... space = (tree_t *)calloc(sizeof(tree_t), 1); if (space == NULL) { #ifndef DEBUG progress_error(HD_ERROR_OUT_OF_MEMORY, "Unable to allocate memory for HTML tree node!"); #endif /* !DEBUG */ return; } // Set/copy font characteristics... if (parent) { space->typeface = parent->typeface; space->size = parent->size; space->style = parent->style; } else { space->typeface = _htmlBodyFont; space->size = SIZE_P; } // Initialize element data... space->markup = MARKUP_NONE; space->data = (uchar *)strdup(" "); // Set tree pointers... space->parent = parent; space->prev = t->prev; space->next = t; if (space->prev) space->prev->next = space; else if (parent) parent->child = space; t->prev = space; compute_size(space); } /* * 'parse_markup()' - Parse a markup string. */ static int /* O - -1 on error, MARKUP_nnnn otherwise */ parse_markup(tree_t *t, /* I - Current tree entry */ FILE *fp, /* I - Input file */ int *linenum) /* O - Current line number */ { int ch, ch2; /* Characters from file */ uchar markup[255], /* Markup string... */ *mptr, /* Current character... */ comment[10240], /* Comment string */ *cptr, /* Current char... */ **temp; /* Markup variable entry */ mptr = markup; while ((ch = getc(fp)) != EOF && mptr < (markup + sizeof(markup) - 1)) if (ch == '>' || isspace(ch)) break; else if (ch == '/' && mptr > markup) { // Look for "/>"... ch = getc(fp); if (ch != '>') return (MARKUP_ERROR); break; } else { if ((ch & 0x80) && _htmlUTF8) { // Collect UTF-8 value... ch = utf8_getc(ch, fp); } if (ch) *mptr++ = (uchar)ch; // Handle comments without whitespace... if ((mptr - markup) == 3 && strncmp((const char *)markup, "!--", 3) == 0) { ch = getc(fp); break; } } *mptr = '\0'; if (ch == EOF) return (MARKUP_ERROR); mptr = markup; temp = (uchar **)bsearch(&mptr, _htmlMarkups, sizeof(_htmlMarkups) / sizeof(_htmlMarkups[0]), sizeof(_htmlMarkups[0]), (compare_func_t)compare_markups); if (temp == NULL) { /* * Unrecognized markup stuff... */ t->markup = MARKUP_UNKNOWN; strlcpy((char *)comment, (char *)markup, sizeof(comment)); cptr = comment + strlen((char *)comment); DEBUG_printf(("%s%s (unrecognized!)\n", indent, markup)); } else { t->markup = (markup_t)((const char **)temp - _htmlMarkups); cptr = comment; DEBUG_printf(("%s%s, line %d\n", indent, markup, *linenum)); } if (t->markup == MARKUP_COMMENT || t->markup == MARKUP_UNKNOWN) { int lastch = ch; // Last character seen while (ch != EOF && cptr < (comment + sizeof(comment) - 2)) { if (ch == '>' && temp == NULL) break; if (ch == '\n') (*linenum) ++; if (ch == '-' && lastch == '-') { *cptr++ = (uchar)ch; if ((ch2 = getc(fp)) == '>') { // Erase trailing --> cptr -= 2; if (cptr < comment) cptr = comment; // Issue #316: buffer underflow break; } else ch = ch2; } else { if (ch == '&') { // Handle character entities... uchar entity[16], // Character entity name *eptr; // Pointer into name eptr = entity; while (eptr < (entity + sizeof(entity) - 1) && (ch = getc(fp)) != EOF) if (!isalnum(ch) && ch != '#') break; else *eptr++ = (uchar)ch; if (ch != ';') { ungetc(ch, fp); ch = 0; } *eptr = '\0'; if (!ch) { progress_error(HD_ERROR_HTML_ERROR, "Unquoted & on line %d of %s.", *linenum, _htmlCurrentFile); if (cptr < (comment + sizeof(comment) - 1)) *cptr++ = '&'; strlcpy((char *)cptr, (char *)entity, sizeof(comment) - (size_t)(cptr - comment)); cptr += strlen((char *)cptr); } else if ((ch = iso8859(entity)) == 0) { progress_error(HD_ERROR_HTML_ERROR, "Unknown character entity \"&%s;\" on line %d of %s.", entity, *linenum, _htmlCurrentFile); if (cptr < (comment + sizeof(comment) - 1)) *cptr++ = '&'; strlcpy((char *)cptr, (char *)entity, sizeof(comment) - (size_t)(cptr - comment)); cptr += strlen((char *)cptr); if (cptr < (comment + sizeof(comment) - 1)) *cptr++ = ';'; } else *cptr++ = (uchar)ch; } else { if ((ch & 0x80) && _htmlUTF8) { // Collect UTF-8 value... ch = utf8_getc(ch, fp); } if (ch) *cptr++ = (uchar)ch; } lastch = ch; ch = getc(fp); } } *cptr = '\0'; t->data = (uchar *)strdup((char *)comment); } else { while (ch != EOF && ch != '>') { if (ch == '\n') (*linenum) ++; if (!isspace(ch)) { ungetc(ch, fp); parse_variable(t, fp, linenum); } ch = getc(fp); if (ch == '/') { // Look for "/>"... ch = getc(fp); if (ch != '>') return (MARKUP_ERROR); break; } } } return (t->markup); } /* * 'parse_variable()' - Parse a markup variable string. */ static int // O - -1 on error, 0 on success parse_variable(tree_t *t, // I - Current tree entry FILE *fp, // I - Input file int *linenum) // I - Current line number { uchar name[1024], // Name of variable value[10240], // Value of variable *ptr, // Temporary pointer entity[16], // Character entity name *eptr; // Pointer into name int ch; // Character from file ptr = name; while ((ch = getc(fp)) != EOF) if (isspace(ch) || ch == '=' || ch == '>' || ch == '\r') break; else if (ch == '/' && ptr == name) break; else if (ptr < (name + sizeof(name) - 1)) { if ((ch & 0x80) && _htmlUTF8) { // Collect UTF-8 value... ch = utf8_getc(ch, fp); } if (ch) *ptr++ = (uchar)ch; } *ptr = '\0'; if (ch == '\n') (*linenum) ++; while (isspace(ch) || ch == '\r') { ch = getc(fp); if (ch == '\n') (*linenum) ++; } switch (ch) { default : ungetc(ch, fp); return (htmlSetVariable(t, name, NULL)); case EOF : return (-1); case '=' : ptr = value; ch = getc(fp); while (isspace(ch) || ch == '\r') ch = getc(fp); if (ch == EOF) return (-1); if (ch == '\'') { while ((ch = getc(fp)) != EOF) { if (ch == '\'') break; else if (ch == '&') { // Possibly a character entity... eptr = entity; while (eptr < (entity + sizeof(entity) - 1) && (ch = getc(fp)) != EOF) if (!isalnum(ch) && ch != '#') break; else *eptr++ = (uchar)ch; if (ch != ';') { ungetc(ch, fp); ch = 0; } *eptr = '\0'; if (!ch) { progress_error(HD_ERROR_HTML_ERROR, "Unquoted & on line %d of %s.", *linenum, _htmlCurrentFile); if (ptr < (value + sizeof(value) - 1)) *ptr++ = '&'; strlcpy((char *)ptr, (char *)entity, sizeof(value) - (size_t)(ptr - value)); ptr += strlen((char *)ptr); } else if ((ch = iso8859(entity)) == 0) { progress_error(HD_ERROR_HTML_ERROR, "Unknown character entity \"&%s;\" on line %d of %s.", entity, *linenum, _htmlCurrentFile); if (ptr < (value + sizeof(value) - 1)) *ptr++ = '&'; strlcpy((char *)ptr, (char *)entity, sizeof(value) - (size_t)(ptr - value)); ptr += strlen((char *)ptr); if (ptr < (value + sizeof(value) - 1)) *ptr++ = ';'; } else if (ptr < (value + sizeof(value) - 1)) *ptr++ = (uchar)ch; } else if (ptr < (value + sizeof(value) - 1) && ch != '\n' && ch != '\r') { if ((ch & 0x80) && _htmlUTF8) { // Collect UTF-8 value... ch = utf8_getc(ch, fp); } if (ch) *ptr++ = (uchar)ch; } else if (ch == '\n') { if (ptr < (value + sizeof(value) - 1)) *ptr++ = ' '; (*linenum) ++; } } *ptr = '\0'; } else if (ch == '\"') { while ((ch = getc(fp)) != EOF) { if (ch == '\"') break; else if (ch == '&') { // Possibly a character entity... eptr = entity; while (eptr < (entity + sizeof(entity) - 1) && (ch = getc(fp)) != EOF) if (!isalnum(ch) && ch != '#') break; else *eptr++ = (uchar)ch; if (ch != ';') { ungetc(ch, fp); ch = 0; } *eptr = '\0'; if (!ch) { progress_error(HD_ERROR_HTML_ERROR, "Unquoted & on line %d of %s.", *linenum, _htmlCurrentFile); if (ptr < (value + sizeof(value) - 1)) *ptr++ = '&'; strlcpy((char *)ptr, (char *)entity, sizeof(value) - (size_t)(ptr - value)); ptr += strlen((char *)ptr); } else if ((ch = iso8859(entity)) == 0) { progress_error(HD_ERROR_HTML_ERROR, "Unknown character entity \"&%s;\" on line %d of %s.", entity, *linenum, _htmlCurrentFile); if (ptr < (value + sizeof(value) - 1)) *ptr++ = '&'; strlcpy((char *)ptr, (char *)entity, sizeof(value) - (size_t)(ptr - value)); ptr += strlen((char *)ptr); if (ptr < (value + sizeof(value) - 1)) *ptr++ = ';'; } else if (ptr < (value + sizeof(value) - 1)) *ptr++ = (uchar)ch; } else if (ptr < (value + sizeof(value) - 1) && ch != '\n' && ch != '\r') { if ((ch & 0x80) && _htmlUTF8) { // Collect UTF-8 value... ch = utf8_getc(ch, fp); } if (ch) *ptr++ = (uchar)ch; } else if (ch == '\n') { if (ptr < (value + sizeof(value) - 1)) *ptr++ = ' '; (*linenum) ++; } } *ptr = '\0'; } else { *ptr++ = (uchar)ch; while ((ch = getc(fp)) != EOF) { if (isspace(ch) || ch == '>' || ch == '\r') break; else if (ch == '&') { // Possibly a character entity... eptr = entity; while (eptr < (entity + sizeof(entity) - 1) && (ch = getc(fp)) != EOF) if (!isalnum(ch) && ch != '#') break; else *eptr++ = (uchar)ch; if (ch != ';') { ungetc(ch, fp); ch = 0; } *eptr = '\0'; if (!ch) { progress_error(HD_ERROR_HTML_ERROR, "Unquoted & on line %d of %s.", *linenum, _htmlCurrentFile); if (ptr < (value + sizeof(value) - 1)) *ptr++ = '&'; strlcpy((char *)ptr, (char *)entity, sizeof(value) - (size_t)(ptr - value)); ptr += strlen((char *)ptr); } else if ((ch = iso8859(entity)) == 0) { progress_error(HD_ERROR_HTML_ERROR, "Unknown character entity \"&%s;\" on line %d of %s.", entity, *linenum, _htmlCurrentFile); if (ptr < (value + sizeof(value) - 1)) *ptr++ = '&'; strlcpy((char *)ptr, (char *)entity, sizeof(value) - (size_t)(ptr - value)); ptr += strlen((char *)ptr); if (ptr < (value + sizeof(value) - 1)) *ptr++ = ';'; } else if (ptr < (value + sizeof(value) - 1)) *ptr++ = (uchar)ch; } else if (ptr < (value + sizeof(value) - 1)) { if ((ch & 0x80) && _htmlUTF8) { // Collect UTF-8 value... ch = utf8_getc(ch, fp); } if (ch) *ptr++ = (uchar)ch; } } if (ch == '\n') (*linenum) ++; *ptr = '\0'; if (ch == '>') ungetc(ch, fp); } return (htmlSetVariable(t, name, value)); } } /* * 'compute_size()' - Compute the width and height of a tree entry. */ static int /* O - 0 = success, -1 = failure */ compute_size(tree_t *t) /* I - Tree entry */ { uchar *ptr; /* Current character */ float width; /* Current width */ int int_width; /* Integer width */ uchar *width_ptr, /* Pointer to width string */ *height_ptr, /* Pointer to height string */ *size_ptr, /* Pointer to size string */ *type_ptr; /* Pointer to spacer type string */ image_t *img; /* Image */ char number[255]; /* Width or height value */ if (!_htmlInitialized) htmlSetCharSet("iso-8859-1"); if (t->markup == MARKUP_IMG) { width_ptr = htmlGetVariable(t, (uchar *)"WIDTH"); height_ptr = htmlGetVariable(t, (uchar *)"HEIGHT"); img = image_load((char *)htmlGetVariable(t, (uchar *)"REALSRC"), _htmlGrayscale); if (width_ptr != NULL && height_ptr != NULL) { t->width = (float)(atoi((char *)width_ptr) / _htmlPPI * 72.0f); t->height = (float)(atoi((char *)height_ptr) / _htmlPPI * 72.0f); return (0); } if (img == NULL) return (-1); if (width_ptr != NULL) { t->width = (float)(atoi((char *)width_ptr) / _htmlPPI * 72.0f); t->height = (float)(t->width * img->height / img->width); snprintf(number, sizeof(number), "%d", atoi((char *)width_ptr) * img->height / img->width); if (strchr((char *)width_ptr, '%') != NULL) strlcat(number, "%", sizeof(number)); htmlSetVariable(t, (uchar *)"HEIGHT", (uchar *)number); } else if (height_ptr != NULL) { t->height = (float)(atoi((char *)height_ptr) / _htmlPPI * 72.0f); t->width = (float)(t->height * img->width / img->height); snprintf(number, sizeof(number), "%d", atoi((char *)height_ptr) * img->width / img->height); if (strchr((char *)height_ptr, '%') != NULL) strlcat(number, "%", sizeof(number)); htmlSetVariable(t, (uchar *)"WIDTH", (uchar *)number); } else { t->width = (float)(img->width / _htmlPPI * 72.0f); t->height = (float)(img->height / _htmlPPI * 72.0f); snprintf(number, sizeof(number), "%d", img->width); htmlSetVariable(t, (uchar *)"WIDTH", (uchar *)number); snprintf(number, sizeof(number), "%d", img->height); htmlSetVariable(t, (uchar *)"HEIGHT", (uchar *)number); } return (0); } else if (t->markup == MARKUP_SPACER) { width_ptr = htmlGetVariable(t, (uchar *)"WIDTH"); height_ptr = htmlGetVariable(t, (uchar *)"HEIGHT"); size_ptr = htmlGetVariable(t, (uchar *)"SIZE"); type_ptr = htmlGetVariable(t, (uchar *)"TYPE"); if (width_ptr != NULL) t->width = (float)(atoi((char *)width_ptr) / _htmlPPI * 72.0f); else if (size_ptr != NULL) t->width = (float)(atoi((char *)size_ptr) / _htmlPPI * 72.0f); else t->width = 1.0f; if (height_ptr != NULL) t->height = (float)(atoi((char *)height_ptr) / _htmlPPI * 72.0f); else if (size_ptr != NULL) t->height = (float)(atoi((char *)size_ptr) / _htmlPPI * 72.0f); else t->height = 1.0f; if (type_ptr == NULL) return (0); if (strcasecmp((char *)type_ptr, "horizontal") == 0) t->height = 0.0; else if (strcasecmp((char *)type_ptr, "vertical") == 0) t->width = 0.0; return (0); } else if (t->markup == MARKUP_BR) { t->width = 0.0; t->height = (float)_htmlSizes[t->size]; return (0); } else if (t->preformatted && t->data) { int max_width = 0; /* Maximum width */ for (int_width = 0, ptr = t->data; *ptr != '\0'; ptr ++) { if (*ptr == '\n') { if (int_width > max_width) max_width = int_width; int_width = 0; } else if (*ptr == '\t') int_width = (int_width + 7) & ~7; else int_width ++; } if (int_width > max_width) max_width = int_width; if (!_htmlWidthsLoaded[t->typeface][t->style]) htmlLoadFontWidths(t->typeface, t->style); width = _htmlWidths[t->typeface][t->style][0x20] * max_width * 0.001f; } else if (t->data) { if (!_htmlWidthsLoaded[t->typeface][t->style]) htmlLoadFontWidths(t->typeface, t->style); for (int_width = 0, ptr = t->data; *ptr != '\0'; ptr ++) int_width += _htmlWidths[t->typeface][t->style][(int)*ptr & 255]; width = 0.001f * int_width; } else width = 0.0f; t->width = (float)(width * _htmlSizes[t->size]); t->height = (float)_htmlSizes[t->size]; DEBUG_printf(("%swidth = %.1f, height = %.1f\n", indent, t->width, t->height)); return (0); } /* * 'compute_color()' - Compute the red, green, blue color from the given * string. */ static int compute_color(tree_t *t, /* I - Tree entry */ uchar *color) /* I - Color string */ { float rgb[3]; /* RGB color */ get_color(color, rgb); t->red = (uchar)(rgb[0] * 255.0f + 0.5f); t->green = (uchar)(rgb[1] * 255.0f + 0.5f); t->blue = (uchar)(rgb[2] * 255.0f + 0.5f); return (0); } /* * 'get_alignment()' - Get horizontal & vertical alignment values. */ static int /* O - 0 for success, -1 for failure */ get_alignment(tree_t *t) /* I - Tree entry */ { uchar *align; /* Alignment string */ if ((align = htmlGetVariable(t, (uchar *)"ALIGN")) == NULL) align = htmlGetStyle(t, (uchar *)"text-align"); if (align != NULL) { if (!strcasecmp((char *)align, "left")) t->halignment = ALIGN_LEFT; else if (!strcasecmp((char *)align, "center")) t->halignment = ALIGN_CENTER; else if (!strcasecmp((char *)align, "right")) t->halignment = ALIGN_RIGHT; else if (!strcasecmp((char *)align, "justify")) t->halignment = ALIGN_JUSTIFY; else if (!strcasecmp((char *)align, "top")) t->valignment = ALIGN_TOP; else if (!strcasecmp((char *)align, "middle") || !strcasecmp((char *)align, "absmiddle")) t->valignment = ALIGN_MIDDLE; else if (!strcasecmp((char *)align, "bottom")) t->valignment = ALIGN_BOTTOM; } if ((align = htmlGetVariable(t, (uchar *)"VALIGN")) == NULL) align = htmlGetStyle(t, (uchar *)"vertical-align"); if (align != NULL) { if (!strcasecmp((char *)align, "top")) t->valignment = ALIGN_TOP; else if (!strcasecmp((char *)align, "middle")) t->valignment = ALIGN_MIDDLE; else if (!strcasecmp((char *)align, "center")) t->valignment = ALIGN_MIDDLE; else if (!strcasecmp((char *)align, "bottom")) t->valignment = ALIGN_BOTTOM; } return (0); } /* * 'fix_filename()' - Fix a filename to be relative to the base directory. */ static const char * /* O - Fixed filename */ fix_filename(char *filename, /* I - Original filename */ char *base) /* I - Base directory */ { char *slash; /* Location of slash */ char temp[1024], /* Temporary filename */ *tempptr; /* Pointer into filename */ static char newfilename[1024]; /* New filename */ // printf("fix_filename(filename=\"%s\", base=\"%s\")\n", filename, base); if (filename == NULL) return (NULL); #ifdef DEBUG // to silence Clang static analyzer, totally unnecessary memset(temp, 0, sizeof(temp)); #endif // DEBUG // Unescape filenames as needed... if (strchr(filename, '%') && !strstr(filename, "//")) { for (tempptr = temp; *filename && tempptr < (temp + sizeof(temp) - 1);) { if (*filename == '%') { // Decode hex-escaped filename character... filename ++; if (isxdigit(filename[0] & 255) && isxdigit(filename[1] & 255)) { if (isdigit(filename[0] & 255)) *tempptr = (char)((filename[0] - '0') << 4); else *tempptr = (char)((tolower(filename[0]) - 'a' + 10) << 4); if (isdigit(filename[1] & 255)) *tempptr |= filename[1] - '0'; else *tempptr |= tolower(filename[0]) - 'a' + 10; tempptr ++; filename += 2; } else *tempptr++ = '%'; } else *tempptr++ = *filename++; } *tempptr = '\0'; filename = temp; } if (strcmp(base, ".") == 0 || strstr(filename, "//") != NULL) return (file_find(Path, filename)); if (strncmp(filename, "./", 2) == 0 || strncmp(filename, ".\\", 2) == 0) filename += 2; if (strncmp(base, "http://", 7) == 0 || strncmp(base, "https://", 8) == 0) { strlcpy(newfilename, base, sizeof(newfilename)); base = strchr(newfilename, ':') + 3; if (filename[0] == '/') { if ((slash = strchr(base, '/')) != NULL) strlcpy(slash, filename, sizeof(newfilename) - (size_t)(slash - newfilename)); else strlcat(newfilename, filename, sizeof(newfilename)); return (newfilename); } else if ((slash = strchr(base, '/')) == NULL) strlcat(newfilename, "/", sizeof(newfilename)); } else { if (filename[0] == '/' || filename[0] == '\\' || base == NULL || base[0] == '\0' || (isalpha(filename[0]) && filename[1] == ':')) return (file_find(Path, filename)); /* No change needed for absolute path */ strlcpy(newfilename, base, sizeof(newfilename)); base = newfilename; } #if defined(WIN32) || defined(__EMX__) while (strncmp(filename, "../", 3) == 0 || strncmp(filename, "..\\", 3) == 0) #else while (strncmp(filename, "../", 3) == 0) #endif // WIN32 || __EMX__ { filename += 3; #if defined(WIN32) || defined(__EMX__) if ((slash = strrchr(base, '/')) != NULL) *slash = '\0'; else if ((slash = strrchr(base, '\\')) != NULL) *slash = '\0'; #else if ((slash = strrchr(base, '/')) != NULL) *slash = '\0'; #endif // WIN32 || __EMX__ else { filename -= 3; break; } } if (filename[0] != '/' && *base && base[strlen(base) - 1] != '/') strlcat(newfilename, "/", sizeof(newfilename)); strlcat(newfilename, filename, sizeof(newfilename)); // printf(" newfilename=\"%s\"\n", newfilename); return (file_find(Path, newfilename)); } // // 'html_memory_used()' - Figure out the amount of memory that was used. // static int // O - Bytes used html_memory_used(tree_t *t) // I - Tree node { int i; // Looping var int bytes; // Bytes used if (t == NULL) return (0); bytes = 0; while (t != NULL) { bytes += sizeof(tree_t); bytes += (size_t)t->nvars * sizeof(var_t); for (i = 0; i < t->nvars; i ++) { bytes += (strlen((char *)t->vars[i].name) + 8) & (size_t)~7; if (t->vars[i].value != NULL) bytes += (strlen((char *)t->vars[i].value) + 8) & (size_t)~7; } if (t->data != NULL) bytes += (strlen((char *)t->data) + 8) & (size_t)~7; bytes += html_memory_used(t->child); t = t->next; } return (bytes); } // // 'htmlDebugStats()' - Display debug statistics for HTML tree memory use. // void htmlDebugStats(const char *title, // I - Title tree_t *t) // I - Document root node { const char *debug; /* HTMLDOC_DEBUG env var */ if ((debug = getenv("HTMLDOC_DEBUG")) == NULL || (strstr(debug, "all") == NULL && strstr(debug, "memory") == NULL)) return; progress_error(HD_ERROR_NONE, "DEBUG: %s = %d kbytes", title, (html_memory_used(t) + 1023) / 1024); } // // 'htmlFindFile()' - Find a file in the document. // tree_t * // O - Node for file htmlFindFile(tree_t *doc, // I - Document pointer uchar *filename) // I - Filename { tree_t *tree; // Current node uchar *treename; // Filename from node if (!filename || !doc) return (NULL); for (tree = doc; tree; tree = tree->next) if ((treename = htmlGetVariable(tree, (uchar *)"_HD_FILENAME")) != NULL && !strcmp((char *)treename, (char *)filename)) return (tree); return (NULL); } // // 'htmlFixLinks()' - Fix the external links in the document. // void htmlFixLinks(tree_t *doc, // I - Top node tree_t *tree, // I - Current node uchar *base) // I - Base directory/path { uchar *href; // HREF attribute char full_href[1024]; // Full HREF value const char *debug; // HTMLDOC_DEBUG environment variable static int show_debug = -1; // Show debug messages? if (show_debug < 0) { if ((debug = getenv("HTMLDOC_DEBUG")) == NULL || (strstr(debug, "all") == NULL && strstr(debug, "links") == NULL)) show_debug = 0; else show_debug = 1; if (show_debug) progress_error(HD_ERROR_NONE, "DEBUG: Updating links in document."); } while (tree) { if (tree->markup == MARKUP_A && base && base[0] && (href = htmlGetVariable(tree, (uchar *)"HREF")) != NULL) { // Check if the link needs to be localized... if (href[0] != '#' && file_method((char *)href) == NULL && file_method((char *)base) != NULL && htmlFindFile(doc, (uchar *)file_basename((char *)href)) == NULL) { // Yes, localize it... if (href[0] == '/') { // Absolute URL, just copy scheme, server, etc. char *ptr; // Pointer into URL... strlcpy(full_href, (char *)base, sizeof(full_href)); if (href[1] == '/') { // Just use scheme... if ((ptr = strstr(full_href, "//")) != NULL) *ptr ='\0'; } else if ((ptr = strstr(full_href, "//")) != NULL && (ptr = strchr(ptr + 2, '/')) != NULL) *ptr ='\0'; strlcat(full_href, (char *)href, sizeof(full_href)); } else if (!strncmp((char *)href, "./", 2)) { // Relative URL of the form "./foo/bar", append href sans // "./" to base to form full href... snprintf(full_href, sizeof(full_href), "%s/%s", base, href + 2); } else { // Relative URL, append href to base to form full href... snprintf(full_href, sizeof(full_href), "%s/%s", base, href); } if (show_debug) progress_error(HD_ERROR_NONE, "DEBUG: Mapping \"%s\" to \"%s\"...", href, full_href); htmlSetVariable(tree, (uchar *)"_HD_FULL_HREF", (uchar *)full_href); } else { // No, just mirror the link in the _HD_FULL_HREF attribute... htmlSetVariable(tree, (uchar *)"_HD_FULL_HREF", href); } } else if (tree->markup == MARKUP_FILE) base = htmlGetVariable(tree, (uchar *)"_HD_BASE"); if (tree->child) htmlFixLinks(doc, tree->child, base); tree = tree->next; } } // // 'utf8_getc()' - Get a UTF-8 encoded character. // static int // O - Unicode equivalent utf8_getc(int ch, // I - Initial character FILE *fp) // I - File to read from { int ch2 = -1, ch3 = -1; // Temporary characters int unicode; // Unicode character if ((ch & 0xe0) == 0xc0) { /* * Two-byte sequence for 0x80 to 0x7ff... */ ch = (ch & 0x1f) << 6; ch2 = getc(fp); if ((ch2 & 0xc0) == 0x80) ch |= ch2 & 0x3f; else goto bad_sequence; } else if ((ch & 0xf0) == 0xe0) { /* * Three-byte sequence from 0x800 to 0xffff... */ ch = (ch & 0x0f) << 12; ch2 = getc(fp); if ((ch2 & 0xc0) == 0x80) ch |= (ch2 & 0x3f) << 6; else goto bad_sequence; ch3 = getc(fp); if ((ch3 & 0xc0) == 0x80) ch |= ch3 & 0x3f; else goto bad_sequence; } else if (ch & 0x80) goto bad_sequence; if (ch == 0xfeff) { // BOMs are invalid in UTF-8 text, but Microsoft insists on still using // them... Try reading another character... // // TODO: Emit a warning about this... if ((ch = utf8_getc(getc(fp), fp)) == 0) return (0); } // If we already have a mapping for this character, return it... if (_htmlCharacters[ch]) return (_htmlCharacters[ch]); if (_htmlUTF8 >= 0x100) { progress_error(HD_ERROR_READ_ERROR, "Too many Unicode code points."); return (0); } unicode = _htmlUTF8++; _htmlCharacters[ch] = (uchar)unicode; _htmlUnicode[unicode] = ch; _htmlGlyphs[unicode] = _htmlGlyphsAll[ch]; for (int i = 0; i < TYPE_MAX; i ++) for (int j = 0; j < STYLE_MAX; j ++) _htmlWidths[i][j][unicode] = _htmlWidthsAll[i][j][ch]; return (unicode); bad_sequence: if (ch3 >= 0) progress_error(HD_ERROR_READ_ERROR, "Bad UTF-8 character sequence %02X %02X %02X.", ch, ch2, ch3); else if (ch2 >= 0) progress_error(HD_ERROR_READ_ERROR, "Bad UTF-8 character sequence %02X %02X.", ch, ch2); else progress_error(HD_ERROR_READ_ERROR, "Bad UTF-8 character sequence %02X.", ch); return (0); } htmldoc-1.9.7/htmldoc/htmlsep.cxx000066400000000000000000000677231354715574200170500ustar00rootroot00000000000000/* * Separated HTML export functions for HTMLDOC, a HTML document processing * program. * * Copyright 2011-2019 by Michael R Sweet. * Copyright 1997-2010 by Easy Software Products. All rights reserved. * * This program is free software. Distribution and use rights are outlined in * the file "COPYING". */ /* * Include necessary headers. */ #include "htmldoc.h" #include "markdown.h" #include // // Named link structure... // typedef struct { uchar *filename; /* File for link */ uchar name[124]; /* Reference name */ } link_t; // // Local globals... // // Heading strings used for filenames... static size_t num_headings = 0, // Number of headings alloc_headings = 0; // Allocated headings static uchar **headings; // Heading strings // Links in document - used to add the correct filename to the link static size_t num_links = 0, // Number of links alloc_links = 0; // Allocated links static link_t *links; // Links // // Local functions... // extern "C" { typedef int (*compare_func_t)(const void *, const void *); } static void write_header(FILE **out, uchar *filename, uchar *title, uchar *author, uchar *copyright, uchar *docnumber, int heading); static void write_footer(FILE **out, int heading); static void write_title(FILE *out, uchar *title, uchar *author, uchar *copyright, uchar *docnumber); static int write_all(FILE *out, tree_t *t, int col); static int write_doc(FILE **out, tree_t *t, int col, int *heading, uchar *title, uchar *author, uchar *copyright, uchar *docnumber); static int write_node(FILE *out, tree_t *t, int col); static int write_nodeclose(FILE *out, tree_t *t, int col); static int write_toc(FILE *out, tree_t *t, int col); static uchar *get_title(tree_t *doc); static void add_heading(tree_t *t); static void add_link(uchar *name); static link_t *find_link(uchar *name); static int compare_links(link_t *n1, link_t *n2); static void scan_links(tree_t *t); static void update_links(tree_t *t, int *heading); // // 'htmlsep_export()' - Export to separated HTML files... // int // O - 0 = success, -1 = failure htmlsep_export(tree_t *document, // I - Document to export tree_t *toc) // I - Table of contents for document { size_t i; // Looping var int heading; // Current heading number uchar *title, // Title text *author, // Author name *copyright, // Copyright text *docnumber; // Document number FILE *out; // Output file // We only support writing to a directory... if (!OutputFiles) { progress_error(HD_ERROR_INTERNAL_ERROR, "Unable to generate separated HTML to a single file!"); return (-1); } // Copy logo and title images... if (LogoImage[0]) image_copy(LogoImage, file_find(LogoImage, Path), OutputPath); for (int hfi = 0; hfi < MAX_HF_IMAGES; hfi ++) if (HFImage[hfi][0]) image_copy(HFImage[hfi], file_find(HFImage[hfi], Path), OutputPath); if (TitleImage[0] && TitlePage && #ifdef WIN32 (stricmp(file_extension(TitleImage), "bmp") == 0 || stricmp(file_extension(TitleImage), "gif") == 0 || stricmp(file_extension(TitleImage), "jpg") == 0 || stricmp(file_extension(TitleImage), "png") == 0)) #else (strcmp(file_extension(TitleImage), "bmp") == 0 || strcmp(file_extension(TitleImage), "gif") == 0 || strcmp(file_extension(TitleImage), "jpg") == 0 || strcmp(file_extension(TitleImage), "png") == 0)) #endif // WIN32 image_copy(TitleImage, file_find(TitleImage, Path), OutputPath); // Get document strings... title = get_title(document); author = htmlGetMeta(document, (uchar *)"author"); copyright = htmlGetMeta(document, (uchar *)"copyright"); docnumber = htmlGetMeta(document, (uchar *)"docnumber"); if (!docnumber) docnumber = htmlGetMeta(document, (uchar *)"version"); // Scan for all links in the document, and then update them... num_links = 0; alloc_links = 0; links = NULL; scan_links(document); // printf("num_headings = %d\n", num_headings); // for (i = 0; i < num_headings; i ++) // printf("headings[%d] = \"%s\"\n", i, headings[i]); heading = -1; update_links(document, &heading); update_links(toc, NULL); // Generate title pages and a table of contents... out = NULL; if (TitlePage) { write_header(&out, (uchar *)"index.html", title, author, copyright, docnumber, -1); if (out != NULL) write_title(out, title, author, copyright, docnumber); write_footer(&out, -1); write_header(&out, (uchar *)"toc.html", title, author, copyright, docnumber, -1); } else write_header(&out, (uchar *)"index.html", title, author, copyright, docnumber, -1); if (out != NULL) write_toc(out, toc, 0); write_footer(&out, -1); // Then write each output file... heading = -1; write_doc(&out, document, 0, &heading, title, author, copyright, docnumber); if (out != NULL) write_footer(&out, heading); // Free memory... if (title != NULL) free(title); if (alloc_links) { free(links); num_links = 0; alloc_links = 0; links = NULL; } if (alloc_headings) { for (i = 0; i < num_headings; i ++) free(headings[i]); free(headings); num_headings = 0; alloc_headings = 0; headings = NULL; } return (out == NULL); } /* * 'write_header()' - Output the standard "header" for a HTML file. */ static void write_header(FILE **out, /* IO - Output file */ uchar *filename, /* I - Output filename */ uchar *title, /* I - Title for document */ uchar *author, /* I - Author for document */ uchar *copyright, /* I - Copyright for document */ uchar *docnumber, /* I - ID number for document */ int heading) /* I - Current heading */ { char realname[1024]; /* Real filename */ const char *basename; /* Filename without directory */ static const char *families[] =/* Typeface names */ { "monospace", "serif", "sans-serif", "monospace", "serif", "sans-serif", "symbol", "dingbats" }; basename = file_basename((char *)filename); snprintf(realname, sizeof(realname), "%s/%s", OutputPath, basename); *out = fopen(realname, "wb"); if (*out == NULL) { progress_error(HD_ERROR_WRITE_ERROR, "Unable to create output file \"%s\" - %s.\n", realname, strerror(errno)); return; } fputs("\n", *out); fputs("\n", *out); fputs("\n", *out); if (title != NULL) fprintf(*out, "%s\n", title); if (author != NULL) fprintf(*out, "\n", author); if (copyright != NULL) fprintf(*out, "\n", copyright); if (docnumber != NULL) fprintf(*out, "\n", docnumber); fprintf(*out, "\n", _htmlCharSet); fputs("\n", *out); if (TitlePage) fputs("\n", *out); else fputs("\n", *out); if (heading >= 0) { if (heading > 0) fprintf(*out, "\n", headings[heading - 1]); if ((size_t)heading < (num_headings - 1)) fprintf(*out, "\n", headings[heading + 1]); } fputs("\n", *out); fputs("\n", *out); if (BodyImage[0]) fprintf(*out, "\n", *out); if (heading >= 0) { if (LogoImage[0]) fprintf(*out, "\n", file_basename(LogoImage)); for (int hfi = 0; hfi < MAX_HF_IMAGES; ++hfi) if (HFImage[hfi][0]) fprintf(*out, "\n", file_basename(HFImage[hfi])); if (TitlePage) fputs("Contents\n", *out); else fputs("Contents\n", *out); if (heading > 0) fprintf(*out, "Previous\n", headings[heading - 1]); if ((size_t)heading < (num_headings - 1)) fprintf(*out, "Next\n", headings[heading + 1]); fputs("
    \n", *out); } } /* * 'write_footer()' - Output the standard "footer" for a HTML file. */ static void write_footer(FILE **out, /* IO - Output file pointer */ int heading) /* I - Current heading */ { if (*out == NULL) return; fputs("
    \n", *out); if (heading >= 0) { if (LogoImage[0]) fprintf(*out, "\n", file_basename(LogoImage)); for (int hfi = 0; hfi < MAX_HF_IMAGES; ++hfi) if (HFImage[hfi][0]) fprintf(*out, "\n", file_basename(HFImage[hfi])); if (TitlePage) fputs("Contents\n", *out); else fputs("Contents\n", *out); if (heading > 0) fprintf(*out, "Previous\n", headings[heading - 1]); if ((size_t)heading < (num_headings - 1)) fprintf(*out, "Next\n", headings[heading + 1]); } fputs("\n", *out); fputs("\n", *out); progress_error(HD_ERROR_NONE, "BYTES: %ld", ftell(*out)); fclose(*out); *out = NULL; } /* * 'write_title()' - Write a title page... */ static void write_title(FILE *out, /* I - Output file */ uchar *title, /* I - Title for document */ uchar *author, /* I - Author for document */ uchar *copyright, /* I - Copyright for document */ uchar *docnumber) /* I - ID number for document */ { FILE *fp; /* Title file */ const char *title_ext, /* Extension of title file */ *title_file; /* Location of title file */ tree_t *t; /* Title file document tree */ if (out == NULL) return; title_ext = file_extension(TitleImage); #ifdef WIN32 if (TitleImage[0] && stricmp(title_ext, "bmp") != 0 && stricmp(title_ext, "gif") != 0 && stricmp(title_ext, "jpg") != 0 && stricmp(title_ext, "png") != 0) #else if (TitleImage[0] && strcmp(title_ext, "bmp") != 0 && strcmp(title_ext, "gif") != 0 && strcmp(title_ext, "jpg") != 0 && strcmp(title_ext, "png") != 0) #endif // WIN32 { // Find the title page file... if ((title_file = file_find(Path, TitleImage)) == NULL) { progress_error(HD_ERROR_FILE_NOT_FOUND, "Unable to find title file \"%s\"!", TitleImage); return; } // Write a title page from HTML source... if ((fp = fopen(title_file, "rb")) == NULL) { progress_error(HD_ERROR_FILE_NOT_FOUND, "Unable to open title file \"%s\" - %s!", TitleImage, strerror(errno)); return; } #ifdef _WIN32 if (!stricmp(title_ext, "md")) #else if (!strcmp(title_ext, "md")) #endif // _WIN32 t = mdReadFile(NULL, fp, file_directory(TitleImage)); else t = htmlReadFile(NULL, fp, file_directory(TitleImage)); htmlFixLinks(t, t, (uchar *)file_directory(TitleImage)); fclose(fp); write_all(out, t, 0); htmlDeleteTree(t); } else { // Write a "standard" title page with image... fputs("
    ", out); if (TitleImage[0]) { image_t *img = image_load(TitleImage, !OutputColor); fprintf(out, "
    \n", file_basename((char *)TitleImage), img->width, img->height, title ? (char *)title : ""); } if (title != NULL) fprintf(out, "

    %s


    \n", title); else fputs("\n", out); if (docnumber != NULL) fprintf(out, "%s
    \n", docnumber); if (author != NULL) fprintf(out, "%s
    \n", author); if (copyright != NULL) fprintf(out, "%s
    \n", copyright); fputs("Table of Contents", out); fputs("
    \n", out); } } /* * 'write_all()' - Write all markup text for the given tree. */ static int /* O - Current column */ write_all(FILE *out, /* I - Output file */ tree_t *t, /* I - Document tree */ int col) /* I - Current column */ { if (out == NULL) return (0); while (t != NULL) { col = write_node(out, t, col); if (t->markup != MARKUP_HEAD && t->markup != MARKUP_TITLE) col = write_all(out, t->child, col); col = write_nodeclose(out, t, col); t = t->next; } return (col); } /* * 'write_doc()' - Write the entire document. */ static int // O - Current column write_doc(FILE **out, // I - Output file tree_t *t, // I - Document tree int col, // I - Current column int *heading, // IO - Current heading uchar *title, // I - Title uchar *author, // I - Author uchar *copyright, // I - Copyright uchar *docnumber) // I - Document number { uchar filename[1024]; // Filename while (t != NULL) { if (t->markup >= MARKUP_H1 && t->markup < (MARKUP_H1 + TocLevels) && htmlGetVariable(t, (uchar *)"_HD_OMIT_TOC") == NULL) { if (*heading >= 0) write_footer(out, *heading); (*heading) ++; if (*heading >= 0) { snprintf((char *)filename, sizeof(filename), "%s.html", headings[*heading]); write_header(out, filename, title, author, copyright, docnumber, *heading); } } col = write_node(*out, t, col); if (t->markup != MARKUP_HEAD && t->markup != MARKUP_TITLE) col = write_doc(out, t->child, col, heading, title, author, copyright, docnumber); col = write_nodeclose(*out, t, col); t = t->next; } return (col); } /* * 'write_node()' - Write a single tree node. */ static int /* O - Current column */ write_node(FILE *out, /* I - Output file */ tree_t *t, /* I - Document tree node */ int col) /* I - Current column */ { int i; /* Looping var */ uchar *ptr, /* Pointer to output string */ *entity, /* Entity string */ *src, /* Source image */ *realsrc, /* Real source image */ newsrc[1024]; /* New source image filename */ if (out == NULL) return (0); switch (t->markup) { case MARKUP_NONE : if (t->data == NULL) break; if (t->preformatted) { for (ptr = t->data; *ptr; ptr ++) fputs((char *)iso8859(*ptr), out); if (t->data[strlen((char *)t->data) - 1] == '\n') col = 0; else col += strlen((char *)t->data); } else { if ((col + (int)strlen((char *)t->data)) > 72 && col > 0) { putc('\n', out); col = 0; } for (ptr = t->data; *ptr; ptr ++) fputs((char *)iso8859(*ptr), out); col += strlen((char *)t->data); if (col > 72) { putc('\n', out); col = 0; } } break; case MARKUP_COMMENT : case MARKUP_UNKNOWN : fputs("\n\n", out); col = 0; break; case MARKUP_AREA : case MARKUP_BODY : case MARKUP_DOCTYPE : case MARKUP_ERROR : case MARKUP_FILE : case MARKUP_HEAD : case MARKUP_HTML : case MARKUP_MAP : case MARKUP_META : case MARKUP_TITLE : break; case MARKUP_BR : case MARKUP_CENTER : case MARKUP_DD : case MARKUP_DL : case MARKUP_DT : case MARKUP_H1 : case MARKUP_H2 : case MARKUP_H3 : case MARKUP_H4 : case MARKUP_H5 : case MARKUP_H6 : case MARKUP_H7 : case MARKUP_H8 : case MARKUP_H9 : case MARKUP_H10 : case MARKUP_H11 : case MARKUP_H12 : case MARKUP_H13 : case MARKUP_H14 : case MARKUP_H15 : case MARKUP_HR : case MARKUP_LI : case MARKUP_OL : case MARKUP_P : case MARKUP_PRE : case MARKUP_TABLE : case MARKUP_TR : case MARKUP_UL : if (col > 0) { putc('\n', out); col = 0; } default : if (t->markup == MARKUP_IMG && (src = htmlGetVariable(t, (uchar *)"SRC")) != NULL && (realsrc = htmlGetVariable(t, (uchar *)"REALSRC")) != NULL) { /* * Update local images... */ if (file_method((char *)src) == NULL && src[0] != '/' && src[0] != '\\' && (!isalpha(src[0]) || src[1] != ':')) { image_copy((char *)src, (char *)realsrc, OutputPath); strlcpy((char *)newsrc, file_basename((char *)src), sizeof(newsrc)); htmlSetVariable(t, (uchar *)"SRC", newsrc); } } if (t->markup != MARKUP_EMBED) { col += fprintf(out, "<%s", _htmlMarkups[t->markup]); for (i = 0; i < t->nvars; i ++) { if (strcasecmp((char *)t->vars[i].name, "BREAK") == 0 && t->markup == MARKUP_HR) continue; if (strcasecmp((char *)t->vars[i].name, "REALSRC") == 0 && t->markup == MARKUP_IMG) continue; if (strncasecmp((char *)t->vars[i].name, "_HD_", 4) == 0) continue; if (col > 72 && !t->preformatted) { putc('\n', out); col = 0; } if (col > 0) { putc(' ', out); col ++; } if (t->vars[i].value == NULL) col += fprintf(out, "%s", t->vars[i].name); else { col += fprintf(out, "%s=\"", t->vars[i].name); for (ptr = t->vars[i].value; *ptr; ptr ++) { entity = iso8859(*ptr); fputs((char *)entity, out); col += strlen((char *)entity); } putc('\"', out); col ++; } } putc('>', out); col ++; if (col > 72 && !t->preformatted) { putc('\n', out); col = 0; } } break; } return (col); } /* * 'write_nodeclose()' - Close a single tree node. */ static int /* O - Current column */ write_nodeclose(FILE *out, /* I - Output file */ tree_t *t, /* I - Document tree node */ int col) /* I - Current column */ { if (out == NULL) return (0); if (t->markup != MARKUP_HEAD && t->markup != MARKUP_TITLE) { if (col > 72 && !t->preformatted) { putc('\n', out); col = 0; } switch (t->markup) { case MARKUP_BODY : case MARKUP_ERROR : case MARKUP_FILE : case MARKUP_HEAD : case MARKUP_HTML : case MARKUP_NONE : case MARKUP_TITLE : case MARKUP_APPLET : case MARKUP_AREA : case MARKUP_BR : case MARKUP_COMMENT : case MARKUP_DOCTYPE : case MARKUP_EMBED : case MARKUP_HR : case MARKUP_IMG : case MARKUP_INPUT : case MARKUP_ISINDEX : case MARKUP_LINK : case MARKUP_META : case MARKUP_NOBR : case MARKUP_SPACER : case MARKUP_WBR : case MARKUP_UNKNOWN : break; case MARKUP_CENTER : case MARKUP_DD : case MARKUP_DL : case MARKUP_DT : case MARKUP_H1 : case MARKUP_H2 : case MARKUP_H3 : case MARKUP_H4 : case MARKUP_H5 : case MARKUP_H6 : case MARKUP_H7 : case MARKUP_H8 : case MARKUP_H9 : case MARKUP_H10 : case MARKUP_H11 : case MARKUP_H12 : case MARKUP_H13 : case MARKUP_H14 : case MARKUP_H15 : case MARKUP_LI : case MARKUP_OL : case MARKUP_P : case MARKUP_PRE : case MARKUP_TABLE : case MARKUP_TR : case MARKUP_UL : fprintf(out, "\n", _htmlMarkups[t->markup]); col = 0; break; default : col += fprintf(out, "", _htmlMarkups[t->markup]); break; } } return (col); } /* * 'write_toc()' - Write all markup text for the given table-of-contents. */ static int /* O - Current column */ write_toc(FILE *out, /* I - Output file */ tree_t *t, /* I - Document tree */ int col) /* I - Current column */ { if (out == NULL) return (0); while (t != NULL) { if (htmlGetVariable(t, (uchar *)"_HD_OMIT_TOC") == NULL) { col = write_node(out, t, col); if (t->markup != MARKUP_HEAD && t->markup != MARKUP_TITLE) col = write_toc(out, t->child, col); col = write_nodeclose(out, t, col); } t = t->next; } return (col); } /* * 'get_title()' - Get the title string for the given document... */ static uchar * /* O - Title string */ get_title(tree_t *doc) /* I - Document tree */ { uchar *temp; /* Temporary pointer to title */ while (doc != NULL) { if (doc->markup == MARKUP_TITLE) return (htmlGetText(doc->child)); else if (doc->child != NULL) if ((temp = get_title(doc->child)) != NULL) return (temp); doc = doc->next; } return (NULL); } // // 'add_heading()' - Add a heading to the list of headings... // static void add_heading(tree_t *t) // I - Heading node { size_t i, // Looping var count; // Count of headings with this name uchar *heading, // Heading text for this node *ptr, // Pointer into text *ptr2, // Second pointer into text s[1024], // New text if we have a conflict **temp; // New heading array pointer // Start by getting the heading text... heading = htmlGetText(t->child); if (!heading || !*heading) return; // Nothing to do! // Sanitize the text... for (ptr = heading; *ptr;) if (!isalnum(*ptr)) { // Remove anything but letters and numbers from the filename for (ptr2 = ptr; *ptr2; ptr2 ++) *ptr2 = ptr2[1]; *ptr2 = '\0'; } else ptr ++; // Now loop through the existing headings and check for dups... for (ptr = heading, i = 0, count = 0; i < num_headings; i ++) if (strcmp((char *)headings[i], (char *)ptr) == 0) { // Create a new instance of the heading... count ++; snprintf((char *)s, sizeof(s), "%s%d", heading, (int)count); ptr = s; } // Now add the heading... if (num_headings >= alloc_headings) { // Allocate more headings... alloc_headings += ALLOC_HEADINGS; if (num_headings == 0) temp = (uchar **)malloc(sizeof(uchar *) * alloc_headings); else temp = (uchar **)realloc(headings, sizeof(uchar *) * alloc_headings); if (temp == NULL) { progress_error(HD_ERROR_OUT_OF_MEMORY, "Unable to allocate memory for %d headings - %s", alloc_headings, strerror(errno)); alloc_headings -= ALLOC_HEADINGS; return; } headings = temp; } if (ptr == heading) { // Reuse the already-allocated string... headings[num_headings] = ptr; } else { // Make a copy of the string "s" and free the old heading string... headings[num_headings] = (uchar *)strdup((char *)s); free(heading); } num_headings ++; } /* * 'add_link()' - Add a named link... */ static void add_link(uchar *name) /* I - Name of link */ { uchar *filename; /* File for link */ link_t *temp; /* New name */ if (num_headings) filename = headings[num_headings - 1]; else filename = (uchar *)"noheading"; if ((temp = find_link(name)) != NULL) temp->filename = filename; else { // See if we need to allocate memory for links... if (num_links >= alloc_links) { // Allocate more links... alloc_links += ALLOC_LINKS; if (num_links == 0) temp = (link_t *)malloc(sizeof(link_t) * alloc_links); else temp = (link_t *)realloc(links, sizeof(link_t) * alloc_links); if (temp == NULL) { progress_error(HD_ERROR_OUT_OF_MEMORY, "Unable to allocate memory for %d links - %s", alloc_links, strerror(errno)); alloc_links -= ALLOC_LINKS; return; } links = temp; } // Add a new link... temp = links + num_links; num_links ++; strlcpy((char *)temp->name, (char *)name, sizeof(temp->name)); temp->filename = filename; if (num_links > 1) qsort(links, num_links, sizeof(link_t), (compare_func_t)compare_links); } } /* * 'find_link()' - Find a named link... */ static link_t * find_link(uchar *name) /* I - Name to find */ { uchar *target; /* Pointer to target name portion */ link_t key, /* Search key */ *match; /* Matching name entry */ if (name == NULL || num_links == 0) return (NULL); if ((target = (uchar *)file_target((char *)name)) == NULL) return (NULL); strlcpy((char *)key.name, (char *)target, sizeof(key.name)); key.name[sizeof(key.name) - 1] = '\0'; match = (link_t *)bsearch(&key, links, num_links, sizeof(link_t), (compare_func_t)compare_links); return (match); } /* * 'compare_links()' - Compare two named links. */ static int /* O - 0 = equal, -1 or 1 = not equal */ compare_links(link_t *n1, /* I - First name */ link_t *n2) /* I - Second name */ { return (strcasecmp((char *)n1->name, (char *)n2->name)); } /* * 'scan_links()' - Scan a document for link targets, and keep track of * the files they are in... */ static void scan_links(tree_t *t) /* I - Document tree */ { uchar *name; /* Name of link */ while (t != NULL) { if (t->markup >= MARKUP_H1 && t->markup < (MARKUP_H1 + TocLevels) && htmlGetVariable(t, (uchar *)"_HD_OMIT_TOC") == NULL) add_heading(t); if (t->markup == MARKUP_A && (name = htmlGetVariable(t, (uchar *)"NAME")) != NULL) add_link(name); if (t->child != NULL) scan_links(t->child); t = t->next; } } /* * 'update_links()' - Update links as needed. */ static void update_links(tree_t *t, /* I - Document tree */ int *heading) /* I - Current heading */ { link_t *link; /* Link */ uchar *href; /* Reference name */ uchar newhref[1024]; /* New reference name */ uchar *filename; /* Current filename */ // Scan the document, rewriting HREF's as needed... while (t != NULL) { if (t->markup >= MARKUP_H1 && t->markup < (MARKUP_H1 + TocLevels) && htmlGetVariable(t, (uchar *)"_HD_OMIT_TOC") == NULL && heading) (*heading) ++; // Figure out the current filename based upon the current heading number... if (!heading || *heading < 0 || (size_t)*heading >= num_headings) filename = (uchar *)"noheading"; else filename = headings[*heading]; if (t->markup == MARKUP_A && (href = htmlGetVariable(t, (uchar *)"HREF")) != NULL) { // Update this link as needed... if (href[0] == '#' && (link = find_link(href)) != NULL) { // The filename in the link structure is a copy of the heading // pointer... if (filename != link->filename) { // Rewrite using the new name... snprintf((char *)newhref, sizeof(newhref), "%s.html%s", link->filename, href); htmlSetVariable(t, (uchar *)"HREF", newhref); } } } // Descend the tree as needed... if (t->child != NULL) update_links(t->child, heading); // Move to the next node at this level... t = t->next; } } htmldoc-1.9.7/htmldoc/http-addr.c000066400000000000000000000501451354715574200166710ustar00rootroot00000000000000/* * HTTP address routines for HTMLDOC. * * Copyright 2016-2017 by Michael R Sweet. * Copyright 2007-2014 by Apple Inc. * Copyright 1997-2006 by Easy Software Products, all rights reserved. * * This program is free software. Distribution and use rights are outlined in * the file "COPYING". */ /* * Include necessary headers... */ #include "http-private.h" #include #ifdef HAVE_RESOLV_H # include #endif /* HAVE_RESOLV_H */ #ifdef __APPLE__ # include # include #endif /* __APPLE__ */ /* * 'httpAddrAny()' - Check for the "any" address. * * @since CUPS 1.2/macOS 10.5@ */ int /* O - 1 if "any", 0 otherwise */ httpAddrAny(const http_addr_t *addr) /* I - Address to check */ { if (!addr) return (0); #ifdef AF_INET6 if (addr->addr.sa_family == AF_INET6 && IN6_IS_ADDR_UNSPECIFIED(&(addr->ipv6.sin6_addr))) return (1); #endif /* AF_INET6 */ if (addr->addr.sa_family == AF_INET && ntohl(addr->ipv4.sin_addr.s_addr) == 0x00000000) return (1); return (0); } /* * 'httpAddrClose()' - Close a socket created by @link httpAddrConnect@ or * @link httpAddrListen@. * * Pass @code NULL@ for sockets created with @link httpAddrConnect@ and the * listen address for sockets created with @link httpAddrListen@. This will * ensure that domain sockets are removed when closed. * * @since CUPS 2.0/OS 10.10@ */ int /* O - 0 on success, -1 on failure */ httpAddrClose(http_addr_t *addr, /* I - Listen address or @code NULL@ */ int fd) /* I - Socket file descriptor */ { #ifdef WIN32 if (closesocket(fd)) #else if (close(fd)) #endif /* WIN32 */ return (-1); #ifdef AF_LOCAL if (addr && addr->addr.sa_family == AF_LOCAL) return (unlink(addr->un.sun_path)); #endif /* AF_LOCAL */ return (0); } /* * 'httpAddrEqual()' - Compare two addresses. * * @since CUPS 1.2/macOS 10.5@ */ int /* O - 1 if equal, 0 if not */ httpAddrEqual(const http_addr_t *addr1, /* I - First address */ const http_addr_t *addr2) /* I - Second address */ { if (!addr1 && !addr2) return (1); if (!addr1 || !addr2) return (0); if (addr1->addr.sa_family != addr2->addr.sa_family) return (0); #ifdef AF_LOCAL if (addr1->addr.sa_family == AF_LOCAL) return (!strcmp(addr1->un.sun_path, addr2->un.sun_path)); #endif /* AF_LOCAL */ #ifdef AF_INET6 if (addr1->addr.sa_family == AF_INET6) return (!memcmp(&(addr1->ipv6.sin6_addr), &(addr2->ipv6.sin6_addr), 16)); #endif /* AF_INET6 */ return (addr1->ipv4.sin_addr.s_addr == addr2->ipv4.sin_addr.s_addr); } /* * 'httpAddrLength()' - Return the length of the address in bytes. * * @since CUPS 1.2/macOS 10.5@ */ int /* O - Length in bytes */ httpAddrLength(const http_addr_t *addr) /* I - Address */ { if (!addr) return (0); #ifdef AF_INET6 if (addr->addr.sa_family == AF_INET6) return (sizeof(addr->ipv6)); else #endif /* AF_INET6 */ #ifdef AF_LOCAL if (addr->addr.sa_family == AF_LOCAL) return ((int)(offsetof(struct sockaddr_un, sun_path) + strlen(addr->un.sun_path) + 1)); else #endif /* AF_LOCAL */ if (addr->addr.sa_family == AF_INET) return (sizeof(addr->ipv4)); else return (0); } /* * 'httpAddrListen()' - Create a listening socket bound to the specified * address and port. * * @since CUPS 1.7/macOS 10.9@ */ int /* O - Socket or -1 on error */ httpAddrListen(http_addr_t *addr, /* I - Address to bind to */ int port) /* I - Port number to bind to */ { int fd = -1, /* Socket */ val, /* Socket value */ status; /* Bind status */ /* * Range check input... */ if (!addr || port < 0) return (-1); /* * Create the socket and set options... */ if ((fd = socket(addr->addr.sa_family, SOCK_STREAM, 0)) < 0) { _cupsSetHTTPError(HTTP_STATUS_ERROR); return (-1); } val = 1; setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, CUPS_SOCAST &val, sizeof(val)); #ifdef IPV6_V6ONLY if (addr->addr.sa_family == AF_INET6) setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, CUPS_SOCAST &val, sizeof(val)); #endif /* IPV6_V6ONLY */ /* * Bind the socket... */ #ifdef AF_LOCAL if (addr->addr.sa_family == AF_LOCAL) { mode_t mask; /* Umask setting */ /* * Remove any existing domain socket file... */ unlink(addr->un.sun_path); /* * Save the current umask and set it to 0 so that all users can access * the domain socket... */ mask = umask(0); /* * Bind the domain socket... */ status = bind(fd, (struct sockaddr *)addr, (socklen_t)httpAddrLength(addr)); /* * Restore the umask and fix permissions... */ umask(mask); chmod(addr->un.sun_path, 0140777); } else #endif /* AF_LOCAL */ { _httpAddrSetPort(addr, port); status = bind(fd, (struct sockaddr *)addr, (socklen_t)httpAddrLength(addr)); } if (status) { _cupsSetHTTPError(HTTP_STATUS_ERROR); close(fd); return (-1); } /* * Listen... */ if (listen(fd, 5)) { _cupsSetHTTPError(HTTP_STATUS_ERROR); close(fd); return (-1); } /* * Close on exec... */ #ifndef WIN32 fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC); #endif /* !WIN32 */ #ifdef SO_NOSIGPIPE /* * Disable SIGPIPE for this socket. */ val = 1; setsockopt(fd, SOL_SOCKET, SO_NOSIGPIPE, CUPS_SOCAST &val, sizeof(val)); #endif /* SO_NOSIGPIPE */ return (fd); } /* * 'httpAddrLocalhost()' - Check for the local loopback address. * * @since CUPS 1.2/macOS 10.5@ */ int /* O - 1 if local host, 0 otherwise */ httpAddrLocalhost( const http_addr_t *addr) /* I - Address to check */ { if (!addr) return (1); #ifdef AF_INET6 if (addr->addr.sa_family == AF_INET6 && IN6_IS_ADDR_LOOPBACK(&(addr->ipv6.sin6_addr))) return (1); #endif /* AF_INET6 */ #ifdef AF_LOCAL if (addr->addr.sa_family == AF_LOCAL) return (1); #endif /* AF_LOCAL */ if (addr->addr.sa_family == AF_INET && (ntohl(addr->ipv4.sin_addr.s_addr) & 0xff000000) == 0x7f000000) return (1); return (0); } /* * 'httpAddrLookup()' - Lookup the hostname associated with the address. * * @since CUPS 1.2/macOS 10.5@ */ char * /* O - Host name */ httpAddrLookup( const http_addr_t *addr, /* I - Address to lookup */ char *name, /* I - Host name buffer */ int namelen) /* I - Size of name buffer */ { DEBUG_printf(("httpAddrLookup(addr=%p, name=%p, namelen=%d)", addr, name, namelen)); /* * Range check input... */ if (!addr || !name || namelen <= 2) { if (name && namelen >= 1) *name = '\0'; return (NULL); } #ifdef AF_LOCAL if (addr->addr.sa_family == AF_LOCAL) { strlcpy(name, addr->un.sun_path, (size_t)namelen); return (name); } #endif /* AF_LOCAL */ /* * Optimize lookups for localhost/loopback addresses... */ if (httpAddrLocalhost(addr)) { strlcpy(name, "localhost", (size_t)namelen); return (name); } #ifdef HAVE_GETNAMEINFO { /* * STR #2486: httpAddrLookup() fails when getnameinfo() returns EAI_AGAIN * * FWIW, I think this is really a bug in the implementation of * getnameinfo(), but falling back on httpAddrString() is easy to * do... */ int error = getnameinfo(&addr->addr, (socklen_t)httpAddrLength(addr), name, (socklen_t)namelen, NULL, 0, 0); if (error) return (httpAddrString(addr, name, namelen)); } #else { struct hostent *host; /* Host from name service */ # ifdef AF_INET6 if (addr->addr.sa_family == AF_INET6) host = gethostbyaddr((char *)&(addr->ipv6.sin6_addr), sizeof(struct in_addr), AF_INET6); else # endif /* AF_INET6 */ host = gethostbyaddr((char *)&(addr->ipv4.sin_addr), sizeof(struct in_addr), AF_INET); if (host == NULL) { /* * No hostname, so return the raw address... */ if (h_errno == NO_RECOVERY) cg->need_res_init = 1; return (httpAddrString(addr, name, namelen)); } strlcpy(name, host->h_name, (size_t)namelen); } #endif /* HAVE_GETNAMEINFO */ DEBUG_printf(("1httpAddrLookup: returning \"%s\"...", name)); return (name); } /* * 'httpAddrFamily()' - Get the address family of an address. */ int /* O - Address family */ httpAddrFamily(http_addr_t *addr) /* I - Address */ { if (addr) return (addr->addr.sa_family); else return (0); } /* * 'httpAddrPort()' - Get the port number associated with an address. * * @since CUPS 1.7/macOS 10.9@ */ int /* O - Port number */ httpAddrPort(http_addr_t *addr) /* I - Address */ { if (!addr) return (-1); #ifdef AF_INET6 else if (addr->addr.sa_family == AF_INET6) return (ntohs(addr->ipv6.sin6_port)); #endif /* AF_INET6 */ else if (addr->addr.sa_family == AF_INET) return (ntohs(addr->ipv4.sin_port)); else return (0); } /* * '_httpAddrSetPort()' - Set the port number associated with an address. */ void _httpAddrSetPort(http_addr_t *addr, /* I - Address */ int port) /* I - Port */ { if (!addr || port <= 0) return; #ifdef AF_INET6 if (addr->addr.sa_family == AF_INET6) addr->ipv6.sin6_port = htons(port); else #endif /* AF_INET6 */ if (addr->addr.sa_family == AF_INET) addr->ipv4.sin_port = htons(port); } /* * 'httpAddrString()' - Convert an address to a numeric string. * * @since CUPS 1.2/macOS 10.5@ */ char * /* O - Numeric address string */ httpAddrString(const http_addr_t *addr, /* I - Address to convert */ char *s, /* I - String buffer */ int slen) /* I - Length of string */ { DEBUG_printf(("httpAddrString(addr=%p, s=%p, slen=%d)", addr, s, slen)); /* * Range check input... */ if (!addr || !s || slen <= 2) { if (s && slen >= 1) *s = '\0'; return (NULL); } #ifdef AF_LOCAL if (addr->addr.sa_family == AF_LOCAL) { if (addr->un.sun_path[0] == '/') strlcpy(s, addr->un.sun_path, (size_t)slen); else strlcpy(s, "localhost", (size_t)slen); } else #endif /* AF_LOCAL */ if (addr->addr.sa_family == AF_INET) { unsigned temp; /* Temporary address */ temp = ntohl(addr->ipv4.sin_addr.s_addr); snprintf(s, (size_t)slen, "%d.%d.%d.%d", (temp >> 24) & 255, (temp >> 16) & 255, (temp >> 8) & 255, temp & 255); } #ifdef AF_INET6 else if (addr->addr.sa_family == AF_INET6) { char *sptr, /* Pointer into string */ temps[64]; /* Temporary string for address */ # ifdef HAVE_GETNAMEINFO if (getnameinfo(&addr->addr, (socklen_t)httpAddrLength(addr), temps, sizeof(temps), NULL, 0, NI_NUMERICHOST)) { /* * If we get an error back, then the address type is not supported * and we should zero out the buffer... */ s[0] = '\0'; return (NULL); } else if ((sptr = strchr(temps, '%')) != NULL) { /* * Convert "%zone" to "+zone" to match URI form... */ *sptr = '+'; } # else int i; /* Looping var */ unsigned temp; /* Current value */ const char *prefix; /* Prefix for address */ prefix = ""; for (sptr = temps, i = 0; i < 4 && addr->ipv6.sin6_addr.s6_addr32[i]; i ++) { temp = ntohl(addr->ipv6.sin6_addr.s6_addr32[i]); snprintf(sptr, sizeof(temps) - (size_t)(sptr - temps), "%s%x", prefix, (temp >> 16) & 0xffff); prefix = ":"; sptr += strlen(sptr); temp &= 0xffff; if (temp || i == 3 || addr->ipv6.sin6_addr.s6_addr32[i + 1]) { snprintf(sptr, sizeof(temps) - (size_t)(sptr - temps), "%s%x", prefix, temp); sptr += strlen(sptr); } } if (i < 4) { while (i < 4 && !addr->ipv6.sin6_addr.s6_addr32[i]) i ++; if (i < 4) { snprintf(sptr, sizeof(temps) - (size_t)(sptr - temps), "%s:", prefix); prefix = ":"; sptr += strlen(sptr); for (; i < 4; i ++) { temp = ntohl(addr->ipv6.sin6_addr.s6_addr32[i]); if ((temp & 0xffff0000) || (i > 0 && addr->ipv6.sin6_addr.s6_addr32[i - 1])) { snprintf(sptr, sizeof(temps) - (size_t)(sptr - temps), "%s%x", prefix, (temp >> 16) & 0xffff); sptr += strlen(sptr); } snprintf(sptr, sizeof(temps) - (size_t)(sptr - temps), "%s%x", prefix, temp & 0xffff); sptr += strlen(sptr); } } else if (sptr == s) { /* * Empty address... */ strlcpy(temps, "::", sizeof(temps)); } else { /* * Empty at end... */ strlcpy(sptr, "::", sizeof(temps) - (size_t)(sptr - temps)); } } # endif /* HAVE_GETNAMEINFO */ /* * Add "[v1." and "]" around IPv6 address to convert to URI form. */ snprintf(s, (size_t)slen, "[v1.%s]", temps); } #endif /* AF_INET6 */ else strlcpy(s, "UNKNOWN", (size_t)slen); DEBUG_printf(("1httpAddrString: returning \"%s\"...", s)); return (s); } /* * 'httpGetAddress()' - Get the address of the connected peer of a connection. * * Returns @code NULL@ if the socket is currently unconnected. * * @since CUPS 2.0/OS 10.10@ */ http_addr_t * /* O - Connected address or @code NULL@ */ httpGetAddress(http_t *http) /* I - HTTP connection */ { if (http) return (http->hostaddr); else return (NULL); } /* * 'httpGetHostByName()' - Lookup a hostname or IPv4 address, and return * address records for the specified name. * * @deprecated@ */ struct hostent * /* O - Host entry */ httpGetHostByName(const char *name) /* I - Hostname or IP address */ { const char *nameptr; /* Pointer into name */ unsigned ip[4]; /* IP address components */ static unsigned ip_addr; /* Packed IPv4 address */ static char *ip_ptrs[2]; /* Pointer to packed address */ static struct hostent hostent; /* Host entry for IP address */ DEBUG_printf(("httpGetHostByName(name=\"%s\")", name)); /* * Avoid lookup delays and configuration problems when connecting * to the localhost address... */ if (!strcmp(name, "localhost")) name = "127.0.0.1"; /* * This function is needed because some operating systems have a * buggy implementation of gethostbyname() that does not support * IP addresses. If the first character of the name string is a * number, then sscanf() is used to extract the IP components. * We then pack the components into an IPv4 address manually, * since the inet_aton() function is deprecated. We use the * htonl() macro to get the right byte order for the address. * * We also support domain sockets when supported by the underlying * OS... */ #ifdef AF_LOCAL if (name[0] == '/') { /* * A domain socket address, so make an AF_LOCAL entry and return it... */ hostent.h_name = (char *)name; hostent.h_aliases = NULL; hostent.h_addrtype = AF_LOCAL; hostent.h_length = (int)strlen(name) + 1; hostent.h_addr_list = ip_ptrs; ip_ptrs[0] = (char *)name; ip_ptrs[1] = NULL; DEBUG_puts("1httpGetHostByName: returning domain socket address..."); return (&hostent); } #endif /* AF_LOCAL */ for (nameptr = name; isdigit(*nameptr & 255) || *nameptr == '.'; nameptr ++); if (!*nameptr) { /* * We have an IPv4 address; break it up and provide the host entry * to the caller. */ if (sscanf(name, "%u.%u.%u.%u", ip, ip + 1, ip + 2, ip + 3) != 4) return (NULL); /* Must have 4 numbers */ if (ip[0] > 255 || ip[1] > 255 || ip[2] > 255 || ip[3] > 255) return (NULL); /* Invalid byte ranges! */ ip_addr = htonl((((((((unsigned)ip[0] << 8) | (unsigned)ip[1]) << 8) | (unsigned)ip[2]) << 8) | (unsigned)ip[3])); /* * Fill in the host entry and return it... */ hostent.h_name = (char *)name; hostent.h_aliases = NULL; hostent.h_addrtype = AF_INET; hostent.h_length = 4; hostent.h_addr_list = ip_ptrs; ip_ptrs[0] = (char *)&ip_addr; ip_ptrs[1] = NULL; DEBUG_puts("1httpGetHostByName: returning IPv4 address..."); return (&hostent); } else { /* * Use the gethostbyname() function to get the IPv4 address for * the name... */ DEBUG_puts("1httpGetHostByName: returning domain lookup address(es)..."); return (gethostbyname(name)); } } /* * 'httpGetHostname()' - Get the FQDN for the connection or local system. * * When "http" points to a connected socket, return the hostname or * address that was used in the call to httpConnect() or httpConnectEncrypt(), * or the address of the client for the connection from httpAcceptConnection(). * Otherwise, return the FQDN for the local system using both gethostname() * and gethostbyname() to get the local hostname with domain. * * @since CUPS 1.2/macOS 10.5@ */ const char * /* O - FQDN for connection or system */ httpGetHostname(http_t *http, /* I - HTTP connection or NULL */ char *s, /* I - String buffer for name */ int slen) /* I - Size of buffer */ { if (http) { if (!s || slen <= 1) { if (http->hostname[0] == '/') return ("localhost"); else return (http->hostname); } else if (http->hostname[0] == '/') strlcpy(s, "localhost", (size_t)slen); else strlcpy(s, http->hostname, (size_t)slen); } else { /* * Get the hostname... */ if (!s || slen <= 1) return (NULL); if (gethostname(s, (size_t)slen) < 0) strlcpy(s, "localhost", (size_t)slen); if (!strchr(s, '.')) { #ifdef HAVE_SCDYNAMICSTORECOPYCOMPUTERNAME /* * The hostname is not a FQDN, so use the local hostname from the * SystemConfiguration framework... */ SCDynamicStoreRef sc = SCDynamicStoreCreate(kCFAllocatorDefault, CFSTR("libcups"), NULL, NULL); /* System configuration data */ CFStringRef local = sc ? SCDynamicStoreCopyLocalHostName(sc) : NULL; /* Local host name */ char localStr[1024]; /* Local host name C string */ if (local && CFStringGetCString(local, localStr, sizeof(localStr), kCFStringEncodingUTF8)) { /* * Append ".local." to the hostname we get... */ snprintf(s, (size_t)slen, "%s.local.", localStr); } if (local) CFRelease(local); if (sc) CFRelease(sc); #else /* * The hostname is not a FQDN, so look it up... */ struct hostent *host; /* Host entry to get FQDN */ if ((host = gethostbyname(s)) != NULL && host->h_name) { /* * Use the resolved hostname... */ strlcpy(s, host->h_name, (size_t)slen); } #endif /* HAVE_SCDYNAMICSTORECOPYCOMPUTERNAME */ } /* * Make sure .local hostnames end with a period... */ if (strlen(s) > 6 && !strcmp(s + strlen(s) - 6, ".local")) strlcat(s, ".", (size_t)slen); } /* * Convert the hostname to lowercase as needed... */ if (s[0] != '/') { char *ptr; /* Pointer into string */ for (ptr = s; *ptr; ptr ++) *ptr = (char)tolower((int)*ptr & 255); } /* * Return the hostname with as much domain info as we have... */ return (s); } /* * 'httpResolveHostname()' - Resolve the hostname of the HTTP connection * address. * * @since CUPS 2.0/OS 10.10@ */ const char * /* O - Resolved hostname or @code NULL@ */ httpResolveHostname(http_t *http, /* I - HTTP connection */ char *buffer, /* I - Hostname buffer */ size_t bufsize) /* I - Size of buffer */ { if (!http) return (NULL); if (isdigit(http->hostname[0] & 255) || http->hostname[0] == '[') { char temp[1024]; /* Temporary string */ if (httpAddrLookup(http->hostaddr, temp, sizeof(temp))) strlcpy(http->hostname, temp, sizeof(http->hostname)); else return (NULL); } if (buffer) { if (http->hostname[0] == '/') strlcpy(buffer, "localhost", bufsize); else strlcpy(buffer, http->hostname, bufsize); return (buffer); } else if (http->hostname[0] == '/') return ("localhost"); else return (http->hostname); } htmldoc-1.9.7/htmldoc/http-addrlist.c000066400000000000000000000522131354715574200175630ustar00rootroot00000000000000/* * HTTP address list routines for HTMLDOC. * * Copyright 2016-2017 by Michael R Sweet. * Copyright 2007-2016 by Apple Inc. * Copyright 1997-2007 by Easy Software Products, all rights reserved. * * This program is free software. Distribution and use rights are outlined in * the file "COPYING". */ /* * Include necessary headers... */ #include "http-private.h" #ifdef HAVE_RESOLV_H # include #endif /* HAVE_RESOLV_H */ #include #ifdef HAVE_POLL # include #endif /* HAVE_POLL */ #ifndef WIN32 # include #endif /* WIN32 */ /* * 'httpAddrConnect()' - Connect to any of the addresses in the list. * * @since CUPS 1.2/macOS 10.5@ */ http_addrlist_t * /* O - Connected address or NULL on failure */ httpAddrConnect( http_addrlist_t *addrlist, /* I - List of potential addresses */ int *sock) /* O - Socket */ { DEBUG_printf(("httpAddrConnect(addrlist=%p, sock=%p)", addrlist, sock)); return (httpAddrConnect2(addrlist, sock, 30000, NULL)); } /* * 'httpAddrConnect2()' - Connect to any of the addresses in the list with a * timeout and optional cancel. * * @since CUPS 1.7/macOS 10.9@ */ http_addrlist_t * /* O - Connected address or NULL on failure */ httpAddrConnect2( http_addrlist_t *addrlist, /* I - List of potential addresses */ int *sock, /* O - Socket */ int msec, /* I - Timeout in milliseconds */ int *cancel) /* I - Pointer to "cancel" variable */ { int val; /* Socket option value */ #ifndef WIN32 int flags; /* Socket flags */ #endif /* !WIN32 */ int remaining; /* Remaining timeout */ int i, /* Looping var */ nfds, /* Number of file descriptors */ fds[100], /* Socket file descriptors */ result; /* Result from select() or poll() */ http_addrlist_t *addrs[100]; /* Addresses */ #ifndef HAVE_POLL int max_fd = -1; /* Highest file descriptor */ #endif /* !HAVE_POLL */ #ifdef O_NONBLOCK # ifdef HAVE_POLL struct pollfd pfds[100]; /* Polled file descriptors */ # else fd_set input_set, /* select() input set */ output_set, /* select() output set */ error_set; /* select() error set */ struct timeval timeout; /* Timeout */ # endif /* HAVE_POLL */ #endif /* O_NONBLOCK */ #ifdef DEBUG socklen_t len; /* Length of value */ http_addr_t peer; /* Peer address */ #endif /* DEBUG */ DEBUG_printf(("httpAddrConnect2(addrlist=%p, sock=%p, msec=%d, cancel=%p)", (void *)addrlist, (void *)sock, msec, (void *)cancel)); if (!sock) { errno = EINVAL; _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(errno), 0); return (NULL); } if (cancel && *cancel) return (NULL); if (msec <= 0) msec = INT_MAX; /* * Loop through each address until we connect or run out of addresses... */ nfds = 0; remaining = msec; while (remaining > 0) { if (cancel && *cancel) { while (nfds > 0) { nfds --; httpAddrClose(NULL, fds[nfds]); } return (NULL); } if (addrlist && nfds < (int)(sizeof(fds) / sizeof(fds[0]))) { /* * Create the socket... */ DEBUG_printf(("2httpAddrConnect2: Trying %s:%d...", httpAddrString(&(addrlist->addr), temp, sizeof(temp)), httpAddrPort(&(addrlist->addr)))); if ((fds[nfds] = (int)socket(httpAddrFamily(&(addrlist->addr)), SOCK_STREAM, 0)) < 0) { /* * Don't abort yet, as this could just be an issue with the local * system not being configured with IPv4/IPv6/domain socket enabled. * * Just skip this address... */ addrlist = addrlist->next; continue; } /* * Set options... */ val = 1; setsockopt(fds[nfds], SOL_SOCKET, SO_REUSEADDR, CUPS_SOCAST &val, sizeof(val)); #ifdef SO_REUSEPORT val = 1; setsockopt(fds[nfds], SOL_SOCKET, SO_REUSEPORT, CUPS_SOCAST &val, sizeof(val)); #endif /* SO_REUSEPORT */ #ifdef SO_NOSIGPIPE val = 1; setsockopt(fds[nfds], SOL_SOCKET, SO_NOSIGPIPE, CUPS_SOCAST &val, sizeof(val)); #endif /* SO_NOSIGPIPE */ /* * Using TCP_NODELAY improves responsiveness, especially on systems * with a slow loopback interface... */ val = 1; setsockopt(fds[nfds], IPPROTO_TCP, TCP_NODELAY, CUPS_SOCAST &val, sizeof(val)); #ifdef FD_CLOEXEC /* * Close this socket when starting another process... */ fcntl(fds[nfds], F_SETFD, FD_CLOEXEC); #endif /* FD_CLOEXEC */ #ifdef O_NONBLOCK /* * Do an asynchronous connect by setting the socket non-blocking... */ DEBUG_printf(("httpAddrConnect2: Setting non-blocking connect()")); flags = fcntl(fds[nfds], F_GETFL, 0); fcntl(fds[nfds], F_SETFL, flags | O_NONBLOCK); #endif /* O_NONBLOCK */ /* * Then connect... */ if (!connect(fds[nfds], &(addrlist->addr.addr), (socklen_t)httpAddrLength(&(addrlist->addr)))) { DEBUG_printf(("1httpAddrConnect2: Connected to %s:%d...", httpAddrString(&(addrlist->addr), temp, sizeof(temp)), httpAddrPort(&(addrlist->addr)))); #ifdef O_NONBLOCK fcntl(fds[nfds], F_SETFL, flags); #endif /* O_NONBLOCK */ *sock = fds[nfds]; while (nfds > 0) { nfds --; httpAddrClose(NULL, fds[nfds]); } return (addrlist); } #ifdef WIN32 if (WSAGetLastError() != WSAEINPROGRESS && WSAGetLastError() != WSAEWOULDBLOCK) #else if (errno != EINPROGRESS && errno != EWOULDBLOCK) #endif /* WIN32 */ { DEBUG_printf(("1httpAddrConnect2: Unable to connect to %s:%d: %s", httpAddrString(&(addrlist->addr), temp, sizeof(temp)), httpAddrPort(&(addrlist->addr)), strerror(errno))); httpAddrClose(NULL, fds[nfds]); addrlist = addrlist->next; continue; } #ifndef WIN32 fcntl(fds[nfds], F_SETFL, flags); #endif /* !WIN32 */ #ifndef HAVE_POLL if (fds[nfds] > max_fd) max_fd = fds[nfds]; #endif /* !HAVE_POLL */ addrs[nfds] = addrlist; nfds ++; addrlist = addrlist->next; } if (!addrlist && nfds == 0) break; /* * See if we can connect to any of the addresses so far... */ #ifdef O_NONBLOCK DEBUG_puts("1httpAddrConnect2: Finishing async connect()"); do { if (cancel && *cancel) { /* * Close this socket and return... */ DEBUG_puts("1httpAddrConnect2: Canceled connect()"); while (nfds > 0) { nfds --; httpAddrClose(NULL, fds[nfds]); } *sock = -1; return (NULL); } # ifdef HAVE_POLL for (i = 0; i < nfds; i ++) { pfds[i].fd = fds[i]; pfds[i].events = POLLIN | POLLOUT; } result = poll(pfds, (nfds_t)nfds, addrlist ? 100 : remaining > 250 ? 250 : remaining); DEBUG_printf(("1httpAddrConnect2: poll() returned %d (%d)", result, errno)); # else FD_ZERO(&input_set); for (i = 0; i < nfds; i ++) FD_SET(fds[i], &input_set); output_set = input_set; error_set = input_set; timeout.tv_sec = 0; timeout.tv_usec = (addrlist ? 100 : remaining > 250 ? 250 : remaining) * 1000; result = select(max_fd + 1, &input_set, &output_set, &error_set, &timeout); DEBUG_printf(("1httpAddrConnect2: select() returned %d (%d)", result, errno)); # endif /* HAVE_POLL */ } # ifdef WIN32 while (result < 0 && (WSAGetLastError() == WSAEINTR || WSAGetLastError() == WSAEWOULDBLOCK)); # else while (result < 0 && (errno == EINTR || errno == EAGAIN)); # endif /* WIN32 */ if (result > 0) { http_addrlist_t *connaddr = NULL; /* Connected address, if any */ for (i = 0; i < nfds; i ++) { # ifdef HAVE_POLL DEBUG_printf(("pfds[%d].revents=%x\n", i, pfds[i].revents)); if (pfds[i].revents && !(pfds[i].revents & (POLLERR | POLLHUP))) # else if (FD_ISSET(fds[i], &input_set) && !FD_ISSET(fds[i], &error_set)) # endif /* HAVE_POLL */ { *sock = fds[i]; connaddr = addrs[i]; # ifdef DEBUG len = sizeof(peer); if (!getpeername(fds[i], (struct sockaddr *)&peer, &len)) DEBUG_printf(("1httpAddrConnect2: Connected to %s:%d...", httpAddrString(&peer, temp, sizeof(temp)), httpAddrPort(&peer))); # endif /* DEBUG */ } # ifdef HAVE_POLL else if (pfds[i].revents & (POLLERR | POLLHUP)) # else else if (FD_ISSET(fds[i], &error_set)) # endif /* HAVE_POLL */ { /* * Error on socket, remove from the "pool"... */ httpAddrClose(NULL, fds[i]); nfds --; if (i < nfds) { memmove(fds + i, fds + i + 1, (size_t)(nfds - i) * (sizeof(fds[0]))); memmove(addrs + i, addrs + i + 1, (size_t)(nfds - i) * (sizeof(addrs[0]))); } i --; } } if (connaddr) return (connaddr); } #endif /* O_NONBLOCK */ if (addrlist) remaining -= 100; else remaining -= 250; } while (nfds > 0) { nfds --; httpAddrClose(NULL, fds[nfds]); } #ifdef WIN32 _cupsSetError(IPP_STATUS_ERROR_SERVICE_UNAVAILABLE, "Connection failed", 0); #else _cupsSetError(IPP_STATUS_ERROR_SERVICE_UNAVAILABLE, strerror(errno), 0); #endif /* WIN32 */ return (NULL); } /* * 'httpAddrCopyList()' - Copy an address list. * * @since CUPS 1.7/macOS 10.9@ */ http_addrlist_t * /* O - New address list or @code NULL@ on error */ httpAddrCopyList( http_addrlist_t *src) /* I - Source address list */ { http_addrlist_t *dst = NULL, /* First list entry */ *prev = NULL, /* Previous list entry */ *current = NULL;/* Current list entry */ while (src) { if ((current = malloc(sizeof(http_addrlist_t))) == NULL) { current = dst; while (current) { prev = current; current = current->next; free(prev); } return (NULL); } memcpy(current, src, sizeof(http_addrlist_t)); current->next = NULL; if (prev) prev->next = current; else dst = current; prev = current; src = src->next; } return (dst); } /* * 'httpAddrFreeList()' - Free an address list. * * @since CUPS 1.2/macOS 10.5@ */ void httpAddrFreeList( http_addrlist_t *addrlist) /* I - Address list to free */ { http_addrlist_t *next; /* Next address in list */ /* * Free each address in the list... */ while (addrlist) { next = addrlist->next; free(addrlist); addrlist = next; } } /* * 'httpAddrGetList()' - Get a list of addresses for a hostname. * * @since CUPS 1.2/macOS 10.5@ */ http_addrlist_t * /* O - List of addresses or NULL */ httpAddrGetList(const char *hostname, /* I - Hostname, IP address, or NULL for passive listen address */ int family, /* I - Address family or AF_UNSPEC */ const char *service) /* I - Service name or port number */ { http_addrlist_t *first, /* First address in list */ *addr, /* Current address in list */ *temp; /* New address */ #ifdef DEBUG printf("httpAddrGetList(hostname=\"%s\", family=AF_%s, service=\"%s\")\n", hostname ? hostname : "(nil)", family == AF_UNSPEC ? "UNSPEC" : # ifdef AF_LOCAL family == AF_LOCAL ? "LOCAL" : # endif /* AF_LOCAL */ # ifdef AF_INET6 family == AF_INET6 ? "INET6" : # endif /* AF_INET6 */ family == AF_INET ? "INET" : "???", service); #endif /* DEBUG */ /* * Lookup the address the best way we can... */ first = addr = NULL; #ifdef AF_LOCAL if (hostname && hostname[0] == '/') { /* * Domain socket address... */ if ((first = (http_addrlist_t *)calloc(1, sizeof(http_addrlist_t))) != NULL) { addr = first; first->addr.un.sun_family = AF_LOCAL; strlcpy(first->addr.un.sun_path, hostname, sizeof(first->addr.un.sun_path)); } } else #endif /* AF_LOCAL */ if (!hostname || _cups_strcasecmp(hostname, "localhost")) { #ifdef HAVE_GETADDRINFO struct addrinfo hints, /* Address lookup hints */ *results, /* Address lookup results */ *current; /* Current result */ char ipv6[64], /* IPv6 address */ *ipv6zone; /* Pointer to zone separator */ int ipv6len; /* Length of IPv6 address */ int error; /* getaddrinfo() error */ /* * Lookup the address as needed... */ memset(&hints, 0, sizeof(hints)); hints.ai_family = family; hints.ai_flags = hostname ? 0 : AI_PASSIVE; hints.ai_socktype = SOCK_STREAM; if (hostname && *hostname == '[') { /* * Remove brackets from numeric IPv6 address... */ if (!strncmp(hostname, "[v1.", 4)) { /* * Copy the newer address format which supports link-local addresses... */ strlcpy(ipv6, hostname + 4, sizeof(ipv6)); if ((ipv6len = (int)strlen(ipv6) - 1) >= 0 && ipv6[ipv6len] == ']') { ipv6[ipv6len] = '\0'; hostname = ipv6; /* * Convert "+zone" in address to "%zone"... */ if ((ipv6zone = strrchr(ipv6, '+')) != NULL) *ipv6zone = '%'; } } else { /* * Copy the regular non-link-local IPv6 address... */ strlcpy(ipv6, hostname + 1, sizeof(ipv6)); if ((ipv6len = (int)strlen(ipv6) - 1) >= 0 && ipv6[ipv6len] == ']') { ipv6[ipv6len] = '\0'; hostname = ipv6; } } } if ((error = getaddrinfo(hostname, service, &hints, &results)) == 0) { /* * Copy the results to our own address list structure... */ for (current = results; current; current = current->ai_next) if (current->ai_family == AF_INET || current->ai_family == AF_INET6) { /* * Copy the address over... */ temp = (http_addrlist_t *)calloc(1, sizeof(http_addrlist_t)); if (!temp) { httpAddrFreeList(first); _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(errno), 0); return (NULL); } if (current->ai_family == AF_INET6) memcpy(&(temp->addr.ipv6), current->ai_addr, sizeof(temp->addr.ipv6)); else memcpy(&(temp->addr.ipv4), current->ai_addr, sizeof(temp->addr.ipv4)); /* * Append the address to the list... */ if (!first) first = temp; if (addr) addr->next = temp; addr = temp; } /* * Free the results from getaddrinfo()... */ freeaddrinfo(results); } else { _cupsSetError(IPP_STATUS_ERROR_INTERNAL, gai_strerror(error), 0); } #else if (hostname) { int i; /* Looping vars */ unsigned ip[4]; /* IPv4 address components */ const char *ptr; /* Pointer into hostname */ struct hostent *host; /* Result of lookup */ struct servent *port; /* Port number for service */ int portnum; /* Port number */ /* * Lookup the service... */ if (!service) portnum = 0; else if (isdigit(*service & 255)) portnum = atoi(service); else if ((port = getservbyname(service, NULL)) != NULL) portnum = ntohs(port->s_port); else if (!strcmp(service, "http")) portnum = 80; else if (!strcmp(service, "https")) portnum = 443; else if (!strcmp(service, "ipp") || !strcmp(service, "ipps")) portnum = 631; else if (!strcmp(service, "lpd")) portnum = 515; else if (!strcmp(service, "socket")) portnum = 9100; else return (NULL); /* * This code is needed because some operating systems have a * buggy implementation of gethostbyname() that does not support * IPv4 addresses. If the hostname string is an IPv4 address, then * sscanf() is used to extract the IPv4 components. We then pack * the components into an IPv4 address manually, since the * inet_aton() function is deprecated. We use the htonl() macro * to get the right byte order for the address. */ for (ptr = hostname; isdigit(*ptr & 255) || *ptr == '.'; ptr ++); if (!*ptr) { /* * We have an IPv4 address; break it up and create an IPv4 address... */ if (sscanf(hostname, "%u.%u.%u.%u", ip, ip + 1, ip + 2, ip + 3) == 4 && ip[0] <= 255 && ip[1] <= 255 && ip[2] <= 255 && ip[3] <= 255) { first = (http_addrlist_t *)calloc(1, sizeof(http_addrlist_t)); if (!first) return (NULL); first->addr.ipv4.sin_family = AF_INET; first->addr.ipv4.sin_addr.s_addr = htonl((((((((unsigned)ip[0] << 8) | (unsigned)ip[1]) << 8) | (unsigned)ip[2]) << 8) | (unsigned)ip[3])); first->addr.ipv4.sin_port = htons(portnum); } } else if ((host = gethostbyname(hostname)) != NULL && # ifdef AF_INET6 (host->h_addrtype == AF_INET || host->h_addrtype == AF_INET6)) # else host->h_addrtype == AF_INET) # endif /* AF_INET6 */ { for (i = 0; host->h_addr_list[i]; i ++) { /* * Copy the address over... */ temp = (http_addrlist_t *)calloc(1, sizeof(http_addrlist_t)); if (!temp) { httpAddrFreeList(first); return (NULL); } # ifdef AF_INET6 if (host->h_addrtype == AF_INET6) { temp->addr.ipv6.sin6_family = AF_INET6; memcpy(&(temp->addr.ipv6.sin6_addr), host->h_addr_list[i], sizeof(temp->addr.ipv6)); temp->addr.ipv6.sin6_port = htons(portnum); } else # endif /* AF_INET6 */ { temp->addr.ipv4.sin_family = AF_INET; memcpy(&(temp->addr.ipv4.sin_addr), host->h_addr_list[i], sizeof(temp->addr.ipv4)); temp->addr.ipv4.sin_port = htons(portnum); } /* * Append the address to the list... */ if (!first) first = temp; if (addr) addr->next = temp; addr = temp; } } else { if (h_errno == NO_RECOVERY) cg->need_res_init = 1; _cupsSetError(IPP_STATUS_ERROR_INTERNAL, hstrerror(h_errno), 0); } } #endif /* HAVE_GETADDRINFO */ } /* * Detect some common errors and handle them sanely... */ if (!addr && (!hostname || !_cups_strcasecmp(hostname, "localhost"))) { struct servent *port; /* Port number for service */ int portnum; /* Port number */ /* * Lookup the service... */ if (!service) portnum = 0; else if (isdigit(*service & 255)) portnum = atoi(service); else if ((port = getservbyname(service, NULL)) != NULL) portnum = ntohs(port->s_port); else if (!strcmp(service, "http")) portnum = 80; else if (!strcmp(service, "https")) portnum = 443; else if (!strcmp(service, "ipp") || !strcmp(service, "ipps")) portnum = 631; else if (!strcmp(service, "lpd")) portnum = 515; else if (!strcmp(service, "socket")) portnum = 9100; else { httpAddrFreeList(first); _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Unknown service name."), 1); return (NULL); } if (hostname && !_cups_strcasecmp(hostname, "localhost")) { /* * Unfortunately, some users ignore all of the warnings in the * /etc/hosts file and delete "localhost" from it. If we get here * then we were unable to resolve the name, so use the IPv6 and/or * IPv4 loopback interface addresses... */ #ifdef AF_INET6 if (family != AF_INET) { /* * Add [::1] to the address list... */ temp = (http_addrlist_t *)calloc(1, sizeof(http_addrlist_t)); if (!temp) { _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(errno), 0); httpAddrFreeList(first); return (NULL); } temp->addr.ipv6.sin6_family = AF_INET6; temp->addr.ipv6.sin6_port = htons(portnum); # ifdef WIN32 temp->addr.ipv6.sin6_addr.u.Byte[15] = 1; # else temp->addr.ipv6.sin6_addr.s6_addr32[3] = htonl(1); # endif /* WIN32 */ if (!first) first = temp; addr = temp; } if (family != AF_INET6) #endif /* AF_INET6 */ { /* * Add 127.0.0.1 to the address list... */ temp = (http_addrlist_t *)calloc(1, sizeof(http_addrlist_t)); if (!temp) { _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(errno), 0); httpAddrFreeList(first); return (NULL); } temp->addr.ipv4.sin_family = AF_INET; temp->addr.ipv4.sin_port = htons(portnum); temp->addr.ipv4.sin_addr.s_addr = htonl(0x7f000001); if (!first) first = temp; if (addr) addr->next = temp; } } else if (!hostname) { /* * Provide one or more passive listening addresses... */ #ifdef AF_INET6 if (family != AF_INET) { /* * Add [::] to the address list... */ temp = (http_addrlist_t *)calloc(1, sizeof(http_addrlist_t)); if (!temp) { _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(errno), 0); httpAddrFreeList(first); return (NULL); } temp->addr.ipv6.sin6_family = AF_INET6; temp->addr.ipv6.sin6_port = htons(portnum); if (!first) first = temp; addr = temp; } if (family != AF_INET6) #endif /* AF_INET6 */ { /* * Add 0.0.0.0 to the address list... */ temp = (http_addrlist_t *)calloc(1, sizeof(http_addrlist_t)); if (!temp) { _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(errno), 0); httpAddrFreeList(first); return (NULL); } temp->addr.ipv4.sin_family = AF_INET; temp->addr.ipv4.sin_port = htons(portnum); if (!first) first = temp; if (addr) addr->next = temp; } } } /* * Return the address list... */ return (first); } htmldoc-1.9.7/htmldoc/http-private.h000066400000000000000000000370431354715574200174400ustar00rootroot00000000000000/* * Private HTTP definitions for HTMLDOC. * * Copyright 2016-2017 by Michael R Sweet. * Copyright 2007-2016 by Apple Inc. * Copyright 1997-2007 by Easy Software Products, all rights reserved. * * This program is free software. Distribution and use rights are outlined in * the file "COPYING". */ #ifndef _CUPS_HTTP_PRIVATE_H_ # define _CUPS_HTTP_PRIVATE_H_ /* * Include necessary headers... */ # include "hdstring.h" # include # include # include # ifdef __sun # include # endif /* __sun */ # include # ifdef WIN32 # include # include # define CUPS_SOCAST (const char *) # else # include # include # include # define CUPS_SOCAST # endif /* WIN32 */ # ifdef HAVE_GSSAPI # ifdef HAVE_GSS_GSSAPI_H # include # elif defined(HAVE_GSSAPI_GSSAPI_H) # include # elif defined(HAVE_GSSAPI_H) # include # endif /* HAVE_GSS_GSSAPI_H */ # ifndef HAVE_GSS_C_NT_HOSTBASED_SERVICE # define GSS_C_NT_HOSTBASED_SERVICE gss_nt_service_name # endif /* !HAVE_GSS_C_NT_HOSTBASED_SERVICE */ # endif /* HAVE_GSSAPI */ # ifdef HAVE_AUTHORIZATION_H # include # endif /* HAVE_AUTHORIZATION_H */ # if defined(__APPLE__) && !defined(_SOCKLEN_T) /* * macOS 10.2.x does not define socklen_t, and in fact uses an int instead of * unsigned type for length values... */ typedef int socklen_t; # endif /* __APPLE__ && !_SOCKLEN_T */ # include "http.h" # include "md5-private.h" # ifdef HAVE_GNUTLS # include # include # elif defined(HAVE_CDSASSL) # include # include # include # ifdef HAVE_SECURETRANSPORTPRIV_H # include # endif /* HAVE_SECURETRANSPORTPRIV_H */ # ifdef HAVE_SECITEM_H # include # endif /* HAVE_SECITEM_H */ # ifdef HAVE_SECBASEPRIV_H # include # endif /* HAVE_SECBASEPRIV_H */ # ifdef HAVE_SECCERTIFICATE_H # include # include # endif /* HAVE_SECCERTIFICATE_H */ # ifdef HAVE_SECCERTIFICATEPRIV_H # include # else # ifdef __cplusplus extern "C" { # endif /* __cplusplus */ # ifndef _SECURITY_VERSION_GREATER_THAN_57610_ typedef CF_OPTIONS(uint32_t, SecKeyUsage) { kSecKeyUsageAll = 0x7FFFFFFF }; # endif /* !_SECURITY_VERSION_GREATER_THAN_57610_ */ extern const void * kSecCSRChallengePassword; extern const void * kSecSubjectAltName; extern const void * kSecCertificateKeyUsage; extern const void * kSecCSRBasicContraintsPathLen; extern const void * kSecCertificateExtensions; extern const void * kSecCertificateExtensionsEncoded; extern const void * kSecOidCommonName; extern const void * kSecOidCountryName; extern const void * kSecOidStateProvinceName; extern const void * kSecOidLocalityName; extern const void * kSecOidOrganization; extern const void * kSecOidOrganizationalUnit; extern SecCertificateRef SecCertificateCreateWithBytes(CFAllocatorRef allocator, const UInt8 *bytes, CFIndex length); extern bool SecCertificateIsValid(SecCertificateRef certificate, CFAbsoluteTime verifyTime); extern CFAbsoluteTime SecCertificateNotValidAfter(SecCertificateRef certificate); extern SecCertificateRef SecGenerateSelfSignedCertificate(CFArrayRef subject, CFDictionaryRef parameters, SecKeyRef publicKey, SecKeyRef privateKey); extern SecIdentityRef SecIdentityCreate(CFAllocatorRef allocator, SecCertificateRef certificate, SecKeyRef privateKey); # ifdef __cplusplus } # endif /* __cplusplus */ # endif /* HAVE_SECCERTIFICATEPRIV_H */ # ifdef HAVE_SECITEMPRIV_H # include # endif /* HAVE_SECITEMPRIV_H */ # ifdef HAVE_SECIDENTITYSEARCHPRIV_H # include # endif /* HAVE_SECIDENTITYSEARCHPRIV_H */ # ifdef HAVE_SECPOLICYPRIV_H # include # endif /* HAVE_SECPOLICYPRIV_H */ # elif defined(HAVE_SSPISSL) # include # include # include # define SECURITY_WIN32 # include # include # endif /* HAVE_GNUTLS */ # ifndef WIN32 # include # include # ifdef HAVE_GETIFADDRS # include # else # include # ifdef HAVE_SYS_SOCKIO_H # include # endif /* HAVE_SYS_SOCKIO_H */ # endif /* HAVE_GETIFADDRS */ # endif /* !WIN32 */ # ifdef HAVE_LIBZ # include # endif /* HAVE_LIBZ */ /* * Stuff that CUPS normally provides... */ # ifndef DEBUG_printf # define DEBUG_printf(x) # define DEBUG_puts(x) # endif /* !DEBUG_printf */ # define _(x) x # define _cups_isalnum(ch) isalnum((ch) & 255) # define _cups_isspace(ch) isspace((ch) & 255) # ifdef WIN32 # define _cups_strcasecmp(s,t) stricmp(s,t) # define _cups_strncasecmp(s,t,n) strnicmp(s,t,n) # else # define _cups_strcasecmp(s,t) strcasecmp(s,t) # define _cups_strncasecmp(s,t,n) strncasecmp(s,t,n) # endif /* WIN32 */ # define _cupsGlobalLock() # define _cupsGlobalUnlock() # define _cupsSetError(x,y,z) # define _cupsSetHTTPError(x) /* * C++ magic... */ # ifdef __cplusplus extern "C" { # endif /* __cplusplus */ /* * Constants... */ #define _HTTP_MAX_SBUFFER 65536 /* Size of (de)compression buffer */ #define _HTTP_RESOLVE_DEFAULT 0 /* Just resolve with default options */ #define _HTTP_RESOLVE_STDERR 1 /* Log resolve progress to stderr */ #define _HTTP_RESOLVE_FQDN 2 /* Resolve to a FQDN */ #define _HTTP_RESOLVE_FAXOUT 4 /* Resolve FaxOut service? */ #define _HTTP_TLS_NONE 0 /* No TLS options */ #define _HTTP_TLS_ALLOW_RC4 1 /* Allow RC4 cipher suites */ #define _HTTP_TLS_ALLOW_SSL3 2 /* Allow SSL 3.0 */ #define _HTTP_TLS_ALLOW_DH 4 /* Allow DH/DHE key negotiation */ #define _HTTP_TLS_DENY_TLS10 16 /* Deny TLS 1.0 */ /* * Types and functions for SSL support... */ # ifdef HAVE_GNUTLS /* * The GNU TLS library is more of a "bare metal" SSL/TLS library... */ typedef gnutls_session_t http_tls_t; typedef gnutls_certificate_credentials_t *http_tls_credentials_t; # elif defined(HAVE_CDSASSL) /* * Darwin's Security framework provides its own SSL/TLS context structure * for its IO and protocol management... */ # if !defined(HAVE_SECBASEPRIV_H) && defined(HAVE_CSSMERRORSTRING) /* Declare prototype for function in that header... */ extern const char *cssmErrorString(int error); # endif /* !HAVE_SECBASEPRIV_H && HAVE_CSSMERRORSTRING */ # if !defined(HAVE_SECIDENTITYSEARCHPRIV_H) && defined(HAVE_SECIDENTITYSEARCHCREATEWITHPOLICY) /* Declare prototype for function in that header... */ extern OSStatus SecIdentitySearchCreateWithPolicy(SecPolicyRef policy, CFStringRef idString, CSSM_KEYUSE keyUsage, CFTypeRef keychainOrArray, Boolean returnOnlyValidIdentities, SecIdentitySearchRef* searchRef); # endif /* !HAVE_SECIDENTITYSEARCHPRIV_H && HAVE_SECIDENTITYSEARCHCREATEWITHPOLICY */ # if !defined(HAVE_SECPOLICYPRIV_H) && defined(HAVE_SECPOLICYSETVALUE) /* Declare prototype for function in that header... */ extern OSStatus SecPolicySetValue(SecPolicyRef policyRef, const CSSM_DATA *value); # endif /* !HAVE_SECPOLICYPRIV_H && HAVE_SECPOLICYSETVALUE */ typedef SSLContextRef http_tls_t; typedef CFArrayRef http_tls_credentials_t; # elif defined(HAVE_SSPISSL) /* * Windows' SSPI library gets a CUPS wrapper... */ typedef struct _http_sspi_s /**** SSPI/SSL data structure ****/ { CredHandle creds; /* Credentials */ CtxtHandle context; /* SSL context */ BOOL contextInitialized; /* Is context init'd? */ SecPkgContext_StreamSizes streamSizes;/* SSL data stream sizes */ BYTE *decryptBuffer; /* Data pre-decryption*/ size_t decryptBufferLength; /* Length of decrypt buffer */ size_t decryptBufferUsed; /* Bytes used in buffer */ BYTE *readBuffer; /* Data post-decryption */ int readBufferLength; /* Length of read buffer */ int readBufferUsed; /* Bytes used in buffer */ BYTE *writeBuffer; /* Data pre-encryption */ int writeBufferLength; /* Length of write buffer */ PCCERT_CONTEXT localCert, /* Local certificate */ remoteCert; /* Remote (peer's) certificate */ char error[256]; /* Most recent error message */ } _http_sspi_t; typedef _http_sspi_t *http_tls_t; typedef PCCERT_CONTEXT http_tls_credentials_t; # else /* * Otherwise define stub types since we have no SSL support... */ typedef void *http_tls_t; typedef void *http_tls_credentials_t; # endif /* HAVE_GNUTLS */ typedef enum _http_coding_e /**** HTTP content coding enumeration ****/ { _HTTP_CODING_IDENTITY, /* No content coding */ _HTTP_CODING_GZIP, /* LZ77+gzip decompression */ _HTTP_CODING_DEFLATE, /* LZ77+zlib compression */ _HTTP_CODING_GUNZIP, /* LZ77+gzip decompression */ _HTTP_CODING_INFLATE /* LZ77+zlib decompression */ } _http_coding_t; typedef enum _http_mode_e /**** HTTP mode enumeration ****/ { _HTTP_MODE_CLIENT, /* Client connected to server */ _HTTP_MODE_SERVER /* Server connected (accepted) from client */ } _http_mode_t; # ifndef _HTTP_NO_PRIVATE struct _http_s /**** HTTP connection structure ****/ { int fd; /* File descriptor for this socket */ int blocking; /* To block or not to block */ int error; /* Last error on read */ time_t activity; /* Time since last read/write */ http_state_t state; /* State of client */ http_status_t status; /* Status of last request */ http_version_t version; /* Protocol version */ http_keepalive_t keep_alive; /* Keep-alive supported? */ struct sockaddr_in _hostaddr; /* Address of connected host (deprecated) */ char hostname[HTTP_MAX_HOST], /* Name of connected host */ fields[HTTP_FIELD_ACCEPT_ENCODING][HTTP_MAX_VALUE]; /* Field values up to Accept-Encoding */ char *data; /* Pointer to data buffer */ http_encoding_t data_encoding; /* Chunked or not */ int _data_remaining;/* Number of bytes left (deprecated) */ int used; /* Number of bytes used in buffer */ char buffer[HTTP_MAX_BUFFER]; /* Buffer for incoming data */ int _auth_type; /* Authentication in use (deprecated) */ _cups_md5_state_t md5_state; /* MD5 state */ char nonce[HTTP_MAX_VALUE]; /* Nonce value */ int nonce_count; /* Nonce count */ http_tls_t tls; /* TLS state information */ http_encryption_t encryption; /* Encryption requirements */ /**** New in CUPS 1.1.19 ****/ fd_set *input_set; /* select() set for httpWait() (deprecated) */ http_status_t expect; /* Expect: header */ char *cookie; /* Cookie value(s) */ /**** New in CUPS 1.1.20 ****/ char _authstring[HTTP_MAX_VALUE], /* Current Authorization value (deprecated) */ userpass[HTTP_MAX_VALUE]; /* Username:password string */ int digest_tries; /* Number of tries for digest auth */ /**** New in CUPS 1.2 ****/ off_t data_remaining; /* Number of bytes left */ http_addr_t *hostaddr; /* Current host address and port */ http_addrlist_t *addrlist; /* List of valid addresses */ char wbuffer[HTTP_MAX_BUFFER]; /* Buffer for outgoing data */ int wused; /* Write buffer bytes used */ /**** New in CUPS 1.3 ****/ char *field_authorization; /* Authorization field */ char *authstring; /* Current Authorization field */ # ifdef HAVE_GSSAPI gss_OID gssmech; /* Authentication mechanism */ gss_ctx_id_t gssctx; /* Authentication context */ gss_name_t gssname; /* Authentication server name */ # endif /* HAVE_GSSAPI */ # ifdef HAVE_AUTHORIZATION_H AuthorizationRef auth_ref; /* Authorization ref */ # endif /* HAVE_AUTHORIZATION_H */ /**** New in CUPS 1.5 ****/ http_tls_credentials_t tls_credentials; /* TLS credentials */ http_timeout_cb_t timeout_cb; /* Timeout callback */ void *timeout_data; /* User data pointer */ double timeout_value; /* Timeout in seconds */ int wait_value; /* httpWait value for timeout */ # ifdef HAVE_GSSAPI char gsshost[256]; /* Hostname for Kerberos */ # endif /* HAVE_GSSAPI */ /**** New in CUPS 1.7 ****/ int tls_upgrade; /* Non-zero if we are doing an upgrade */ _http_mode_t mode; /* _HTTP_MODE_CLIENT or _HTTP_MODE_SERVER */ char *accept_encoding, /* Accept-Encoding field */ *allow, /* Allow field */ *server, /* Server field */ *default_accept_encoding, *default_server, *default_user_agent; /* Default field values */ # ifdef HAVE_LIBZ _http_coding_t coding; /* _HTTP_CODING_xxx */ z_stream stream; /* (De)compression stream */ Bytef *sbuffer; /* (De)compression buffer */ # endif /* HAVE_LIBZ */ }; # endif /* !_HTTP_NO_PRIVATE */ /* * Some OS's don't have hstrerror(), most notably Solaris... */ # ifndef HAVE_HSTRERROR extern const char *_cups_hstrerror(int error); # define hstrerror _cups_hstrerror # endif /* !HAVE_HSTRERROR */ /* * Some OS's don't have getifaddrs() and freeifaddrs()... */ # if !defined(WIN32) && !defined(HAVE_GETIFADDRS) # ifdef ifa_dstaddr # undef ifa_dstaddr # endif /* ifa_dstaddr */ # ifndef ifr_netmask # define ifr_netmask ifr_addr # endif /* !ifr_netmask */ struct ifaddrs /**** Interface Structure ****/ { struct ifaddrs *ifa_next; /* Next interface in list */ char *ifa_name; /* Name of interface */ unsigned int ifa_flags; /* Flags (up, point-to-point, etc.) */ struct sockaddr *ifa_addr, /* Network address */ *ifa_netmask; /* Address mask */ union { struct sockaddr *ifu_broadaddr; /* Broadcast address of this interface. */ struct sockaddr *ifu_dstaddr; /* Point-to-point destination address. */ } ifa_ifu; void *ifa_data; /* Interface statistics */ }; # ifndef ifa_broadaddr # define ifa_broadaddr ifa_ifu.ifu_broadaddr # endif /* !ifa_broadaddr */ # ifndef ifa_dstaddr # define ifa_dstaddr ifa_ifu.ifu_dstaddr # endif /* !ifa_dstaddr */ extern int _cups_getifaddrs(struct ifaddrs **addrs); # define getifaddrs _cups_getifaddrs extern void _cups_freeifaddrs(struct ifaddrs *addrs); # define freeifaddrs _cups_freeifaddrs # endif /* !WIN32 && !HAVE_GETIFADDRS */ /* * Prototypes... */ extern void _httpAddrSetPort(http_addr_t *addr, int port); extern http_tls_credentials_t _httpCreateCredentials(cups_array_t *credentials); extern char *_httpDecodeURI(char *dst, const char *src, size_t dstsize); extern void _httpDisconnect(http_t *http); extern char *_httpEncodeURI(char *dst, const char *src, size_t dstsize); extern void _httpFreeCredentials(http_tls_credentials_t credentials); extern const char *_httpResolveURI(const char *uri, char *resolved_uri, size_t resolved_size, int options, int (*cb)(void *context), void *context); //extern const char *_httpStatus(cups_lang_t *lang, http_status_t status); extern void _httpTLSInitialize(void); extern size_t _httpTLSPending(http_t *http); extern int _httpTLSRead(http_t *http, char *buf, int len); extern int _httpTLSSetCredentials(http_t *http); extern void _httpTLSSetOptions(int options); extern int _httpTLSStart(http_t *http); extern void _httpTLSStop(http_t *http); extern int _httpTLSWrite(http_t *http, const char *buf, int len); extern int _httpUpdate(http_t *http, http_status_t *status); extern int _httpWait(http_t *http, int msec, int usessl); /* * C++ magic... */ # ifdef __cplusplus } # endif /* __cplusplus */ #endif /* !_CUPS_HTTP_PRIVATE_H_ */ htmldoc-1.9.7/htmldoc/http-support.c000066400000000000000000001713001354715574200174700ustar00rootroot00000000000000/* * HTTP support routines for HTMLDOC. * * Copyright 2016-2017 by Michael R Sweet. * Copyright 2007-2016 by Apple Inc. * Copyright 1997-2007 by Easy Software Products, all rights reserved. * * This program is free software. Distribution and use rights are outlined in * the file "COPYING". */ /* * Include necessary headers... */ #include "http-private.h" #include #ifdef HAVE_DNSSD # include # ifdef WIN32 # include # elif defined(HAVE_POLL) # include # else # include # endif /* WIN32 */ #elif defined(HAVE_AVAHI) # include # include # include #endif /* HAVE_DNSSD */ /* * Local types... */ typedef struct _http_uribuf_s /* URI buffer */ { #ifdef HAVE_AVAHI AvahiSimplePoll *poll; /* Poll state */ #endif /* HAVE_AVAHI */ char *buffer; /* Pointer to buffer */ size_t bufsize; /* Size of buffer */ int options; /* Options passed to _httpResolveURI */ const char *resource; /* Resource from URI */ const char *uuid; /* UUID from URI */ } _http_uribuf_t; /* * Local globals... */ static const char * const http_days[7] =/* Days of the week */ { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" }; static const char * const http_months[12] = { /* Months of the year */ "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; static const char * const http_states[] = { /* HTTP state strings */ "HTTP_STATE_ERROR", "HTTP_STATE_WAITING", "HTTP_STATE_OPTIONS", "HTTP_STATE_GET", "HTTP_STATE_GET_SEND", "HTTP_STATE_HEAD", "HTTP_STATE_POST", "HTTP_STATE_POST_RECV", "HTTP_STATE_POST_SEND", "HTTP_STATE_PUT", "HTTP_STATE_PUT_RECV", "HTTP_STATE_DELETE", "HTTP_STATE_TRACE", "HTTP_STATE_CONNECT", "HTTP_STATE_STATUS", "HTTP_STATE_UNKNOWN_METHOD", "HTTP_STATE_UNKNOWN_VERSION" }; /* * Local functions... */ static const char *http_copy_decode(char *dst, const char *src, int dstsize, const char *term, int decode); static char *http_copy_encode(char *dst, const char *src, char *dstend, const char *reserved, const char *term, int encode); #ifdef HAVE_DNSSD static void DNSSD_API http_resolve_cb(DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex, DNSServiceErrorType errorCode, const char *fullName, const char *hostTarget, uint16_t port, uint16_t txtLen, const unsigned char *txtRecord, void *context); #endif /* HAVE_DNSSD */ #ifdef HAVE_AVAHI static void http_client_cb(AvahiClient *client, AvahiClientState state, void *simple_poll); static int http_poll_cb(struct pollfd *pollfds, unsigned int num_pollfds, int timeout, void *context); static void http_resolve_cb(AvahiServiceResolver *resolver, AvahiIfIndex interface, AvahiProtocol protocol, AvahiResolverEvent event, const char *name, const char *type, const char *domain, const char *host_name, const AvahiAddress *address, uint16_t port, AvahiStringList *txt, AvahiLookupResultFlags flags, void *context); #endif /* HAVE_AVAHI */ /* * 'httpAssembleURI()' - Assemble a uniform resource identifier from its * components. * * This function escapes reserved characters in the URI depending on the * value of the "encoding" argument. You should use this function in * place of traditional string functions whenever you need to create a * URI string. * * @since CUPS 1.2/macOS 10.5@ */ http_uri_status_t /* O - URI status */ httpAssembleURI( http_uri_coding_t encoding, /* I - Encoding flags */ char *uri, /* I - URI buffer */ int urilen, /* I - Size of URI buffer */ const char *scheme, /* I - Scheme name */ const char *username, /* I - Username */ const char *host, /* I - Hostname or address */ int port, /* I - Port number */ const char *resource) /* I - Resource */ { char *ptr, /* Pointer into URI buffer */ *end; /* End of URI buffer */ /* * Range check input... */ if (!uri || urilen < 1 || !scheme || port < 0) { if (uri) *uri = '\0'; return (HTTP_URI_STATUS_BAD_ARGUMENTS); } /* * Assemble the URI starting with the scheme... */ end = uri + urilen - 1; ptr = http_copy_encode(uri, scheme, end, NULL, NULL, 0); if (!ptr) goto assemble_overflow; if (!strcmp(scheme, "geo") || !strcmp(scheme, "mailto") || !strcmp(scheme, "tel")) { /* * geo:, mailto:, and tel: only have :, no //... */ if (ptr < end) *ptr++ = ':'; else goto assemble_overflow; } else { /* * Schemes other than geo:, mailto:, and tel: typically have //... */ if ((ptr + 2) < end) { *ptr++ = ':'; *ptr++ = '/'; *ptr++ = '/'; } else goto assemble_overflow; } /* * Next the username and hostname, if any... */ if (host) { const char *hostptr; /* Pointer into hostname */ int have_ipv6; /* Do we have an IPv6 address? */ if (username && *username) { /* * Add username@ first... */ ptr = http_copy_encode(ptr, username, end, "/?#[]@", NULL, encoding & HTTP_URI_CODING_USERNAME); if (!ptr) goto assemble_overflow; if (ptr < end) *ptr++ = '@'; else goto assemble_overflow; } /* * Then add the hostname. Since IPv6 is a particular pain to deal * with, we have several special cases to deal with. If we get * an IPv6 address with brackets around it, assume it is already in * URI format. Since DNS-SD service names can sometimes look like * raw IPv6 addresses, we specifically look for "._tcp" in the name, * too... */ for (hostptr = host, have_ipv6 = strchr(host, ':') && !strstr(host, "._tcp"); *hostptr && have_ipv6; hostptr ++) if (*hostptr != ':' && !isxdigit(*hostptr & 255)) { have_ipv6 = *hostptr == '%'; break; } if (have_ipv6) { /* * We have a raw IPv6 address... */ if (strchr(host, '%') && !(encoding & HTTP_URI_CODING_RFC6874)) { /* * We have a link-local address, add "[v1." prefix... */ if ((ptr + 4) < end) { *ptr++ = '['; *ptr++ = 'v'; *ptr++ = '1'; *ptr++ = '.'; } else goto assemble_overflow; } else { /* * We have a normal (or RFC 6874 link-local) address, add "[" prefix... */ if (ptr < end) *ptr++ = '['; else goto assemble_overflow; } /* * Copy the rest of the IPv6 address, and terminate with "]". */ while (ptr < end && *host) { if (*host == '%') { /* * Convert/encode zone separator */ if (encoding & HTTP_URI_CODING_RFC6874) { if (ptr >= (end - 2)) goto assemble_overflow; *ptr++ = '%'; *ptr++ = '2'; *ptr++ = '5'; } else *ptr++ = '+'; host ++; } else *ptr++ = *host++; } if (*host) goto assemble_overflow; if (ptr < end) *ptr++ = ']'; else goto assemble_overflow; } else { /* * Otherwise, just copy the host string (the extra chars are not in the * "reg-name" ABNF rule; anything <= SP or >= DEL plus % gets automatically * percent-encoded. */ ptr = http_copy_encode(ptr, host, end, "\"#/:<>?@[\\]^`{|}", NULL, encoding & HTTP_URI_CODING_HOSTNAME); if (!ptr) goto assemble_overflow; } /* * Finish things off with the port number... */ if (port > 0) { snprintf(ptr, (size_t)(end - ptr + 1), ":%d", port); ptr += strlen(ptr); if (ptr >= end) goto assemble_overflow; } } /* * Last but not least, add the resource string... */ if (resource) { char *query; /* Pointer to query string */ /* * Copy the resource string up to the query string if present... */ query = strchr(resource, '?'); ptr = http_copy_encode(ptr, resource, end, NULL, "?", encoding & HTTP_URI_CODING_RESOURCE); if (!ptr) goto assemble_overflow; if (query) { /* * Copy query string without encoding... */ ptr = http_copy_encode(ptr, query, end, NULL, NULL, encoding & HTTP_URI_CODING_QUERY); if (!ptr) goto assemble_overflow; } } else if (ptr < end) *ptr++ = '/'; else goto assemble_overflow; /* * Nul-terminate the URI buffer and return with no errors... */ *ptr = '\0'; return (HTTP_URI_STATUS_OK); /* * Clear the URI string and return an overflow error; I don't usually * like goto's, but in this case it makes sense... */ assemble_overflow: *uri = '\0'; return (HTTP_URI_STATUS_OVERFLOW); } /* * 'httpAssembleURIf()' - Assemble a uniform resource identifier from its * components with a formatted resource. * * This function creates a formatted version of the resource string * argument "resourcef" and escapes reserved characters in the URI * depending on the value of the "encoding" argument. You should use * this function in place of traditional string functions whenever * you need to create a URI string. * * @since CUPS 1.2/macOS 10.5@ */ http_uri_status_t /* O - URI status */ httpAssembleURIf( http_uri_coding_t encoding, /* I - Encoding flags */ char *uri, /* I - URI buffer */ int urilen, /* I - Size of URI buffer */ const char *scheme, /* I - Scheme name */ const char *username, /* I - Username */ const char *host, /* I - Hostname or address */ int port, /* I - Port number */ const char *resourcef, /* I - Printf-style resource */ ...) /* I - Additional arguments as needed */ { va_list ap; /* Pointer to additional arguments */ char resource[1024]; /* Formatted resource string */ int bytes; /* Bytes in formatted string */ /* * Range check input... */ if (!uri || urilen < 1 || !scheme || port < 0 || !resourcef) { if (uri) *uri = '\0'; return (HTTP_URI_STATUS_BAD_ARGUMENTS); } /* * Format the resource string and assemble the URI... */ va_start(ap, resourcef); bytes = vsnprintf(resource, sizeof(resource), resourcef, ap); va_end(ap); if ((size_t)bytes >= sizeof(resource)) { *uri = '\0'; return (HTTP_URI_STATUS_OVERFLOW); } else return (httpAssembleURI(encoding, uri, urilen, scheme, username, host, port, resource)); } /* * 'httpAssembleUUID()' - Assemble a name-based UUID URN conforming to RFC 4122. * * This function creates a unique 128-bit identifying number using the server * name, port number, random data, and optionally an object name and/or object * number. The result is formatted as a UUID URN as defined in RFC 4122. * * The buffer needs to be at least 46 bytes in size. * * @since CUPS 1.7/macOS 10.9@ */ char * /* I - UUID string */ httpAssembleUUID(const char *server, /* I - Server name */ int port, /* I - Port number */ const char *name, /* I - Object name or NULL */ int number, /* I - Object number or 0 */ char *buffer, /* I - String buffer */ size_t bufsize) /* I - Size of buffer */ { char data[1024]; /* Source string for MD5 */ _cups_md5_state_t md5state; /* MD5 state */ unsigned char md5sum[16]; /* MD5 digest/sum */ /* * Build a version 3 UUID conforming to RFC 4122. * * Start with the MD5 sum of the server, port, object name and * number, and some random data on the end. */ snprintf(data, sizeof(data), "%s:%d:%s:%d:%04x:%04x", server, port, name ? name : server, number, (unsigned)HTMLDOC_RAND() & 0xffff, (unsigned)HTMLDOC_RAND() & 0xffff); _cupsMD5Init(&md5state); _cupsMD5Append(&md5state, (unsigned char *)data, (int)strlen(data)); _cupsMD5Finish(&md5state, md5sum); /* * Generate the UUID from the MD5... */ snprintf(buffer, bufsize, "urn:uuid:%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-" "%02x%02x%02x%02x%02x%02x", md5sum[0], md5sum[1], md5sum[2], md5sum[3], md5sum[4], md5sum[5], (md5sum[6] & 15) | 0x30, md5sum[7], (md5sum[8] & 0x3f) | 0x40, md5sum[9], md5sum[10], md5sum[11], md5sum[12], md5sum[13], md5sum[14], md5sum[15]); return (buffer); } /* * 'httpDecode64()' - Base64-decode a string. * * This function is deprecated. Use the httpDecode64_2() function instead * which provides buffer length arguments. * * @deprecated@ */ char * /* O - Decoded string */ httpDecode64(char *out, /* I - String to write to */ const char *in) /* I - String to read from */ { int outlen; /* Output buffer length */ /* * Use the old maximum buffer size for binary compatibility... */ outlen = 512; return (httpDecode64_2(out, &outlen, in)); } /* * 'httpDecode64_2()' - Base64-decode a string. * * @since CUPS 1.1.21/macOS 10.4@ */ char * /* O - Decoded string */ httpDecode64_2(char *out, /* I - String to write to */ int *outlen, /* IO - Size of output string */ const char *in) /* I - String to read from */ { int pos; /* Bit position */ unsigned base64; /* Value of this character */ char *outptr, /* Output pointer */ *outend; /* End of output buffer */ /* * Range check input... */ if (!out || !outlen || *outlen < 1 || !in) return (NULL); if (!*in) { *out = '\0'; *outlen = 0; return (out); } /* * Convert from base-64 to bytes... */ for (outptr = out, outend = out + *outlen - 1, pos = 0; *in != '\0'; in ++) { /* * Decode this character into a number from 0 to 63... */ if (*in >= 'A' && *in <= 'Z') base64 = (unsigned)(*in - 'A'); else if (*in >= 'a' && *in <= 'z') base64 = (unsigned)(*in - 'a' + 26); else if (*in >= '0' && *in <= '9') base64 = (unsigned)(*in - '0' + 52); else if (*in == '+') base64 = 62; else if (*in == '/') base64 = 63; else if (*in == '=') break; else continue; /* * Store the result in the appropriate chars... */ switch (pos) { case 0 : if (outptr < outend) *outptr = (char)(base64 << 2); pos ++; break; case 1 : if (outptr < outend) *outptr++ |= (char)((base64 >> 4) & 3); if (outptr < outend) *outptr = (char)((base64 << 4) & 255); pos ++; break; case 2 : if (outptr < outend) *outptr++ |= (char)((base64 >> 2) & 15); if (outptr < outend) *outptr = (char)((base64 << 6) & 255); pos ++; break; case 3 : if (outptr < outend) *outptr++ |= (char)base64; pos = 0; break; } } *outptr = '\0'; /* * Return the decoded string and size... */ *outlen = (int)(outptr - out); return (out); } /* * 'httpEncode64()' - Base64-encode a string. * * This function is deprecated. Use the httpEncode64_2() function instead * which provides buffer length arguments. * * @deprecated@ */ char * /* O - Encoded string */ httpEncode64(char *out, /* I - String to write to */ const char *in) /* I - String to read from */ { return (httpEncode64_2(out, 512, in, (int)strlen(in))); } /* * 'httpEncode64_2()' - Base64-encode a string. * * @since CUPS 1.1.21/macOS 10.4@ */ char * /* O - Encoded string */ httpEncode64_2(char *out, /* I - String to write to */ int outlen, /* I - Size of output string */ const char *in, /* I - String to read from */ int inlen) /* I - Size of input string */ { char *outptr, /* Output pointer */ *outend; /* End of output buffer */ static const char base64[] = /* Base64 characters... */ { "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "abcdefghijklmnopqrstuvwxyz" "0123456789" "+/" }; /* * Range check input... */ if (!out || outlen < 1 || !in) return (NULL); /* * Convert bytes to base-64... */ for (outptr = out, outend = out + outlen - 1; inlen > 0; in ++, inlen --) { /* * Encode the up to 3 characters as 4 Base64 numbers... */ if (outptr < outend) *outptr ++ = base64[(in[0] & 255) >> 2]; if (outptr < outend) { if (inlen > 1) *outptr ++ = base64[(((in[0] & 255) << 4) | ((in[1] & 255) >> 4)) & 63]; else *outptr ++ = base64[((in[0] & 255) << 4) & 63]; } in ++; inlen --; if (inlen <= 0) { if (outptr < outend) *outptr ++ = '='; if (outptr < outend) *outptr ++ = '='; break; } if (outptr < outend) { if (inlen > 1) *outptr ++ = base64[(((in[0] & 255) << 2) | ((in[1] & 255) >> 6)) & 63]; else *outptr ++ = base64[((in[0] & 255) << 2) & 63]; } in ++; inlen --; if (inlen <= 0) { if (outptr < outend) *outptr ++ = '='; break; } if (outptr < outend) *outptr ++ = base64[in[0] & 63]; } *outptr = '\0'; /* * Return the encoded string... */ return (out); } /* * 'httpGetDateString()' - Get a formatted date/time string from a time value. * * @deprecated@ */ const char * /* O - Date/time string */ httpGetDateString(time_t t) /* I - UNIX time */ { static char http_date[256]; /* Static buffer */ return (httpGetDateString2(t, http_date, sizeof(http_date))); } /* * 'httpGetDateString2()' - Get a formatted date/time string from a time value. * * @since CUPS 1.2/macOS 10.5@ */ const char * /* O - Date/time string */ httpGetDateString2(time_t t, /* I - UNIX time */ char *s, /* I - String buffer */ int slen) /* I - Size of string buffer */ { struct tm *tdate; /* UNIX date/time data */ tdate = gmtime(&t); if (tdate) snprintf(s, (size_t)slen, "%s, %02d %s %d %02d:%02d:%02d GMT", http_days[tdate->tm_wday], tdate->tm_mday, http_months[tdate->tm_mon], tdate->tm_year + 1900, tdate->tm_hour, tdate->tm_min, tdate->tm_sec); else s[0] = '\0'; return (s); } /* * 'httpGetDateTime()' - Get a time value from a formatted date/time string. */ time_t /* O - UNIX time */ httpGetDateTime(const char *s) /* I - Date/time string */ { int i; /* Looping var */ char mon[16]; /* Abbreviated month name */ int day, year; /* Day of month and year */ int hour, min, sec; /* Time */ int days; /* Number of days since 1970 */ static const int normal_days[] = /* Days to a month, normal years */ { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 }; static const int leap_days[] = /* Days to a month, leap years */ { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }; DEBUG_printf(("2httpGetDateTime(s=\"%s\")", s)); /* * Extract the date and time from the formatted string... */ if (sscanf(s, "%*s%d%15s%d%d:%d:%d", &day, mon, &year, &hour, &min, &sec) < 6) return (0); DEBUG_printf(("4httpGetDateTime: day=%d, mon=\"%s\", year=%d, hour=%d, " "min=%d, sec=%d", day, mon, year, hour, min, sec)); /* * Convert the month name to a number from 0 to 11. */ for (i = 0; i < 12; i ++) if (!_cups_strcasecmp(mon, http_months[i])) break; if (i >= 12) return (0); DEBUG_printf(("4httpGetDateTime: i=%d", i)); /* * Now convert the date and time to a UNIX time value in seconds since * 1970. We can't use mktime() since the timezone may not be UTC but * the date/time string *is* UTC. */ if ((year & 3) == 0 && ((year % 100) != 0 || (year % 400) == 0)) days = leap_days[i] + day - 1; else days = normal_days[i] + day - 1; DEBUG_printf(("4httpGetDateTime: days=%d", days)); days += (year - 1970) * 365 + /* 365 days per year (normally) */ ((year - 1) / 4 - 492) - /* + leap days */ ((year - 1) / 100 - 19) + /* - 100 year days */ ((year - 1) / 400 - 4); /* + 400 year days */ DEBUG_printf(("4httpGetDateTime: days=%d\n", days)); return (days * 86400 + hour * 3600 + min * 60 + sec); } /* * 'httpSeparate()' - Separate a Universal Resource Identifier into its * components. * * This function is deprecated; use the httpSeparateURI() function instead. * * @deprecated@ */ void httpSeparate(const char *uri, /* I - Universal Resource Identifier */ char *scheme, /* O - Scheme [32] (http, https, etc.) */ char *username, /* O - Username [1024] */ char *host, /* O - Hostname [1024] */ int *port, /* O - Port number to use */ char *resource) /* O - Resource/filename [1024] */ { httpSeparateURI(HTTP_URI_CODING_ALL, uri, scheme, 32, username, HTTP_MAX_URI, host, HTTP_MAX_URI, port, resource, HTTP_MAX_URI); } /* * 'httpSeparate2()' - Separate a Universal Resource Identifier into its * components. * * This function is deprecated; use the httpSeparateURI() function instead. * * @since CUPS 1.1.21/macOS 10.4@ * @deprecated@ */ void httpSeparate2(const char *uri, /* I - Universal Resource Identifier */ char *scheme, /* O - Scheme (http, https, etc.) */ int schemelen, /* I - Size of scheme buffer */ char *username, /* O - Username */ int usernamelen, /* I - Size of username buffer */ char *host, /* O - Hostname */ int hostlen, /* I - Size of hostname buffer */ int *port, /* O - Port number to use */ char *resource, /* O - Resource/filename */ int resourcelen) /* I - Size of resource buffer */ { httpSeparateURI(HTTP_URI_CODING_ALL, uri, scheme, schemelen, username, usernamelen, host, hostlen, port, resource, resourcelen); } /* * 'httpSeparateURI()' - Separate a Universal Resource Identifier into its * components. * * @since CUPS 1.2/macOS 10.5@ */ http_uri_status_t /* O - Result of separation */ httpSeparateURI( http_uri_coding_t decoding, /* I - Decoding flags */ const char *uri, /* I - Universal Resource Identifier */ char *scheme, /* O - Scheme (http, https, etc.) */ int schemelen, /* I - Size of scheme buffer */ char *username, /* O - Username */ int usernamelen, /* I - Size of username buffer */ char *host, /* O - Hostname */ int hostlen, /* I - Size of hostname buffer */ int *port, /* O - Port number to use */ char *resource, /* O - Resource/filename */ int resourcelen) /* I - Size of resource buffer */ { char *ptr, /* Pointer into string... */ *end; /* End of string */ const char *sep; /* Separator character */ http_uri_status_t status; /* Result of separation */ /* * Initialize everything to blank... */ if (scheme && schemelen > 0) *scheme = '\0'; if (username && usernamelen > 0) *username = '\0'; if (host && hostlen > 0) *host = '\0'; if (port) *port = 0; if (resource && resourcelen > 0) *resource = '\0'; /* * Range check input... */ if (!uri || !port || !scheme || schemelen <= 0 || !username || usernamelen <= 0 || !host || hostlen <= 0 || !resource || resourcelen <= 0) return (HTTP_URI_STATUS_BAD_ARGUMENTS); if (!*uri) return (HTTP_URI_STATUS_BAD_URI); /* * Grab the scheme portion of the URI... */ status = HTTP_URI_STATUS_OK; if (!strncmp(uri, "//", 2)) { /* * Workaround for HP IPP client bug... */ strlcpy(scheme, "ipp", (size_t)schemelen); status = HTTP_URI_STATUS_MISSING_SCHEME; } else if (*uri == '/') { /* * Filename... */ strlcpy(scheme, "file", (size_t)schemelen); status = HTTP_URI_STATUS_MISSING_SCHEME; } else { /* * Standard URI with scheme... */ for (ptr = scheme, end = scheme + schemelen - 1; *uri && *uri != ':' && ptr < end;) if (strchr("ABCDEFGHIJKLMNOPQRSTUVWXYZ" "abcdefghijklmnopqrstuvwxyz" "0123456789-+.", *uri) != NULL) *ptr++ = *uri++; else break; *ptr = '\0'; if (*uri != ':') { *scheme = '\0'; return (HTTP_URI_STATUS_BAD_SCHEME); } uri ++; } /* * Set the default port number... */ if (!strcmp(scheme, "http")) *port = 80; else if (!strcmp(scheme, "https")) *port = 443; else if (!strcmp(scheme, "ipp") || !strcmp(scheme, "ipps")) *port = 631; else if (!_cups_strcasecmp(scheme, "lpd")) *port = 515; else if (!strcmp(scheme, "socket")) /* Not yet registered with IANA... */ *port = 9100; else if (strcmp(scheme, "file") && strcmp(scheme, "mailto") && strcmp(scheme, "tel")) status = HTTP_URI_STATUS_UNKNOWN_SCHEME; /* * Now see if we have a hostname... */ if (!strncmp(uri, "//", 2)) { /* * Yes, extract it... */ uri += 2; /* * Grab the username, if any... */ if ((sep = strpbrk(uri, "@/")) != NULL && *sep == '@') { /* * Get a username:password combo... */ uri = http_copy_decode(username, uri, usernamelen, "@", decoding & HTTP_URI_CODING_USERNAME); if (!uri) { *username = '\0'; return (HTTP_URI_STATUS_BAD_USERNAME); } uri ++; } /* * Then the hostname/IP address... */ if (*uri == '[') { /* * Grab IPv6 address... */ uri ++; if (*uri == 'v') { /* * Skip IPvFuture ("vXXXX.") prefix... */ uri ++; while (isxdigit(*uri & 255)) uri ++; if (*uri != '.') { *host = '\0'; return (HTTP_URI_STATUS_BAD_HOSTNAME); } uri ++; } uri = http_copy_decode(host, uri, hostlen, "]", decoding & HTTP_URI_CODING_HOSTNAME); if (!uri) { *host = '\0'; return (HTTP_URI_STATUS_BAD_HOSTNAME); } /* * Validate value... */ if (*uri != ']') { *host = '\0'; return (HTTP_URI_STATUS_BAD_HOSTNAME); } uri ++; for (ptr = host; *ptr; ptr ++) if (*ptr == '+') { /* * Convert zone separator to % and stop here... */ *ptr = '%'; break; } else if (*ptr == '%') { /* * Stop at zone separator (RFC 6874) */ break; } else if (*ptr != ':' && *ptr != '.' && !isxdigit(*ptr & 255)) { *host = '\0'; return (HTTP_URI_STATUS_BAD_HOSTNAME); } } else { /* * Validate the hostname or IPv4 address first... */ for (ptr = (char *)uri; *ptr; ptr ++) if (strchr(":?/", *ptr)) break; else if (!strchr("abcdefghijklmnopqrstuvwxyz" /* unreserved */ "ABCDEFGHIJKLMNOPQRSTUVWXYZ" /* unreserved */ "0123456789" /* unreserved */ "-._~" /* unreserved */ "%" /* pct-encoded */ "!$&'()*+,;=" /* sub-delims */ "\\", *ptr)) /* SMB domain */ { *host = '\0'; return (HTTP_URI_STATUS_BAD_HOSTNAME); } /* * Then copy the hostname or IPv4 address to the buffer... */ uri = http_copy_decode(host, uri, hostlen, ":?/", decoding & HTTP_URI_CODING_HOSTNAME); if (!uri) { *host = '\0'; return (HTTP_URI_STATUS_BAD_HOSTNAME); } } /* * Validate hostname for file scheme - only empty and localhost are * acceptable. */ if (!strcmp(scheme, "file") && strcmp(host, "localhost") && host[0]) { *host = '\0'; return (HTTP_URI_STATUS_BAD_HOSTNAME); } /* * See if we have a port number... */ if (*uri == ':') { /* * Yes, collect the port number... */ if (!isdigit(uri[1] & 255)) { *port = 0; return (HTTP_URI_STATUS_BAD_PORT); } *port = (int)strtol(uri + 1, (char **)&uri, 10); if (*port <= 0 || *port > 65535) { *port = 0; return (HTTP_URI_STATUS_BAD_PORT); } if (*uri != '/' && *uri) { *port = 0; return (HTTP_URI_STATUS_BAD_PORT); } } } /* * The remaining portion is the resource string... */ if (*uri == '?' || !*uri) { /* * Hostname but no path... */ status = HTTP_URI_STATUS_MISSING_RESOURCE; *resource = '/'; /* * Copy any query string... */ if (*uri == '?') uri = http_copy_decode(resource + 1, uri, resourcelen - 1, NULL, decoding & HTTP_URI_CODING_QUERY); else resource[1] = '\0'; } else { uri = http_copy_decode(resource, uri, resourcelen, "?", decoding & HTTP_URI_CODING_RESOURCE); if (uri && *uri == '?') { /* * Concatenate any query string... */ char *resptr = resource + strlen(resource); uri = http_copy_decode(resptr, uri, resourcelen - (int)(resptr - resource), NULL, decoding & HTTP_URI_CODING_QUERY); } } if (!uri) { *resource = '\0'; return (HTTP_URI_STATUS_BAD_RESOURCE); } /* * Return the URI separation status... */ return (status); } /* * 'httpStateString()' - Return the string describing a HTTP state value. * * @since CUPS 2.0/OS 10.10@ */ const char * /* O - State string */ httpStateString(http_state_t state) /* I - HTTP state value */ { if (state < HTTP_STATE_ERROR || state > HTTP_STATE_UNKNOWN_VERSION) return ("HTTP_STATE_???"); else return (http_states[state - HTTP_STATE_ERROR]); } /* * 'httpStatus()' - Return a short string describing a HTTP status code. * * The returned string is localized to the current POSIX locale and is based * on the status strings defined in RFC 2616. */ const char * /* O - Localized status string */ httpStatus(http_status_t status) /* I - HTTP status code */ { const char *s; /* Status string */ switch (status) { case HTTP_STATUS_ERROR : s = strerror(errno); break; case HTTP_STATUS_CONTINUE : s = _("Continue"); break; case HTTP_STATUS_SWITCHING_PROTOCOLS : s = _("Switching Protocols"); break; case HTTP_STATUS_OK : s = _("OK"); break; case HTTP_STATUS_CREATED : s = _("Created"); break; case HTTP_STATUS_ACCEPTED : s = _("Accepted"); break; case HTTP_STATUS_NO_CONTENT : s = _("No Content"); break; case HTTP_STATUS_MOVED_PERMANENTLY : s = _("Moved Permanently"); break; case HTTP_STATUS_SEE_OTHER : s = _("See Other"); break; case HTTP_STATUS_NOT_MODIFIED : s = _("Not Modified"); break; case HTTP_STATUS_BAD_REQUEST : s = _("Bad Request"); break; case HTTP_STATUS_UNAUTHORIZED : case HTTP_STATUS_CUPS_AUTHORIZATION_CANCELED : s = _("Unauthorized"); break; case HTTP_STATUS_FORBIDDEN : s = _("Forbidden"); break; case HTTP_STATUS_NOT_FOUND : s = _("Not Found"); break; case HTTP_STATUS_REQUEST_TOO_LARGE : s = _("Request Entity Too Large"); break; case HTTP_STATUS_URI_TOO_LONG : s = _("URI Too Long"); break; case HTTP_STATUS_UPGRADE_REQUIRED : s = _("Upgrade Required"); break; case HTTP_STATUS_NOT_IMPLEMENTED : s = _("Not Implemented"); break; case HTTP_STATUS_NOT_SUPPORTED : s = _("Not Supported"); break; case HTTP_STATUS_EXPECTATION_FAILED : s = _("Expectation Failed"); break; case HTTP_STATUS_SERVICE_UNAVAILABLE : s = _("Service Unavailable"); break; case HTTP_STATUS_SERVER_ERROR : s = _("Internal Server Error"); break; case HTTP_STATUS_CUPS_PKI_ERROR : s = _("SSL/TLS Negotiation Error"); break; case HTTP_STATUS_CUPS_WEBIF_DISABLED : s = _("Web Interface is Disabled"); break; default : s = _("Unknown"); break; } return (s); } /* * 'httpURIStatusString()' - Return a string describing a URI status code. * * @since CUPS 2.0/OS 10.10@ */ const char * /* O - Localized status string */ httpURIStatusString( http_uri_status_t status) /* I - URI status code */ { const char *s; /* Status string */ switch (status) { case HTTP_URI_STATUS_OVERFLOW : s = _("URI too large"); break; case HTTP_URI_STATUS_BAD_ARGUMENTS : s = _("Bad arguments to function"); break; case HTTP_URI_STATUS_BAD_RESOURCE : s = _("Bad resource in URI"); break; case HTTP_URI_STATUS_BAD_PORT : s = _("Bad port number in URI"); break; case HTTP_URI_STATUS_BAD_HOSTNAME : s = _("Bad hostname/address in URI"); break; case HTTP_URI_STATUS_BAD_USERNAME : s = _("Bad username in URI"); break; case HTTP_URI_STATUS_BAD_SCHEME : s = _("Bad scheme in URI"); break; case HTTP_URI_STATUS_BAD_URI : s = _("Bad/empty URI"); break; case HTTP_URI_STATUS_OK : s = _("OK"); break; case HTTP_URI_STATUS_MISSING_SCHEME : s = _("Missing scheme in URI"); break; case HTTP_URI_STATUS_UNKNOWN_SCHEME : s = _("Unknown scheme in URI"); break; case HTTP_URI_STATUS_MISSING_RESOURCE : s = _("Missing resource in URI"); break; default: s = _("Unknown"); break; } return (s); } #ifndef HAVE_HSTRERROR /* * '_cups_hstrerror()' - hstrerror() emulation function for Solaris and others. */ const char * /* O - Error string */ _cups_hstrerror(int error) /* I - Error number */ { static const char * const errors[] = /* Error strings */ { "OK", "Host not found.", "Try again.", "Unrecoverable lookup error.", "No data associated with name." }; if (error < 0 || error > 4) return ("Unknown hostname lookup error."); else return (errors[error]); } #endif /* !HAVE_HSTRERROR */ /* * '_httpDecodeURI()' - Percent-decode a HTTP request URI. */ char * /* O - Decoded URI or NULL on error */ _httpDecodeURI(char *dst, /* I - Destination buffer */ const char *src, /* I - Source URI */ size_t dstsize) /* I - Size of destination buffer */ { if (http_copy_decode(dst, src, (int)dstsize, NULL, 1)) return (dst); else return (NULL); } /* * '_httpEncodeURI()' - Percent-encode a HTTP request URI. */ char * /* O - Encoded URI */ _httpEncodeURI(char *dst, /* I - Destination buffer */ const char *src, /* I - Source URI */ size_t dstsize) /* I - Size of destination buffer */ { http_copy_encode(dst, src, dst + dstsize - 1, NULL, NULL, 1); return (dst); } /* * '_httpResolveURI()' - Resolve a DNS-SD URI. */ const char * /* O - Resolved URI */ _httpResolveURI( const char *uri, /* I - DNS-SD URI */ char *resolved_uri, /* I - Buffer for resolved URI */ size_t resolved_size, /* I - Size of URI buffer */ int options, /* I - Resolve options */ int (*cb)(void *context), /* I - Continue callback function */ void *context) /* I - Context pointer for callback */ { char scheme[32], /* URI components... */ userpass[256], hostname[1024], resource[1024]; int port; #ifdef DEBUG http_uri_status_t status; /* URI decode status */ #endif /* DEBUG */ DEBUG_printf(("4_httpResolveURI(uri=\"%s\", resolved_uri=%p, " "resolved_size=" HTMLDOC_LLFMT ")", uri, resolved_uri, HTMLDOC_LLCAST resolved_size)); /* * Get the device URI... */ #ifdef DEBUG if ((status = httpSeparateURI(HTTP_URI_CODING_ALL, uri, scheme, sizeof(scheme), userpass, sizeof(userpass), hostname, sizeof(hostname), &port, resource, sizeof(resource))) < HTTP_URI_STATUS_OK) #else if (httpSeparateURI(HTTP_URI_CODING_ALL, uri, scheme, sizeof(scheme), userpass, sizeof(userpass), hostname, sizeof(hostname), &port, resource, sizeof(resource)) < HTTP_URI_STATUS_OK) #endif /* DEBUG */ { DEBUG_printf(("6_httpResolveURI: httpSeparateURI returned %d!", status)); DEBUG_puts("5_httpResolveURI: Returning NULL"); return (NULL); } /* * Resolve it as needed... */ if (strstr(hostname, "._tcp")) { #if defined(HAVE_DNSSD) || defined(HAVE_AVAHI) char *regtype, /* Pointer to type in hostname */ *domain, /* Pointer to domain in hostname */ *uuid, /* Pointer to UUID in URI */ *uuidend; /* Pointer to end of UUID in URI */ _http_uribuf_t uribuf; /* URI buffer */ int offline = 0; /* offline-report state set? */ # ifdef HAVE_DNSSD # ifdef WIN32 # pragma comment(lib, "dnssd.lib") # endif /* WIN32 */ DNSServiceRef ref, /* DNS-SD master service reference */ domainref = NULL,/* DNS-SD service reference for domain */ ippref = NULL, /* DNS-SD service reference for network IPP */ ippsref = NULL, /* DNS-SD service reference for network IPPS */ localref; /* DNS-SD service reference for .local */ int extrasent = 0; /* Send the domain/IPP/IPPS resolves? */ # ifdef HAVE_POLL struct pollfd polldata; /* Polling data */ # else /* select() */ fd_set input_set; /* Input set for select() */ struct timeval stimeout; /* Timeout value for select() */ # endif /* HAVE_POLL */ # elif defined(HAVE_AVAHI) AvahiClient *client; /* Client information */ int error; /* Status */ # endif /* HAVE_DNSSD */ if (options & _HTTP_RESOLVE_STDERR) fprintf(stderr, "DEBUG: Resolving \"%s\"...\n", hostname); /* * Separate the hostname into service name, registration type, and domain... */ for (regtype = strstr(hostname, "._tcp") - 2; regtype > hostname; regtype --) if (regtype[0] == '.' && regtype[1] == '_') { /* * Found ._servicetype in front of ._tcp... */ *regtype++ = '\0'; break; } if (regtype <= hostname) { DEBUG_puts("5_httpResolveURI: Bad hostname, returning NULL"); return (NULL); } for (domain = strchr(regtype, '.'); domain; domain = strchr(domain + 1, '.')) if (domain[1] != '_') break; if (domain) *domain++ = '\0'; if ((uuid = strstr(resource, "?uuid=")) != NULL) { *uuid = '\0'; uuid += 6; if ((uuidend = strchr(uuid, '&')) != NULL) *uuidend = '\0'; } resolved_uri[0] = '\0'; uribuf.buffer = resolved_uri; uribuf.bufsize = resolved_size; uribuf.options = options; uribuf.resource = resource; uribuf.uuid = uuid; DEBUG_printf(("6_httpResolveURI: Resolving hostname=\"%s\", regtype=\"%s\", " "domain=\"%s\"\n", hostname, regtype, domain)); if (options & _HTTP_RESOLVE_STDERR) { fputs("STATE: +connecting-to-device\n", stderr); fprintf(stderr, "DEBUG: Resolving \"%s\", regtype=\"%s\", " "domain=\"local.\"...\n", hostname, regtype); } uri = NULL; # ifdef HAVE_DNSSD if (DNSServiceCreateConnection(&ref) == kDNSServiceErr_NoError) { uint32_t myinterface = kDNSServiceInterfaceIndexAny; /* Lookup on any interface */ if (!strcmp(scheme, "ippusb")) myinterface = kDNSServiceInterfaceIndexLocalOnly; localref = ref; if (DNSServiceResolve(&localref, kDNSServiceFlagsShareConnection, myinterface, hostname, regtype, "local.", http_resolve_cb, &uribuf) == kDNSServiceErr_NoError) { int fds; /* Number of ready descriptors */ time_t timeout, /* Poll timeout */ start_time = time(NULL),/* Start time */ end_time = start_time + 90; /* End time */ while (time(NULL) < end_time) { if (options & _HTTP_RESOLVE_STDERR) _cupsLangPrintFilter(stderr, "INFO", _("Looking for printer...")); if (cb && !(*cb)(context)) { DEBUG_puts("5_httpResolveURI: callback returned 0 (stop)"); break; } /* * Wakeup every 2 seconds to emit a "looking for printer" message... */ if ((timeout = end_time - time(NULL)) > 2) timeout = 2; # ifdef HAVE_POLL polldata.fd = DNSServiceRefSockFD(ref); polldata.events = POLLIN; fds = poll(&polldata, 1, (int)(1000 * timeout)); # else /* select() */ FD_ZERO(&input_set); FD_SET(DNSServiceRefSockFD(ref), &input_set); # ifdef WIN32 stimeout.tv_sec = (long)timeout; # else stimeout.tv_sec = timeout; # endif /* WIN32 */ stimeout.tv_usec = 0; fds = select(DNSServiceRefSockFD(ref)+1, &input_set, NULL, NULL, &stimeout); # endif /* HAVE_POLL */ if (fds < 0) { if (errno != EINTR && errno != EAGAIN) { DEBUG_printf(("5_httpResolveURI: poll error: %s", strerror(errno))); break; } } else if (fds == 0) { /* * Wait 2 seconds for a response to the local resolve; if nothing * comes in, do an additional domain resolution... */ if (extrasent == 0 && domain && _cups_strcasecmp(domain, "local.")) { if (options & _HTTP_RESOLVE_STDERR) fprintf(stderr, "DEBUG: Resolving \"%s\", regtype=\"%s\", " "domain=\"%s\"...\n", hostname, regtype, domain ? domain : ""); domainref = ref; if (DNSServiceResolve(&domainref, kDNSServiceFlagsShareConnection, myinterface, hostname, regtype, domain, http_resolve_cb, &uribuf) == kDNSServiceErr_NoError) extrasent = 1; } else if (extrasent == 0 && !strcmp(scheme, "ippusb")) { if (options & _HTTP_RESOLVE_STDERR) fprintf(stderr, "DEBUG: Resolving \"%s\", regtype=\"_ipps._tcp\", domain=\"local.\"...\n", hostname); ippsref = ref; if (DNSServiceResolve(&ippsref, kDNSServiceFlagsShareConnection, kDNSServiceInterfaceIndexAny, hostname, "_ipps._tcp", domain, http_resolve_cb, &uribuf) == kDNSServiceErr_NoError) extrasent = 1; } else if (extrasent == 1 && !strcmp(scheme, "ippusb")) { if (options & _HTTP_RESOLVE_STDERR) fprintf(stderr, "DEBUG: Resolving \"%s\", regtype=\"_ipp._tcp\", domain=\"local.\"...\n", hostname); ippref = ref; if (DNSServiceResolve(&ippref, kDNSServiceFlagsShareConnection, kDNSServiceInterfaceIndexAny, hostname, "_ipp._tcp", domain, http_resolve_cb, &uribuf) == kDNSServiceErr_NoError) extrasent = 2; } /* * If it hasn't resolved within 5 seconds set the offline-report * printer-state-reason... */ if ((options & _HTTP_RESOLVE_STDERR) && offline == 0 && time(NULL) > (start_time + 5)) { fputs("STATE: +offline-report\n", stderr); offline = 1; } } else { if (DNSServiceProcessResult(ref) == kDNSServiceErr_NoError && resolved_uri[0]) { uri = resolved_uri; break; } } } if (extrasent) { if (domainref) DNSServiceRefDeallocate(domainref); if (ippref) DNSServiceRefDeallocate(ippref); if (ippsref) DNSServiceRefDeallocate(ippsref); } DNSServiceRefDeallocate(localref); } DNSServiceRefDeallocate(ref); } # else /* HAVE_AVAHI */ if ((uribuf.poll = avahi_simple_poll_new()) != NULL) { avahi_simple_poll_set_func(uribuf.poll, http_poll_cb, NULL); if ((client = avahi_client_new(avahi_simple_poll_get(uribuf.poll), 0, http_client_cb, &uribuf, &error)) != NULL) { if (avahi_service_resolver_new(client, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, hostname, regtype, "local.", AVAHI_PROTO_UNSPEC, 0, http_resolve_cb, &uribuf) != NULL) { time_t start_time = time(NULL), /* Start time */ end_time = start_time + 90; /* End time */ int pstatus; /* Poll status */ pstatus = avahi_simple_poll_iterate(uribuf.poll, 2000); if (pstatus == 0 && !resolved_uri[0] && domain && _cups_strcasecmp(domain, "local.")) { /* * Resolve for .local hasn't returned anything, try the listed * domain... */ avahi_service_resolver_new(client, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, hostname, regtype, domain, AVAHI_PROTO_UNSPEC, 0, http_resolve_cb, &uribuf); } while (!pstatus && !resolved_uri[0] && time(NULL) < end_time) { if ((pstatus = avahi_simple_poll_iterate(uribuf.poll, 2000)) != 0) break; /* * If it hasn't resolved within 5 seconds set the offline-report * printer-state-reason... */ if ((options & _HTTP_RESOLVE_STDERR) && offline == 0 && time(NULL) > (start_time + 5)) { fputs("STATE: +offline-report\n", stderr); offline = 1; } } /* * Collect the result (if we got one). */ if (resolved_uri[0]) uri = resolved_uri; } avahi_client_free(client); } avahi_simple_poll_free(uribuf.poll); } # endif /* HAVE_DNSSD */ if (options & _HTTP_RESOLVE_STDERR) { if (uri) { fprintf(stderr, "DEBUG: Resolved as \"%s\"...\n", uri); fputs("STATE: -connecting-to-device,offline-report\n", stderr); } else { fputs("DEBUG: Unable to resolve URI\n", stderr); fputs("STATE: -connecting-to-device\n", stderr); } } #else /* HAVE_DNSSD || HAVE_AVAHI */ /* * No DNS-SD support... */ uri = NULL; #endif /* HAVE_DNSSD || HAVE_AVAHI */ } else { /* * Nothing more to do... */ strlcpy(resolved_uri, uri, resolved_size); uri = resolved_uri; } DEBUG_printf(("5_httpResolveURI: Returning \"%s\"", uri)); return (uri); } #ifdef HAVE_AVAHI /* * 'http_client_cb()' - Client callback for resolving URI. */ static void http_client_cb( AvahiClient *client, /* I - Client information */ AvahiClientState state, /* I - Current state */ void *context) /* I - Pointer to URI buffer */ { DEBUG_printf(("7http_client_cb(client=%p, state=%d, context=%p)", client, state, context)); /* * If the connection drops, quit. */ if (state == AVAHI_CLIENT_FAILURE) { _http_uribuf_t *uribuf = (_http_uribuf_t *)context; /* URI buffer */ avahi_simple_poll_quit(uribuf->poll); } } #endif /* HAVE_AVAHI */ /* * 'http_copy_decode()' - Copy and decode a URI. */ static const char * /* O - New source pointer or NULL on error */ http_copy_decode(char *dst, /* O - Destination buffer */ const char *src, /* I - Source pointer */ int dstsize, /* I - Destination size */ const char *term, /* I - Terminating characters */ int decode) /* I - Decode %-encoded values */ { char *ptr, /* Pointer into buffer */ *end; /* End of buffer */ int quoted; /* Quoted character */ /* * Copy the src to the destination until we hit a terminating character * or the end of the string. */ for (ptr = dst, end = dst + dstsize - 1; *src && (!term || !strchr(term, *src)); src ++) if (ptr < end) { if (*src == '%' && decode) { if (isxdigit(src[1] & 255) && isxdigit(src[2] & 255)) { /* * Grab a hex-encoded character... */ src ++; if (isalpha(*src)) quoted = (tolower(*src) - 'a' + 10) << 4; else quoted = (*src - '0') << 4; src ++; if (isalpha(*src)) quoted |= tolower(*src) - 'a' + 10; else quoted |= *src - '0'; *ptr++ = (char)quoted; } else { /* * Bad hex-encoded character... */ *ptr = '\0'; return (NULL); } } else if ((*src & 255) <= 0x20 || (*src & 255) >= 0x7f) { *ptr = '\0'; return (NULL); } else *ptr++ = *src; } *ptr = '\0'; return (src); } /* * 'http_copy_encode()' - Copy and encode a URI. */ static char * /* O - End of current URI */ http_copy_encode(char *dst, /* O - Destination buffer */ const char *src, /* I - Source pointer */ char *dstend, /* I - End of destination buffer */ const char *reserved, /* I - Extra reserved characters */ const char *term, /* I - Terminating characters */ int encode) /* I - %-encode reserved chars? */ { static const char hex[] = "0123456789ABCDEF"; while (*src && dst < dstend) { if (term && *src == *term) return (dst); if (encode && (*src == '%' || *src <= ' ' || *src & 128 || (reserved && strchr(reserved, *src)))) { /* * Hex encode reserved characters... */ if ((dst + 2) >= dstend) break; *dst++ = '%'; *dst++ = hex[(*src >> 4) & 15]; *dst++ = hex[*src & 15]; src ++; } else *dst++ = *src++; } *dst = '\0'; if (*src) return (NULL); else return (dst); } #ifdef HAVE_DNSSD /* * 'http_resolve_cb()' - Build a device URI for the given service name. */ static void DNSSD_API http_resolve_cb( DNSServiceRef sdRef, /* I - Service reference */ DNSServiceFlags flags, /* I - Results flags */ uint32_t interfaceIndex, /* I - Interface number */ DNSServiceErrorType errorCode, /* I - Error, if any */ const char *fullName, /* I - Full service name */ const char *hostTarget, /* I - Hostname */ uint16_t port, /* I - Port number */ uint16_t txtLen, /* I - Length of TXT record */ const unsigned char *txtRecord, /* I - TXT record data */ void *context) /* I - Pointer to URI buffer */ { _http_uribuf_t *uribuf = (_http_uribuf_t *)context; /* URI buffer */ const char *scheme, /* URI scheme */ *hostptr, /* Pointer into hostTarget */ *reskey, /* "rp" or "rfo" */ *resdefault; /* Default path */ char resource[257], /* Remote path */ fqdn[256]; /* FQDN of the .local name */ const void *value; /* Value from TXT record */ uint8_t valueLen; /* Length of value */ DEBUG_printf(("7http_resolve_cb(sdRef=%p, flags=%x, interfaceIndex=%u, " "errorCode=%d, fullName=\"%s\", hostTarget=\"%s\", port=%u, " "txtLen=%u, txtRecord=%p, context=%p)", sdRef, flags, interfaceIndex, errorCode, fullName, hostTarget, port, txtLen, txtRecord, context)); /* * If we have a UUID, compare it... */ if (uribuf->uuid && (value = TXTRecordGetValuePtr(txtLen, txtRecord, "UUID", &valueLen)) != NULL) { char uuid[256]; /* UUID value */ memcpy(uuid, value, valueLen); uuid[valueLen] = '\0'; if (_cups_strcasecmp(uuid, uribuf->uuid)) { if (uribuf->options & _HTTP_RESOLVE_STDERR) fprintf(stderr, "DEBUG: Found UUID %s, looking for %s.", uuid, uribuf->uuid); DEBUG_printf(("7http_resolve_cb: Found UUID %s, looking for %s.", uuid, uribuf->uuid)); return; } } /* * Figure out the scheme from the full name... */ if (strstr(fullName, "._ipps") || strstr(fullName, "._ipp-tls")) scheme = "ipps"; else if (strstr(fullName, "._ipp") || strstr(fullName, "._fax-ipp")) scheme = "ipp"; else if (strstr(fullName, "._http.")) scheme = "http"; else if (strstr(fullName, "._https.")) scheme = "https"; else if (strstr(fullName, "._printer.")) scheme = "lpd"; else if (strstr(fullName, "._pdl-datastream.")) scheme = "socket"; else scheme = "riousbprint"; /* * Extract the "remote printer" key from the TXT record... */ if ((uribuf->options & _HTTP_RESOLVE_FAXOUT) && (!strcmp(scheme, "ipp") || !strcmp(scheme, "ipps")) && !TXTRecordGetValuePtr(txtLen, txtRecord, "printer-type", &valueLen)) { reskey = "rfo"; resdefault = "/ipp/faxout"; } else { reskey = "rp"; resdefault = "/"; } if ((value = TXTRecordGetValuePtr(txtLen, txtRecord, reskey, &valueLen)) != NULL) { if (((char *)value)[0] == '/') { /* * Value (incorrectly) has a leading slash already... */ memcpy(resource, value, valueLen); resource[valueLen] = '\0'; } else { /* * Convert to resource by concatenating with a leading "/"... */ resource[0] = '/'; memcpy(resource + 1, value, valueLen); resource[valueLen + 1] = '\0'; } } else { /* * Use the default value... */ strlcpy(resource, resdefault, sizeof(resource)); } /* * Lookup the FQDN if needed... */ if ((uribuf->options & _HTTP_RESOLVE_FQDN) && (hostptr = hostTarget + strlen(hostTarget) - 7) > hostTarget && !_cups_strcasecmp(hostptr, ".local.")) { /* * OK, we got a .local name but the caller needs a real domain. Start by * getting the IP address of the .local name and then do reverse-lookups... */ http_addrlist_t *addrlist, /* List of addresses */ *addr; /* Current address */ DEBUG_printf(("8http_resolve_cb: Looking up \"%s\".", hostTarget)); snprintf(fqdn, sizeof(fqdn), "%d", ntohs(port)); if ((addrlist = httpAddrGetList(hostTarget, AF_UNSPEC, fqdn)) != NULL) { for (addr = addrlist; addr; addr = addr->next) { int error = getnameinfo(&(addr->addr.addr), (socklen_t)httpAddrLength(&(addr->addr)), fqdn, sizeof(fqdn), NULL, 0, NI_NAMEREQD); if (!error) { DEBUG_printf(("8http_resolve_cb: Found \"%s\".", fqdn)); if ((hostptr = fqdn + strlen(fqdn) - 6) <= fqdn || _cups_strcasecmp(hostptr, ".local")) { hostTarget = fqdn; break; } } #ifdef DEBUG else DEBUG_printf(("8http_resolve_cb: \"%s\" did not resolve: %d", httpAddrString(&(addr->addr), fqdn, sizeof(fqdn)), error)); #endif /* DEBUG */ } httpAddrFreeList(addrlist); } } /* * Assemble the final device URI... */ if ((!strcmp(scheme, "ipp") || !strcmp(scheme, "ipps")) && !strcmp(uribuf->resource, "/cups")) httpAssembleURIf(HTTP_URI_CODING_ALL, uribuf->buffer, (int)uribuf->bufsize, scheme, NULL, hostTarget, ntohs(port), "%s?snmp=false", resource); else httpAssembleURI(HTTP_URI_CODING_ALL, uribuf->buffer, (int)uribuf->bufsize, scheme, NULL, hostTarget, ntohs(port), resource); DEBUG_printf(("8http_resolve_cb: Resolved URI is \"%s\"...", uribuf->buffer)); } #elif defined(HAVE_AVAHI) /* * 'http_poll_cb()' - Wait for input on the specified file descriptors. * * Note: This function is needed because avahi_simple_poll_iterate is broken * and always uses a timeout of 0 (!) milliseconds. * (Avahi Ticket #364) */ static int /* O - Number of file descriptors matching */ http_poll_cb( struct pollfd *pollfds, /* I - File descriptors */ unsigned int num_pollfds, /* I - Number of file descriptors */ int timeout, /* I - Timeout in milliseconds (used) */ void *context) /* I - User data (unused) */ { (void)timeout; (void)context; return (poll(pollfds, num_pollfds, 2000)); } /* * 'http_resolve_cb()' - Build a device URI for the given service name. */ static void http_resolve_cb( AvahiServiceResolver *resolver, /* I - Resolver (unused) */ AvahiIfIndex interface, /* I - Interface index (unused) */ AvahiProtocol protocol, /* I - Network protocol (unused) */ AvahiResolverEvent event, /* I - Event (found, etc.) */ const char *name, /* I - Service name */ const char *type, /* I - Registration type */ const char *domain, /* I - Domain (unused) */ const char *hostTarget, /* I - Hostname */ const AvahiAddress *address, /* I - Address (unused) */ uint16_t port, /* I - Port number */ AvahiStringList *txt, /* I - TXT record */ AvahiLookupResultFlags flags, /* I - Lookup flags (unused) */ void *context) /* I - Pointer to URI buffer */ { _http_uribuf_t *uribuf = (_http_uribuf_t *)context; /* URI buffer */ const char *scheme, /* URI scheme */ *hostptr, /* Pointer into hostTarget */ *reskey, /* "rp" or "rfo" */ *resdefault; /* Default path */ char resource[257], /* Remote path */ fqdn[256]; /* FQDN of the .local name */ AvahiStringList *pair; /* Current TXT record key/value pair */ char *value; /* Value for "rp" key */ size_t valueLen = 0; /* Length of "rp" key */ DEBUG_printf(("7http_resolve_cb(resolver=%p, " "interface=%d, protocol=%d, event=%d, name=\"%s\", " "type=\"%s\", domain=\"%s\", hostTarget=\"%s\", address=%p, " "port=%d, txt=%p, flags=%d, context=%p)", resolver, interface, protocol, event, name, type, domain, hostTarget, address, port, txt, flags, context)); if (event != AVAHI_RESOLVER_FOUND) { avahi_service_resolver_free(resolver); avahi_simple_poll_quit(uribuf->poll); return; } /* * If we have a UUID, compare it... */ if (uribuf->uuid && (pair = avahi_string_list_find(txt, "UUID")) != NULL) { char uuid[256]; /* UUID value */ avahi_string_list_get_pair(pair, NULL, &value, &valueLen); memcpy(uuid, value, valueLen); uuid[valueLen] = '\0'; if (_cups_strcasecmp(uuid, uribuf->uuid)) { if (uribuf->options & _HTTP_RESOLVE_STDERR) fprintf(stderr, "DEBUG: Found UUID %s, looking for %s.", uuid, uribuf->uuid); DEBUG_printf(("7http_resolve_cb: Found UUID %s, looking for %s.", uuid, uribuf->uuid)); return; } } /* * Figure out the scheme from the full name... */ if (strstr(type, "_ipp.")) scheme = "ipp"; else if (strstr(type, "_printer.")) scheme = "lpd"; else if (strstr(type, "_pdl-datastream.")) scheme = "socket"; else scheme = "riousbprint"; if (!strncmp(type, "_ipps.", 6) || !strncmp(type, "_ipp-tls.", 9)) scheme = "ipps"; else if (!strncmp(type, "_ipp.", 5) || !strncmp(type, "_fax-ipp.", 9)) scheme = "ipp"; else if (!strncmp(type, "_http.", 6)) scheme = "http"; else if (!strncmp(type, "_https.", 7)) scheme = "https"; else if (!strncmp(type, "_printer.", 9)) scheme = "lpd"; else if (!strncmp(type, "_pdl-datastream.", 16)) scheme = "socket"; else { avahi_service_resolver_free(resolver); avahi_simple_poll_quit(uribuf->poll); return; } /* * Extract the remote resource key from the TXT record... */ if ((uribuf->options & _HTTP_RESOLVE_FAXOUT) && (!strcmp(scheme, "ipp") || !strcmp(scheme, "ipps")) && !avahi_string_list_find(txt, "printer-type")) { reskey = "rfo"; resdefault = "/ipp/faxout"; } else { reskey = "rp"; resdefault = "/"; } if ((pair = avahi_string_list_find(txt, reskey)) != NULL) { avahi_string_list_get_pair(pair, NULL, &value, &valueLen); if (value[0] == '/') { /* * Value (incorrectly) has a leading slash already... */ memcpy(resource, value, valueLen); resource[valueLen] = '\0'; } else { /* * Convert to resource by concatenating with a leading "/"... */ resource[0] = '/'; memcpy(resource + 1, value, valueLen); resource[valueLen + 1] = '\0'; } } else { /* * Use the default value... */ strlcpy(resource, resdefault, sizeof(resource)); } /* * Lookup the FQDN if needed... */ if ((uribuf->options & _HTTP_RESOLVE_FQDN) && (hostptr = hostTarget + strlen(hostTarget) - 6) > hostTarget && !_cups_strcasecmp(hostptr, ".local")) { /* * OK, we got a .local name but the caller needs a real domain. Start by * getting the IP address of the .local name and then do reverse-lookups... */ http_addrlist_t *addrlist, /* List of addresses */ *addr; /* Current address */ DEBUG_printf(("8http_resolve_cb: Looking up \"%s\".", hostTarget)); snprintf(fqdn, sizeof(fqdn), "%d", ntohs(port)); if ((addrlist = httpAddrGetList(hostTarget, AF_UNSPEC, fqdn)) != NULL) { for (addr = addrlist; addr; addr = addr->next) { int error = getnameinfo(&(addr->addr.addr), (socklen_t)httpAddrLength(&(addr->addr)), fqdn, sizeof(fqdn), NULL, 0, NI_NAMEREQD); if (!error) { DEBUG_printf(("8http_resolve_cb: Found \"%s\".", fqdn)); if ((hostptr = fqdn + strlen(fqdn) - 6) <= fqdn || _cups_strcasecmp(hostptr, ".local")) { hostTarget = fqdn; break; } } #ifdef DEBUG else DEBUG_printf(("8http_resolve_cb: \"%s\" did not resolve: %d", httpAddrString(&(addr->addr), fqdn, sizeof(fqdn)), error)); #endif /* DEBUG */ } httpAddrFreeList(addrlist); } } /* * Assemble the final device URI using the resolved hostname... */ httpAssembleURI(HTTP_URI_CODING_ALL, uribuf->buffer, uribuf->bufsize, scheme, NULL, hostTarget, port, resource); DEBUG_printf(("8http_resolve_cb: Resolved URI is \"%s\".", uribuf->buffer)); avahi_simple_poll_quit(uribuf->poll); } #endif /* HAVE_DNSSD */ htmldoc-1.9.7/htmldoc/http.c000066400000000000000000003413651354715574200157700ustar00rootroot00000000000000/* * HTTP routines for HTMLDOC. * * Copyright 2016 by Michael R Sweet. * Copyright 2007-2015 by Apple Inc. * Copyright 1997-2007 by Easy Software Products, all rights reserved. * * This file contains Kerberos support code, copyright 2006 by * Jelmer Vernooij. * * This program is free software. Distribution and use rights are outlined in * the file "COPYING". */ /* * Include necessary headers... */ #include "http-private.h" #include #include #include #ifdef WIN32 # include #else # include # include # include #endif /* WIN32 */ #ifdef HAVE_POLL # include #endif /* HAVE_POLL */ /* * Some operating systems have done away with the Fxxxx constants for * the fcntl() call; this works around that "feature"... */ #ifndef FNONBLK # define FNONBLK O_NONBLOCK #endif /* !FNONBLK */ /* * Local functions... */ #ifdef HAVE_LIBZ static void http_content_coding_finish(http_t *http); static void http_content_coding_start(http_t *http, const char *value); #endif /* HAVE_LIBZ */ static http_t *http_create(const char *host, int port, http_addrlist_t *addrlist, int family, http_encryption_t encryption, int blocking, _http_mode_t mode); #ifdef DEBUG static void http_debug_hex(const char *prefix, const char *buffer, int bytes); #endif /* DEBUG */ static ssize_t http_read(http_t *http, char *buffer, size_t length); static ssize_t http_read_buffered(http_t *http, char *buffer, size_t length); static ssize_t http_read_chunk(http_t *http, char *buffer, size_t length); static int http_send(http_t *http, http_state_t request, const char *uri); static ssize_t http_write(http_t *http, const char *buffer, size_t length); static ssize_t http_write_chunk(http_t *http, const char *buffer, size_t length); static off_t http_set_length(http_t *http); static void http_set_timeout(int fd, double timeout); static void http_set_wait(http_t *http); #ifdef HAVE_SSL static int http_tls_upgrade(http_t *http); #endif /* HAVE_SSL */ /* * Local globals... */ static const char * const http_fields[] = { "Accept-Language", "Accept-Ranges", "Authorization", "Connection", "Content-Encoding", "Content-Language", "Content-Length", "Content-Location", "Content-MD5", "Content-Range", "Content-Type", "Content-Version", "Date", "Host", "If-Modified-Since", "If-Unmodified-since", "Keep-Alive", "Last-Modified", "Link", "Location", "Range", "Referer", "Retry-After", "Transfer-Encoding", "Upgrade", "User-Agent", "WWW-Authenticate", "Accept-Encoding", "Allow", "Server" }; /* * 'httpAcceptConnection()' - Accept a new HTTP client connection from the * specified listening socket. * * @since CUPS 1.7/macOS 10.9@ */ http_t * /* O - HTTP connection or @code NULL@ */ httpAcceptConnection(int fd, /* I - Listen socket file descriptor */ int blocking) /* I - 1 if the connection should be blocking, 0 otherwise */ { http_t *http; /* HTTP connection */ http_addrlist_t addrlist; /* Dummy address list */ socklen_t addrlen; /* Length of address */ int val; /* Socket option value */ /* * Range check input... */ if (fd < 0) return (NULL); /* * Create the client connection... */ memset(&addrlist, 0, sizeof(addrlist)); if ((http = http_create(NULL, 0, &addrlist, AF_UNSPEC, HTTP_ENCRYPTION_IF_REQUESTED, blocking, _HTTP_MODE_SERVER)) == NULL) return (NULL); /* * Accept the client and get the remote address... */ addrlen = sizeof(http_addr_t); if ((http->fd = accept(fd, (struct sockaddr *)&(http->addrlist->addr), &addrlen)) < 0) { _cupsSetHTTPError(HTTP_STATUS_ERROR); httpClose(http); return (NULL); } http->hostaddr = &(http->addrlist->addr); if (httpAddrLocalhost(http->hostaddr)) strlcpy(http->hostname, "localhost", sizeof(http->hostname)); else httpAddrString(http->hostaddr, http->hostname, sizeof(http->hostname)); #ifdef SO_NOSIGPIPE /* * Disable SIGPIPE for this socket. */ val = 1; setsockopt(http->fd, SOL_SOCKET, SO_NOSIGPIPE, CUPS_SOCAST &val, sizeof(val)); #endif /* SO_NOSIGPIPE */ /* * Using TCP_NODELAY improves responsiveness, especially on systems * with a slow loopback interface. Since we write large buffers * when sending print files and requests, there shouldn't be any * performance penalty for this... */ val = 1; setsockopt(http->fd, IPPROTO_TCP, TCP_NODELAY, CUPS_SOCAST &val, sizeof(val)); #ifdef FD_CLOEXEC /* * Close this socket when starting another process... */ fcntl(http->fd, F_SETFD, FD_CLOEXEC); #endif /* FD_CLOEXEC */ return (http); } /* * 'httpAddCredential()' - Allocates and adds a single credential to an array. * * Use @code cupsArrayNew(NULL, NULL)@ to create a credentials array. * * @since CUPS 1.5/macOS 10.7@ */ int /* O - 0 on success, -1 on error */ httpAddCredential( cups_array_t *credentials, /* I - Credentials array */ const void *data, /* I - PEM-encoded X.509 data */ size_t datalen) /* I - Length of data */ { http_credential_t *credential; /* Credential data */ if ((credential = malloc(sizeof(http_credential_t))) != NULL) { credential->datalen = datalen; if ((credential->data = malloc(datalen)) != NULL) { memcpy(credential->data, data, datalen); cupsArrayAdd(credentials, credential); return (0); } free(credential); } return (-1); } /* * 'httpBlocking()' - Set blocking/non-blocking behavior on a connection. */ void httpBlocking(http_t *http, /* I - HTTP connection */ int b) /* I - 1 = blocking, 0 = non-blocking */ { if (http) { http->blocking = b; http_set_wait(http); } } /* * 'httpCheck()' - Check to see if there is a pending response from the server. */ int /* O - 0 = no data, 1 = data available */ httpCheck(http_t *http) /* I - HTTP connection */ { return (httpWait(http, 0)); } /* * 'httpClearCookie()' - Clear the cookie value(s). * * @since CUPS 1.1.19/macOS 10.3@ */ void httpClearCookie(http_t *http) /* I - HTTP connection */ { if (!http) return; if (http->cookie) { free(http->cookie); http->cookie = NULL; } } /* * 'httpClearFields()' - Clear HTTP request fields. */ void httpClearFields(http_t *http) /* I - HTTP connection */ { DEBUG_printf(("httpClearFields(http=%p)", http)); if (http) { memset(http->fields, 0, sizeof(http->fields)); if (http->mode == _HTTP_MODE_CLIENT) { if (http->hostname[0] == '/') httpSetField(http, HTTP_FIELD_HOST, "localhost"); else httpSetField(http, HTTP_FIELD_HOST, http->hostname); } if (http->field_authorization) { free(http->field_authorization); http->field_authorization = NULL; } if (http->accept_encoding) { free(http->accept_encoding); http->accept_encoding = NULL; } if (http->allow) { free(http->allow); http->allow = NULL; } if (http->server) { free(http->server); http->server = NULL; } http->expect = (http_status_t)0; } } /* * 'httpClose()' - Close an HTTP connection. */ void httpClose(http_t *http) /* I - HTTP connection */ { #ifdef HAVE_GSSAPI OM_uint32 minor_status; /* Minor status code */ #endif /* HAVE_GSSAPI */ DEBUG_printf(("httpClose(http=%p)", http)); /* * Range check input... */ if (!http) return; /* * Close any open connection... */ _httpDisconnect(http); /* * Free memory used... */ httpAddrFreeList(http->addrlist); if (http->cookie) free(http->cookie); #ifdef HAVE_GSSAPI if (http->gssctx != GSS_C_NO_CONTEXT) gss_delete_sec_context(&minor_status, &http->gssctx, GSS_C_NO_BUFFER); if (http->gssname != GSS_C_NO_NAME) gss_release_name(&minor_status, &http->gssname); #endif /* HAVE_GSSAPI */ #ifdef HAVE_AUTHORIZATION_H if (http->auth_ref) AuthorizationFree(http->auth_ref, kAuthorizationFlagDefaults); #endif /* HAVE_AUTHORIZATION_H */ httpClearFields(http); if (http->authstring && http->authstring != http->_authstring) free(http->authstring); free(http); } /* * 'httpCompareCredentials()' - Compare two sets of X.509 credentials. * * @since CUPS 2.0/OS 10.10@ */ int /* O - 1 if they match, 0 if they do not */ httpCompareCredentials( cups_array_t *cred1, /* I - First set of X.509 credentials */ cups_array_t *cred2) /* I - Second set of X.509 credentials */ { http_credential_t *temp1, *temp2; /* Temporary credentials */ for (temp1 = (http_credential_t *)cupsArrayFirst(cred1), temp2 = (http_credential_t *)cupsArrayFirst(cred2); temp1 && temp2; temp1 = (http_credential_t *)cupsArrayNext(cred1), temp2 = (http_credential_t *)cupsArrayNext(cred2)) if (temp1->datalen != temp2->datalen) return (0); else if (memcmp(temp1->data, temp2->data, temp1->datalen)) return (0); return (temp1 == temp2); } /* * 'httpConnect()' - Connect to a HTTP server. * * This function is deprecated - use @link httpConnect2@ instead. * * @deprecated@ */ http_t * /* O - New HTTP connection */ httpConnect(const char *host, /* I - Host to connect to */ int port) /* I - Port number */ { return (httpConnect2(host, port, NULL, AF_UNSPEC, HTTP_ENCRYPTION_IF_REQUESTED, 1, 30000, NULL)); } /* * 'httpConnect2()' - Connect to a HTTP server. * * @since CUPS 1.7/macOS 10.9@ */ http_t * /* O - New HTTP connection */ httpConnect2( const char *host, /* I - Host to connect to */ int port, /* I - Port number */ http_addrlist_t *addrlist, /* I - List of addresses or NULL to lookup */ int family, /* I - Address family to use or @code AF_UNSPEC@ for any */ http_encryption_t encryption, /* I - Type of encryption to use */ int blocking, /* I - 1 for blocking connection, 0 for non-blocking */ int msec, /* I - Connection timeout in milliseconds, 0 means don't connect */ int *cancel) /* I - Pointer to "cancel" variable */ { http_t *http; /* New HTTP connection */ DEBUG_printf(("httpConnect2(host=\"%s\", port=%d, addrlist=%p, family=%d, " "encryption=%d, blocking=%d, msec=%d, cancel=%p)", host, port, addrlist, family, encryption, blocking, msec, cancel)); /* * Create the HTTP structure... */ if ((http = http_create(host, port, addrlist, family, encryption, blocking, _HTTP_MODE_CLIENT)) == NULL) return (NULL); /* * Optionally connect to the remote system... */ if (msec == 0 || !httpReconnect2(http, msec, cancel)) return (http); /* * Could not connect to any known address - bail out! */ httpClose(http); return (NULL); } /* * 'httpConnectEncrypt()' - Connect to a HTTP server using encryption. * * This function is now deprecated. Please use the @link httpConnect2@ function * instead. * * @deprecated@ */ http_t * /* O - New HTTP connection */ httpConnectEncrypt( const char *host, /* I - Host to connect to */ int port, /* I - Port number */ http_encryption_t encryption) /* I - Type of encryption to use */ { DEBUG_printf(("httpConnectEncrypt(host=\"%s\", port=%d, encryption=%d)", host, port, encryption)); return (httpConnect2(host, port, NULL, AF_UNSPEC, encryption, 1, 30000, NULL)); } /* * 'httpDelete()' - Send a DELETE request to the server. */ int /* O - Status of call (0 = success) */ httpDelete(http_t *http, /* I - HTTP connection */ const char *uri) /* I - URI to delete */ { return (http_send(http, HTTP_STATE_DELETE, uri)); } /* * '_httpDisconnect()' - Disconnect a HTTP connection. */ void _httpDisconnect(http_t *http) /* I - HTTP connection */ { #ifdef HAVE_SSL if (http->tls) _httpTLSStop(http); #endif /* HAVE_SSL */ httpAddrClose(NULL, http->fd); http->fd = -1; } /* * 'httpEncryption()' - Set the required encryption on the link. */ int /* O - -1 on error, 0 on success */ httpEncryption(http_t *http, /* I - HTTP connection */ http_encryption_t e) /* I - New encryption preference */ { DEBUG_printf(("httpEncryption(http=%p, e=%d)", http, e)); #ifdef HAVE_SSL if (!http) return (0); if (http->mode == _HTTP_MODE_CLIENT) { http->encryption = e; if ((http->encryption == HTTP_ENCRYPTION_ALWAYS && !http->tls) || (http->encryption == HTTP_ENCRYPTION_NEVER && http->tls)) return (httpReconnect2(http, 30000, NULL)); else if (http->encryption == HTTP_ENCRYPTION_REQUIRED && !http->tls) return (http_tls_upgrade(http)); else return (0); } else { if (e == HTTP_ENCRYPTION_NEVER && http->tls) return (-1); http->encryption = e; if (e != HTTP_ENCRYPTION_IF_REQUESTED && !http->tls) return (_httpTLSStart(http)); else return (0); } #else if (e == HTTP_ENCRYPTION_ALWAYS || e == HTTP_ENCRYPTION_REQUIRED) return (-1); else return (0); #endif /* HAVE_SSL */ } /* * 'httpError()' - Get the last error on a connection. */ int /* O - Error code (errno) value */ httpError(http_t *http) /* I - HTTP connection */ { if (http) return (http->error); else return (EINVAL); } /* * 'httpFieldValue()' - Return the HTTP field enumeration value for a field * name. */ http_field_t /* O - Field index */ httpFieldValue(const char *name) /* I - String name */ { int i; /* Looping var */ for (i = 0; i < HTTP_FIELD_MAX; i ++) if (!_cups_strcasecmp(name, http_fields[i])) return ((http_field_t)i); return (HTTP_FIELD_UNKNOWN); } /* * 'httpFlush()' - Flush data from a HTTP connection. */ void httpFlush(http_t *http) /* I - HTTP connection */ { char buffer[8192]; /* Junk buffer */ int blocking; /* To block or not to block */ http_state_t oldstate; /* Old state */ DEBUG_printf(("httpFlush(http=%p), state=%s", http, httpStateString(http->state))); /* * Nothing to do if we are in the "waiting" state... */ if (http->state == HTTP_STATE_WAITING) return; /* * Temporarily set non-blocking mode so we don't get stuck in httpRead()... */ blocking = http->blocking; http->blocking = 0; /* * Read any data we can... */ oldstate = http->state; while (httpRead2(http, buffer, sizeof(buffer)) > 0); /* * Restore blocking and reset the connection if we didn't get all of * the remaining data... */ http->blocking = blocking; if (http->state == oldstate && http->state != HTTP_STATE_WAITING && http->fd >= 0) { /* * Didn't get the data back, so close the current connection. */ #ifdef HAVE_LIBZ if (http->coding) http_content_coding_finish(http); #endif /* HAVE_LIBZ */ DEBUG_puts("1httpFlush: Setting state to HTTP_STATE_WAITING and closing."); http->state = HTTP_STATE_WAITING; #ifdef HAVE_SSL if (http->tls) _httpTLSStop(http); #endif /* HAVE_SSL */ httpAddrClose(NULL, http->fd); http->fd = -1; } } /* * 'httpFlushWrite()' - Flush data in write buffer. * * @since CUPS 1.2/macOS 10.5@ */ int /* O - Bytes written or -1 on error */ httpFlushWrite(http_t *http) /* I - HTTP connection */ { ssize_t bytes; /* Bytes written */ DEBUG_printf(("httpFlushWrite(http=%p) data_encoding=%d", http, http ? http->data_encoding : 100)); if (!http || !http->wused) { DEBUG_puts(http ? "1httpFlushWrite: Write buffer is empty." : "1httpFlushWrite: No connection."); return (0); } if (http->data_encoding == HTTP_ENCODING_CHUNKED) bytes = http_write_chunk(http, http->wbuffer, (size_t)http->wused); else bytes = http_write(http, http->wbuffer, (size_t)http->wused); http->wused = 0; DEBUG_printf(("1httpFlushWrite: Returning %d, errno=%d.", (int)bytes, errno)); return ((int)bytes); } /* * 'httpFreeCredentials()' - Free an array of credentials. */ void httpFreeCredentials( cups_array_t *credentials) /* I - Array of credentials */ { http_credential_t *credential; /* Credential */ for (credential = (http_credential_t *)cupsArrayFirst(credentials); credential; credential = (http_credential_t *)cupsArrayNext(credentials)) { cupsArrayRemove(credentials, credential); free((void *)credential->data); free(credential); } cupsArrayDelete(credentials); } /* * 'httpGet()' - Send a GET request to the server. */ int /* O - Status of call (0 = success) */ httpGet(http_t *http, /* I - HTTP connection */ const char *uri) /* I - URI to get */ { return (http_send(http, HTTP_STATE_GET, uri)); } /* * 'httpGetActivity()' - Get the most recent activity for a connection. * * The return value is the UNIX time of the last read or write. * * @since CUPS 2.0/OS 10.10@ */ time_t /* O - Time of last read or write */ httpGetActivity(http_t *http) /* I - HTTP connection */ { return (http ? http->activity : 0); } /* * 'httpGetAuthString()' - Get the current authorization string. * * The authorization string is set by cupsDoAuthentication() and * httpSetAuthString(). Use httpGetAuthString() to retrieve the * string to use with httpSetField() for the HTTP_FIELD_AUTHORIZATION * value. * * @since CUPS 1.3/macOS 10.5@ */ char * /* O - Authorization string */ httpGetAuthString(http_t *http) /* I - HTTP connection */ { if (http) return (http->authstring); else return (NULL); } /* * 'httpGetBlocking()' - Get the blocking/non-block state of a connection. * * @since CUPS 1.2/macOS 10.5@ */ int /* O - 1 if blocking, 0 if non-blocking */ httpGetBlocking(http_t *http) /* I - HTTP connection */ { return (http ? http->blocking : 0); } /* * 'httpGetContentEncoding()' - Get a common content encoding, if any, between * the client and server. * * This function uses the value of the Accepts-Encoding HTTP header and must be * called after receiving a response from the server or a request from the * client. The value returned can be use in subsequent requests (for clients) * or in the response (for servers) in order to compress the content stream. * * @since CUPS 1.7/macOS 10.9@ */ const char * /* O - Content-Coding value or @code NULL@ for the identity coding. */ httpGetContentEncoding(http_t *http) /* I - HTTP connection */ { #ifdef HAVE_LIBZ if (http && http->accept_encoding) { int i; /* Looping var */ char temp[HTTP_MAX_VALUE], /* Copy of Accepts-Encoding value */ *start, /* Start of coding value */ *end; /* End of coding value */ double qvalue; /* "qvalue" for coding */ struct lconv *loc = localeconv(); /* Locale data */ static const char * const codings[] = { /* Supported content codings */ "deflate", "gzip", "x-deflate", "x-gzip" }; strlcpy(temp, http->accept_encoding, sizeof(temp)); for (start = temp; *start; start = end) { /* * Find the end of the coding name... */ qvalue = 1.0; end = start; while (*end && *end != ';' && *end != ',' && !isspace(*end & 255)) end ++; if (*end == ';') { /* * Grab the qvalue as needed... */ if (!strncmp(end, ";q=", 3)) qvalue = _cupsStrScand(end + 3, NULL, loc); /* * Skip past all attributes... */ *end++ = '\0'; while (*end && *end != ',' && !isspace(*end & 255)) end ++; } else if (*end) *end++ = '\0'; while (*end && isspace(*end & 255)) end ++; /* * Check value if it matches something we support... */ if (qvalue <= 0.0) continue; for (i = 0; i < (int)(sizeof(codings) / sizeof(codings[0])); i ++) if (!strcmp(start, codings[i])) return (codings[i]); } } #endif /* HAVE_LIBZ */ return (NULL); } /* * 'httpGetCookie()' - Get any cookie data from the response. * * @since CUPS 1.1.19/macOS 10.3@ */ const char * /* O - Cookie data or NULL */ httpGetCookie(http_t *http) /* I - HTTP connection */ { return (http ? http->cookie : NULL); } /* * 'httpGetEncryption()' - Get the current encryption mode of a connection. * * This function returns the encryption mode for the connection. Use the * @link httpIsEncrypted@ function to determine whether a TLS session has * been established. * * @since CUPS 2.0/OS 10.10@ */ http_encryption_t /* O - Current encryption mode */ httpGetEncryption(http_t *http) /* I - HTTP connection */ { return (http ? http->encryption : HTTP_ENCRYPTION_IF_REQUESTED); } /* * 'httpGetExpect()' - Get the value of the Expect header, if any. * * Returns @code HTTP_STATUS_NONE@ if there is no Expect header, otherwise * returns the expected HTTP status code, typically @code HTTP_STATUS_CONTINUE@. * * @since CUPS 1.7/macOS 10.9@ */ http_status_t /* O - Expect: status, if any */ httpGetExpect(http_t *http) /* I - HTTP connection */ { if (!http) return (HTTP_STATUS_ERROR); else return (http->expect); } /* * 'httpGetFd()' - Get the file descriptor associated with a connection. * * @since CUPS 1.2/macOS 10.5@ */ int /* O - File descriptor or -1 if none */ httpGetFd(http_t *http) /* I - HTTP connection */ { return (http ? http->fd : -1); } /* * 'httpGetField()' - Get a field value from a request/response. */ const char * /* O - Field value */ httpGetField(http_t *http, /* I - HTTP connection */ http_field_t field) /* I - Field to get */ { if (!http || field <= HTTP_FIELD_UNKNOWN || field >= HTTP_FIELD_MAX) return (NULL); switch (field) { case HTTP_FIELD_ACCEPT_ENCODING : return (http->accept_encoding); case HTTP_FIELD_ALLOW : return (http->allow); case HTTP_FIELD_SERVER : return (http->server); case HTTP_FIELD_AUTHORIZATION : if (http->field_authorization) { /* * Special case for WWW-Authenticate: as its contents can be * longer than HTTP_MAX_VALUE... */ return (http->field_authorization); } default : return (http->fields[field]); } } /* * 'httpGetKeepAlive()' - Get the current Keep-Alive state of the connection. * * @since CUPS 2.0/OS 10.10@ */ http_keepalive_t /* O - Keep-Alive state */ httpGetKeepAlive(http_t *http) /* I - HTTP connection */ { return (http ? http->keep_alive : HTTP_KEEPALIVE_OFF); } /* * 'httpGetLength()' - Get the amount of data remaining from the * content-length or transfer-encoding fields. * * This function is deprecated and will not return lengths larger than * 2^31 - 1; use httpGetLength2() instead. * * @deprecated@ */ int /* O - Content length */ httpGetLength(http_t *http) /* I - HTTP connection */ { /* * Get the read content length and return the 32-bit value. */ if (http) { httpGetLength2(http); return (http->_data_remaining); } else return (-1); } /* * 'httpGetLength2()' - Get the amount of data remaining from the * content-length or transfer-encoding fields. * * This function returns the complete content length, even for * content larger than 2^31 - 1. * * @since CUPS 1.2/macOS 10.5@ */ off_t /* O - Content length */ httpGetLength2(http_t *http) /* I - HTTP connection */ { off_t remaining; /* Remaining length */ DEBUG_printf(("2httpGetLength2(http=%p), state=%s", http, httpStateString(http->state))); if (!http) return (-1); if (!_cups_strcasecmp(http->fields[HTTP_FIELD_TRANSFER_ENCODING], "chunked")) { DEBUG_puts("4httpGetLength2: chunked request!"); remaining = 0; } else { /* * The following is a hack for HTTP servers that don't send a * Content-Length or Transfer-Encoding field... * * If there is no Content-Length then the connection must close * after the transfer is complete... */ if (!http->fields[HTTP_FIELD_CONTENT_LENGTH][0]) { /* * Default content length is 0 for errors and certain types of operations, * and 2^31-1 for other successful requests... */ if (http->status >= HTTP_STATUS_MULTIPLE_CHOICES || http->state == HTTP_STATE_OPTIONS || (http->state == HTTP_STATE_GET && http->mode == _HTTP_MODE_SERVER) || http->state == HTTP_STATE_HEAD || (http->state == HTTP_STATE_PUT && http->mode == _HTTP_MODE_CLIENT) || http->state == HTTP_STATE_DELETE || http->state == HTTP_STATE_TRACE || http->state == HTTP_STATE_CONNECT) remaining = 0; else remaining = 2147483647; } else if ((remaining = strtoll(http->fields[HTTP_FIELD_CONTENT_LENGTH], NULL, 10)) < 0) remaining = -1; DEBUG_printf(("4httpGetLength2: content_length=" HTMLDOC_LLFMT, HTMLDOC_LLCAST remaining)); } return (remaining); } /* * 'httpGetPending()' - Get the number of bytes that are buffered for writing. * * @since CUPS 2.0/OS 10.10@ */ size_t /* O - Number of bytes buffered */ httpGetPending(http_t *http) /* I - HTTP connection */ { return (http ? (size_t)http->wused : 0); } /* * 'httpGetReady()' - Get the number of bytes that can be read without blocking. * * @since CUPS 2.0/OS 10.10@ */ size_t /* O - Number of bytes available */ httpGetReady(http_t *http) /* I - HTTP connection */ { if (!http) return (0); else if (http->used > 0) return ((size_t)http->used); #ifdef HAVE_SSL else if (http->tls) return (_httpTLSPending(http)); #endif /* HAVE_SSL */ return (0); } /* * 'httpGetRemaining()' - Get the number of remaining bytes in the message * body or current chunk. * * The @link httpIsChunked@ function can be used to determine whether the * message body is chunked or fixed-length. * * @since CUPS 2.0/OS 10.10@ */ size_t /* O - Remaining bytes */ httpGetRemaining(http_t *http) /* I - HTTP connection */ { return (http ? (size_t)http->data_remaining : 0); } /* * 'httpGets()' - Get a line of text from a HTTP connection. */ char * /* O - Line or NULL */ httpGets(char *line, /* I - Line to read into */ int length, /* I - Max length of buffer */ http_t *http) /* I - HTTP connection */ { char *lineptr, /* Pointer into line */ *lineend, /* End of line */ *bufptr, /* Pointer into input buffer */ *bufend; /* Pointer to end of buffer */ ssize_t bytes; /* Number of bytes read */ int eol; /* End-of-line? */ DEBUG_printf(("2httpGets(line=%p, length=%d, http=%p)", line, length, http)); if (!http || !line || length <= 1) return (NULL); /* * Read a line from the buffer... */ http->error = 0; lineptr = line; lineend = line + length - 1; eol = 0; while (lineptr < lineend) { /* * Pre-load the buffer as needed... */ #ifdef WIN32 WSASetLastError(0); #else errno = 0; #endif /* WIN32 */ while (http->used == 0) { /* * No newline; see if there is more data to be read... */ while (!_httpWait(http, http->wait_value, 1)) { if (http->timeout_cb && (*http->timeout_cb)(http, http->timeout_data)) continue; DEBUG_puts("3httpGets: Timed out!"); #ifdef WIN32 http->error = WSAETIMEDOUT; #else http->error = ETIMEDOUT; #endif /* WIN32 */ return (NULL); } bytes = http_read(http, http->buffer + http->used, (size_t)(HTTP_MAX_BUFFER - http->used)); DEBUG_printf(("4httpGets: read " HTMLDOC_LLFMT " bytes.", HTMLDOC_LLCAST bytes)); if (bytes < 0) { /* * Nope, can't get a line this time... */ #ifdef WIN32 DEBUG_printf(("3httpGets: recv() error %d!", WSAGetLastError())); if (WSAGetLastError() == WSAEINTR) continue; else if (WSAGetLastError() == WSAEWOULDBLOCK) { if (http->timeout_cb && (*http->timeout_cb)(http, http->timeout_data)) continue; http->error = WSAGetLastError(); } else if (WSAGetLastError() != http->error) { http->error = WSAGetLastError(); continue; } #else DEBUG_printf(("3httpGets: recv() error %d!", errno)); if (errno == EINTR) continue; else if (errno == EWOULDBLOCK || errno == EAGAIN) { if (http->timeout_cb && (*http->timeout_cb)(http, http->timeout_data)) continue; else if (!http->timeout_cb && errno == EAGAIN) continue; http->error = errno; } else if (errno != http->error) { http->error = errno; continue; } #endif /* WIN32 */ return (NULL); } else if (bytes == 0) { http->error = EPIPE; return (NULL); } /* * Yup, update the amount used... */ http->used += (int)bytes; } /* * Now copy as much of the current line as possible... */ for (bufptr = http->buffer, bufend = http->buffer + http->used; lineptr < lineend && bufptr < bufend;) { if (*bufptr == 0x0a) { eol = 1; bufptr ++; break; } else if (*bufptr == 0x0d) bufptr ++; else *lineptr++ = *bufptr++; } http->used -= (int)(bufptr - http->buffer); if (http->used > 0) memmove(http->buffer, bufptr, (size_t)http->used); if (eol) { /* * End of line... */ http->activity = time(NULL); *lineptr = '\0'; DEBUG_printf(("3httpGets: Returning \"%s\"", line)); return (line); } } DEBUG_puts("3httpGets: No new line available!"); return (NULL); } /* * 'httpGetState()' - Get the current state of the HTTP request. */ http_state_t /* O - HTTP state */ httpGetState(http_t *http) /* I - HTTP connection */ { return (http ? http->state : HTTP_STATE_ERROR); } /* * 'httpGetStatus()' - Get the status of the last HTTP request. * * @since CUPS 1.2/macOS 10.5@ */ http_status_t /* O - HTTP status */ httpGetStatus(http_t *http) /* I - HTTP connection */ { return (http ? http->status : HTTP_STATUS_ERROR); } /* * 'httpGetSubField()' - Get a sub-field value. * * @deprecated@ */ char * /* O - Value or NULL */ httpGetSubField(http_t *http, /* I - HTTP connection */ http_field_t field, /* I - Field index */ const char *name, /* I - Name of sub-field */ char *value) /* O - Value string */ { return (httpGetSubField2(http, field, name, value, HTTP_MAX_VALUE)); } /* * 'httpGetSubField2()' - Get a sub-field value. * * @since CUPS 1.2/macOS 10.5@ */ char * /* O - Value or NULL */ httpGetSubField2(http_t *http, /* I - HTTP connection */ http_field_t field, /* I - Field index */ const char *name, /* I - Name of sub-field */ char *value, /* O - Value string */ int valuelen) /* I - Size of value buffer */ { const char *fptr; /* Pointer into field */ char temp[HTTP_MAX_VALUE], /* Temporary buffer for name */ *ptr, /* Pointer into string buffer */ *end; /* End of value buffer */ DEBUG_printf(("2httpGetSubField2(http=%p, field=%d, name=\"%s\", value=%p, " "valuelen=%d)", http, field, name, value, valuelen)); if (!http || !name || !value || valuelen < 2 || field <= HTTP_FIELD_UNKNOWN || field >= HTTP_FIELD_MAX) return (NULL); end = value + valuelen - 1; for (fptr = http->fields[field]; *fptr;) { /* * Skip leading whitespace... */ while (_cups_isspace(*fptr)) fptr ++; if (*fptr == ',') { fptr ++; continue; } /* * Get the sub-field name... */ for (ptr = temp; *fptr && *fptr != '=' && !_cups_isspace(*fptr) && ptr < (temp + sizeof(temp) - 1); *ptr++ = *fptr++); *ptr = '\0'; DEBUG_printf(("4httpGetSubField2: name=\"%s\"", temp)); /* * Skip trailing chars up to the '='... */ while (_cups_isspace(*fptr)) fptr ++; if (!*fptr) break; if (*fptr != '=') continue; /* * Skip = and leading whitespace... */ fptr ++; while (_cups_isspace(*fptr)) fptr ++; if (*fptr == '\"') { /* * Read quoted string... */ for (ptr = value, fptr ++; *fptr && *fptr != '\"' && ptr < end; *ptr++ = *fptr++); *ptr = '\0'; while (*fptr && *fptr != '\"') fptr ++; if (*fptr) fptr ++; } else { /* * Read unquoted string... */ for (ptr = value; *fptr && !_cups_isspace(*fptr) && *fptr != ',' && ptr < end; *ptr++ = *fptr++); *ptr = '\0'; while (*fptr && !_cups_isspace(*fptr) && *fptr != ',') fptr ++; } DEBUG_printf(("4httpGetSubField2: value=\"%s\"", value)); /* * See if this is the one... */ if (!strcmp(name, temp)) { DEBUG_printf(("3httpGetSubField2: Returning \"%s\"", value)); return (value); } } value[0] = '\0'; DEBUG_puts("3httpGetSubField2: Returning NULL"); return (NULL); } /* * 'httpGetVersion()' - Get the HTTP version at the other end. */ http_version_t /* O - Version number */ httpGetVersion(http_t *http) /* I - HTTP connection */ { return (http ? http->version : HTTP_VERSION_1_0); } /* * 'httpHead()' - Send a HEAD request to the server. */ int /* O - Status of call (0 = success) */ httpHead(http_t *http, /* I - HTTP connection */ const char *uri) /* I - URI for head */ { DEBUG_printf(("httpHead(http=%p, uri=\"%s\")", http, uri)); return (http_send(http, HTTP_STATE_HEAD, uri)); } /* * 'httpInitialize()' - Initialize the HTTP interface library and set the * default HTTP proxy (if any). */ void httpInitialize(void) { static int initialized = 0; /* Have we been called before? */ #ifdef WIN32 WSADATA winsockdata; /* WinSock data */ #endif /* WIN32 */ _cupsGlobalLock(); if (initialized) { _cupsGlobalUnlock(); return; } #ifdef WIN32 WSAStartup(MAKEWORD(2,2), &winsockdata); #elif !defined(SO_NOSIGPIPE) /* * Ignore SIGPIPE signals... */ # ifdef HAVE_SIGSET sigset(SIGPIPE, SIG_IGN); # elif defined(HAVE_SIGACTION) struct sigaction action; /* POSIX sigaction data */ memset(&action, 0, sizeof(action)); action.sa_handler = SIG_IGN; sigaction(SIGPIPE, &action, NULL); # else signal(SIGPIPE, SIG_IGN); # endif /* !SO_NOSIGPIPE */ #endif /* WIN32 */ # ifdef HAVE_SSL _httpTLSInitialize(); # endif /* HAVE_SSL */ initialized = 1; _cupsGlobalUnlock(); } /* * 'httpIsChunked()' - Report whether a message body is chunked. * * This function returns non-zero if the message body is composed of * variable-length chunks. * * @since CUPS 2.0/OS 10.10@ */ int /* O - 1 if chunked, 0 if not */ httpIsChunked(http_t *http) /* I - HTTP connection */ { return (http ? http->data_encoding == HTTP_ENCODING_CHUNKED : 0); } /* * 'httpIsEncrypted()' - Report whether a connection is encrypted. * * This function returns non-zero if the connection is currently encrypted. * * @since CUPS 2.0/OS 10.10@ */ int /* O - 1 if encrypted, 0 if not */ httpIsEncrypted(http_t *http) /* I - HTTP connection */ { return (http ? http->tls != NULL : 0); } /* * 'httpOptions()' - Send an OPTIONS request to the server. */ int /* O - Status of call (0 = success) */ httpOptions(http_t *http, /* I - HTTP connection */ const char *uri) /* I - URI for options */ { return (http_send(http, HTTP_STATE_OPTIONS, uri)); } /* * 'httpPeek()' - Peek at data from a HTTP connection. * * This function copies available data from the given HTTP connection, reading * a buffer as needed. The data is still available for reading using * @link httpRead@ or @link httpRead2@. * * For non-blocking connections the usual timeouts apply. * * @since CUPS 1.7/macOS 10.9@ */ ssize_t /* O - Number of bytes copied */ httpPeek(http_t *http, /* I - HTTP connection */ char *buffer, /* I - Buffer for data */ size_t length) /* I - Maximum number of bytes */ { ssize_t bytes; /* Bytes read */ char len[32]; /* Length string */ DEBUG_printf(("httpPeek(http=%p, buffer=%p, length=" HTMLDOC_LLFMT ")", http, buffer, HTMLDOC_LLCAST length)); if (http == NULL || buffer == NULL) return (-1); http->activity = time(NULL); http->error = 0; if (length <= 0) return (0); if (http->data_encoding == HTTP_ENCODING_CHUNKED && http->data_remaining <= 0) { DEBUG_puts("2httpPeek: Getting chunk length..."); if (httpGets(len, sizeof(len), http) == NULL) { DEBUG_puts("1httpPeek: Could not get length!"); return (0); } if (!len[0]) { DEBUG_puts("1httpPeek: Blank chunk length, trying again..."); if (!httpGets(len, sizeof(len), http)) { DEBUG_puts("1httpPeek: Could not get chunk length."); return (0); } } http->data_remaining = strtoll(len, NULL, 16); if (http->data_remaining < 0) { DEBUG_puts("1httpPeek: Negative chunk length!"); return (0); } } DEBUG_printf(("2httpPeek: data_remaining=" HTMLDOC_LLFMT, HTMLDOC_LLCAST http->data_remaining)); if (http->data_remaining <= 0 && http->data_encoding != HTTP_ENCODING_FIELDS) { /* * A zero-length chunk ends a transfer; unless we are reading POST * data, go idle... */ #ifdef HAVE_LIBZ if (http->coding >= _HTTP_CODING_GUNZIP) http_content_coding_finish(http); #endif /* HAVE_LIBZ */ if (http->data_encoding == HTTP_ENCODING_CHUNKED) httpGets(len, sizeof(len), http); if (http->state == HTTP_STATE_POST_RECV) http->state ++; else http->state = HTTP_STATE_STATUS; DEBUG_printf(("1httpPeek: 0-length chunk, set state to %s.", httpStateString(http->state))); /* * Prevent future reads for this request... */ http->data_encoding = HTTP_ENCODING_FIELDS; return (0); } else if (length > (size_t)http->data_remaining) length = (size_t)http->data_remaining; #ifdef HAVE_LIBZ if (http->used == 0 && (http->coding == _HTTP_CODING_IDENTITY || (http->coding >= _HTTP_CODING_GUNZIP && http->stream.avail_in == 0))) #else if (http->used == 0) #endif /* HAVE_LIBZ */ { /* * Buffer small reads for better performance... */ ssize_t buflen; /* Length of read for buffer */ if (!http->blocking) { while (!httpWait(http, http->wait_value)) { if (http->timeout_cb && (*http->timeout_cb)(http, http->timeout_data)) continue; return (0); } } if ((size_t)http->data_remaining > sizeof(http->buffer)) buflen = sizeof(http->buffer); else buflen = (ssize_t)http->data_remaining; DEBUG_printf(("2httpPeek: Reading %d bytes into buffer.", (int)buflen)); bytes = http_read(http, http->buffer, (size_t)buflen); DEBUG_printf(("2httpPeek: Read " HTMLDOC_LLFMT " bytes into buffer.", HTMLDOC_LLCAST bytes)); if (bytes > 0) { #ifdef DEBUG http_debug_hex("httpPeek", http->buffer, (int)bytes); #endif /* DEBUG */ http->used = (int)bytes; } } #ifdef HAVE_LIBZ if (http->coding >= _HTTP_CODING_GUNZIP) { # ifdef HAVE_INFLATECOPY int zerr; /* Decompressor error */ z_stream stream; /* Copy of decompressor stream */ if (http->used > 0 && http->stream.avail_in < HTTP_MAX_BUFFER) { size_t buflen = buflen = HTTP_MAX_BUFFER - http->stream.avail_in; /* Number of bytes to copy */ if (http->stream.avail_in > 0 && http->stream.next_in > http->sbuffer) memmove(http->sbuffer, http->stream.next_in, http->stream.avail_in); http->stream.next_in = http->sbuffer; if (buflen > (size_t)http->data_remaining) buflen = (size_t)http->data_remaining; if (buflen > (size_t)http->used) buflen = (size_t)http->used; DEBUG_printf(("1httpPeek: Copying %d more bytes of data into " "decompression buffer.", (int)buflen)); memcpy(http->sbuffer + http->stream.avail_in, http->buffer, buflen); http->stream.avail_in += buflen; http->used -= (int)buflen; http->data_remaining -= (off_t)buflen; if (http->used > 0) memmove(http->buffer, http->buffer + buflen, (size_t)http->used); } DEBUG_printf(("2httpPeek: length=%d, avail_in=%d", (int)length, (int)http->stream.avail_in)); if (inflateCopy(&stream, &(http->stream)) != Z_OK) { DEBUG_puts("2httpPeek: Unable to copy decompressor stream."); http->error = ENOMEM; return (-1); } stream.next_out = (Bytef *)buffer; stream.avail_out = (uInt)length; zerr = inflate(&stream, Z_SYNC_FLUSH); inflateEnd(&stream); if (zerr < Z_OK) { DEBUG_printf(("2httpPeek: zerr=%d", zerr)); #ifdef DEBUG http_debug_hex("2httpPeek", (char *)http->sbuffer, (int)http->stream.avail_in); #endif /* DEBUG */ http->error = EIO; return (-1); } bytes = (ssize_t)(length - http->stream.avail_out); # else DEBUG_puts("2httpPeek: No inflateCopy on this platform, httpPeek does not " "work with compressed streams."); return (-1); # endif /* HAVE_INFLATECOPY */ } else #endif /* HAVE_LIBZ */ if (http->used > 0) { if (length > (size_t)http->used) length = (size_t)http->used; bytes = (ssize_t)length; DEBUG_printf(("2httpPeek: grabbing %d bytes from input buffer...", (int)bytes)); memcpy(buffer, http->buffer, length); } else bytes = 0; if (bytes < 0) { #ifdef WIN32 if (WSAGetLastError() == WSAEINTR || WSAGetLastError() == WSAEWOULDBLOCK) bytes = 0; else http->error = WSAGetLastError(); #else if (errno == EINTR || errno == EAGAIN) bytes = 0; else http->error = errno; #endif /* WIN32 */ } else if (bytes == 0) { http->error = EPIPE; return (0); } return (bytes); } /* * 'httpPost()' - Send a POST request to the server. */ int /* O - Status of call (0 = success) */ httpPost(http_t *http, /* I - HTTP connection */ const char *uri) /* I - URI for post */ { return (http_send(http, HTTP_STATE_POST, uri)); } /* * 'httpPrintf()' - Print a formatted string to a HTTP connection. * * @private@ */ int /* O - Number of bytes written */ httpPrintf(http_t *http, /* I - HTTP connection */ const char *format, /* I - printf-style format string */ ...) /* I - Additional args as needed */ { ssize_t bytes; /* Number of bytes to write */ char buf[16384]; /* Buffer for formatted string */ va_list ap; /* Variable argument pointer */ DEBUG_printf(("2httpPrintf(http=%p, format=\"%s\", ...)", http, format)); va_start(ap, format); bytes = vsnprintf(buf, sizeof(buf), format, ap); va_end(ap); DEBUG_printf(("3httpPrintf: (" HTMLDOC_LLFMT " bytes) %s", HTMLDOC_LLCAST bytes, buf)); if (http->data_encoding == HTTP_ENCODING_FIELDS) return ((int)httpWrite2(http, buf, (size_t)bytes)); else { if (http->wused) { DEBUG_puts("4httpPrintf: flushing existing data..."); if (httpFlushWrite(http) < 0) return (-1); } return ((int)http_write(http, buf, (size_t)bytes)); } } /* * 'httpPut()' - Send a PUT request to the server. */ int /* O - Status of call (0 = success) */ httpPut(http_t *http, /* I - HTTP connection */ const char *uri) /* I - URI to put */ { DEBUG_printf(("httpPut(http=%p, uri=\"%s\")", http, uri)); return (http_send(http, HTTP_STATE_PUT, uri)); } /* * 'httpRead()' - Read data from a HTTP connection. * * This function is deprecated. Use the httpRead2() function which can * read more than 2GB of data. * * @deprecated@ */ int /* O - Number of bytes read */ httpRead(http_t *http, /* I - HTTP connection */ char *buffer, /* I - Buffer for data */ int length) /* I - Maximum number of bytes */ { return ((int)httpRead2(http, buffer, (size_t)length)); } /* * 'httpRead2()' - Read data from a HTTP connection. * * @since CUPS 1.2/macOS 10.5@ */ ssize_t /* O - Number of bytes read */ httpRead2(http_t *http, /* I - HTTP connection */ char *buffer, /* I - Buffer for data */ size_t length) /* I - Maximum number of bytes */ { ssize_t bytes; /* Bytes read */ #ifdef HAVE_LIBZ DEBUG_printf(("httpRead2(http=%p, buffer=%p, length=" HTMLDOC_LLFMT ") coding=%d data_encoding=%d data_remaining=" HTMLDOC_LLFMT, http, buffer, HTMLDOC_LLCAST length, http->coding, http->data_encoding, HTMLDOC_LLCAST http->data_remaining)); #else DEBUG_printf(("httpRead2(http=%p, buffer=%p, length=" HTMLDOC_LLFMT ") data_encoding=%d data_remaining=" HTMLDOC_LLFMT, http, buffer, HTMLDOC_LLCAST length, http->data_encoding, HTMLDOC_LLCAST http->data_remaining)); #endif /* HAVE_LIBZ */ if (http == NULL || buffer == NULL) return (-1); http->activity = time(NULL); http->error = 0; if (length <= 0) return (0); #ifdef HAVE_LIBZ if (http->coding >= _HTTP_CODING_GUNZIP) { do { if (http->stream.avail_in > 0) { int zerr; /* Decompressor error */ DEBUG_printf(("2httpRead2: avail_in=%d, avail_out=%d", (int)http->stream.avail_in, (int)length)); http->stream.next_out = (Bytef *)buffer; http->stream.avail_out = (uInt)length; if ((zerr = inflate(&(http->stream), Z_SYNC_FLUSH)) < Z_OK) { DEBUG_printf(("2httpRead2: zerr=%d", zerr)); #ifdef DEBUG http_debug_hex("2httpRead2", (char *)http->sbuffer, (int)http->stream.avail_in); #endif /* DEBUG */ http->error = EIO; return (-1); } bytes = (ssize_t)(length - http->stream.avail_out); DEBUG_printf(("2httpRead2: avail_in=%d, avail_out=%d, bytes=%d", http->stream.avail_in, http->stream.avail_out, (int)bytes)); } else bytes = 0; if (bytes == 0) { ssize_t buflen = HTTP_MAX_BUFFER - (ssize_t)http->stream.avail_in; /* Additional bytes for buffer */ if (buflen > 0) { if (http->stream.avail_in > 0 && http->stream.next_in > http->sbuffer) memmove(http->sbuffer, http->stream.next_in, http->stream.avail_in); http->stream.next_in = http->sbuffer; DEBUG_printf(("1httpRead2: Reading up to %d more bytes of data into " "decompression buffer.", (int)buflen)); if (http->data_remaining > 0) { if (buflen > http->data_remaining) buflen = (ssize_t)http->data_remaining; bytes = http_read_buffered(http, (char *)http->sbuffer + http->stream.avail_in, (size_t)buflen); } else if (http->data_encoding == HTTP_ENCODING_CHUNKED) bytes = http_read_chunk(http, (char *)http->sbuffer + http->stream.avail_in, (size_t)buflen); else bytes = 0; if (bytes < 0) return (bytes); else if (bytes == 0) break; DEBUG_printf(("1httpRead2: Adding " HTMLDOC_LLFMT " bytes to " "decompression buffer.", HTMLDOC_LLCAST bytes)); http->data_remaining -= bytes; http->stream.avail_in += (uInt)bytes; if (http->data_remaining <= 0 && http->data_encoding == HTTP_ENCODING_CHUNKED) { /* * Read the trailing blank line now... */ char len[32]; /* Length string */ httpGets(len, sizeof(len), http); } bytes = 0; } else return (0); } } while (bytes == 0); } else #endif /* HAVE_LIBZ */ if (http->data_remaining == 0 && http->data_encoding == HTTP_ENCODING_CHUNKED) { if ((bytes = http_read_chunk(http, buffer, length)) > 0) { http->data_remaining -= bytes; if (http->data_remaining <= 0) { /* * Read the trailing blank line now... */ char len[32]; /* Length string */ httpGets(len, sizeof(len), http); } } } else if (http->data_remaining <= 0) { /* * No more data to read... */ return (0); } else { DEBUG_printf(("1httpRead2: Reading up to %d bytes into buffer.", (int)length)); if (length > (size_t)http->data_remaining) length = (size_t)http->data_remaining; if ((bytes = http_read_buffered(http, buffer, length)) > 0) { http->data_remaining -= bytes; if (http->data_remaining <= 0 && http->data_encoding == HTTP_ENCODING_CHUNKED) { /* * Read the trailing blank line now... */ char len[32]; /* Length string */ httpGets(len, sizeof(len), http); } } } if ( #ifdef HAVE_LIBZ (http->coding == _HTTP_CODING_IDENTITY || (http->coding >= _HTTP_CODING_GUNZIP && http->stream.avail_in == 0)) && #endif /* HAVE_LIBZ */ ((http->data_remaining <= 0 && http->data_encoding == HTTP_ENCODING_LENGTH) || (http->data_encoding == HTTP_ENCODING_CHUNKED && bytes == 0))) { #ifdef HAVE_LIBZ if (http->coding >= _HTTP_CODING_GUNZIP) http_content_coding_finish(http); #endif /* HAVE_LIBZ */ if (http->state == HTTP_STATE_POST_RECV) http->state ++; else if (http->state == HTTP_STATE_GET_SEND || http->state == HTTP_STATE_POST_SEND) http->state = HTTP_STATE_WAITING; else http->state = HTTP_STATE_STATUS; DEBUG_printf(("1httpRead2: End of content, set state to %s.", httpStateString(http->state))); } return (bytes); } /* * 'httpReadRequest()' - Read a HTTP request from a connection. * * @since CUPS 1.7/macOS 10.9@ */ http_state_t /* O - New state of connection */ httpReadRequest(http_t *http, /* I - HTTP connection */ char *uri, /* I - URI buffer */ size_t urilen) /* I - Size of URI buffer */ { char line[4096], /* HTTP request line */ *req_method, /* HTTP request method */ *req_uri, /* HTTP request URI */ *req_version; /* HTTP request version number string */ /* * Range check input... */ DEBUG_printf(("httpReadRequest(http=%p, uri=%p, urilen=" HTMLDOC_LLFMT ")", http, uri, HTMLDOC_LLCAST urilen)); if (uri) *uri = '\0'; if (!http || !uri || urilen < 1) { DEBUG_puts("1httpReadRequest: Bad arguments, returning HTTP_STATE_ERROR."); return (HTTP_STATE_ERROR); } else if (http->state != HTTP_STATE_WAITING) { DEBUG_printf(("1httpReadRequest: Bad state %s, returning HTTP_STATE_ERROR.", httpStateString(http->state))); return (HTTP_STATE_ERROR); } /* * Reset state... */ httpClearFields(http); http->activity = time(NULL); http->data_encoding = HTTP_ENCODING_FIELDS; http->data_remaining = 0; http->keep_alive = HTTP_KEEPALIVE_OFF; http->status = HTTP_STATUS_OK; http->version = HTTP_VERSION_1_1; /* * Read a line from the socket... */ if (!httpGets(line, sizeof(line), http)) { DEBUG_puts("1httpReadRequest: Unable to read, returning HTTP_STATE_ERROR"); return (HTTP_STATE_ERROR); } if (!line[0]) { DEBUG_puts("1httpReadRequest: Blank line, returning HTTP_STATE_WAITING"); return (HTTP_STATE_WAITING); } DEBUG_printf(("1httpReadRequest: %s", line)); /* * Parse it... */ req_method = line; req_uri = line; while (*req_uri && !isspace(*req_uri & 255)) req_uri ++; if (!*req_uri) { DEBUG_puts("1httpReadRequest: No request URI."); _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("No request URI."), 1); return (HTTP_STATE_ERROR); } *req_uri++ = '\0'; while (*req_uri && isspace(*req_uri & 255)) req_uri ++; req_version = req_uri; while (*req_version && !isspace(*req_version & 255)) req_version ++; if (!*req_version) { DEBUG_puts("1httpReadRequest: No request protocol version."); _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("No request protocol version."), 1); return (HTTP_STATE_ERROR); } *req_version++ = '\0'; while (*req_version && isspace(*req_version & 255)) req_version ++; /* * Validate... */ if (!strcmp(req_method, "OPTIONS")) http->state = HTTP_STATE_OPTIONS; else if (!strcmp(req_method, "GET")) http->state = HTTP_STATE_GET; else if (!strcmp(req_method, "HEAD")) http->state = HTTP_STATE_HEAD; else if (!strcmp(req_method, "POST")) http->state = HTTP_STATE_POST; else if (!strcmp(req_method, "PUT")) http->state = HTTP_STATE_PUT; else if (!strcmp(req_method, "DELETE")) http->state = HTTP_STATE_DELETE; else if (!strcmp(req_method, "TRACE")) http->state = HTTP_STATE_TRACE; else if (!strcmp(req_method, "CONNECT")) http->state = HTTP_STATE_CONNECT; else { DEBUG_printf(("1httpReadRequest: Unknown method \"%s\".", req_method)); _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Unknown request method."), 1); return (HTTP_STATE_UNKNOWN_METHOD); } DEBUG_printf(("1httpReadRequest: Set state to %s.", httpStateString(http->state))); if (!strcmp(req_version, "HTTP/1.0")) { http->version = HTTP_VERSION_1_0; http->keep_alive = HTTP_KEEPALIVE_OFF; } else if (!strcmp(req_version, "HTTP/1.1")) { http->version = HTTP_VERSION_1_1; http->keep_alive = HTTP_KEEPALIVE_ON; } else { DEBUG_printf(("1httpReadRequest: Unknown version \"%s\".", req_version)); _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Unknown request version."), 1); return (HTTP_STATE_UNKNOWN_VERSION); } DEBUG_printf(("1httpReadRequest: URI is \"%s\".", req_uri)); strlcpy(uri, req_uri, urilen); return (http->state); } /* * 'httpReconnect()' - Reconnect to a HTTP server. * * This function is deprecated. Please use the @link httpReconnect2@ function * instead. * * @deprecated@ */ int /* O - 0 on success, non-zero on failure */ httpReconnect(http_t *http) /* I - HTTP connection */ { DEBUG_printf(("httpReconnect(http=%p)", http)); return (httpReconnect2(http, 30000, NULL)); } /* * 'httpReconnect2()' - Reconnect to a HTTP server with timeout and optional * cancel. */ int /* O - 0 on success, non-zero on failure */ httpReconnect2(http_t *http, /* I - HTTP connection */ int msec, /* I - Timeout in milliseconds */ int *cancel) /* I - Pointer to "cancel" variable */ { http_addrlist_t *addr; /* Connected address */ #ifdef DEBUG http_addrlist_t *current; /* Current address */ #endif /* DEBUG */ DEBUG_printf(("httpReconnect2(http=%p, msec=%d, cancel=%p)", http, msec, cancel)); if (!http) { _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(EINVAL), 0); return (-1); } #ifdef HAVE_SSL if (http->tls) { DEBUG_puts("2httpReconnect2: Shutting down SSL/TLS..."); _httpTLSStop(http); } #endif /* HAVE_SSL */ /* * Close any previously open socket... */ if (http->fd >= 0) { DEBUG_printf(("2httpReconnect2: Closing socket %d...", http->fd)); httpAddrClose(NULL, http->fd); http->fd = -1; } /* * Reset all state (except fields, which may be reused)... */ http->state = HTTP_STATE_WAITING; http->version = HTTP_VERSION_1_1; http->keep_alive = HTTP_KEEPALIVE_OFF; memset(&http->_hostaddr, 0, sizeof(http->_hostaddr)); http->data_encoding = HTTP_ENCODING_FIELDS; http->_data_remaining = 0; http->used = 0; http->data_remaining = 0; http->hostaddr = NULL; http->wused = 0; /* * Connect to the server... */ #ifdef DEBUG for (current = http->addrlist; current; current = current->next) DEBUG_printf(("2httpReconnect2: Address %s:%d", httpAddrString(&(current->addr), temp, sizeof(temp)), httpAddrPort(&(current->addr)))); #endif /* DEBUG */ if ((addr = httpAddrConnect2(http->addrlist, &(http->fd), msec, cancel)) == NULL) { /* * Unable to connect... */ #ifdef WIN32 http->error = WSAGetLastError(); #else http->error = errno; #endif /* WIN32 */ http->status = HTTP_STATUS_ERROR; DEBUG_printf(("1httpReconnect2: httpAddrConnect failed: %s", strerror(http->error))); return (-1); } DEBUG_printf(("2httpReconnect2: New socket=%d", http->fd)); if (http->timeout_value > 0) http_set_timeout(http->fd, http->timeout_value); http->hostaddr = &(addr->addr); http->error = 0; #ifdef HAVE_SSL if (http->encryption == HTTP_ENCRYPTION_ALWAYS) { /* * Always do encryption via SSL. */ if (_httpTLSStart(http) != 0) { httpAddrClose(NULL, http->fd); return (-1); } } else if (http->encryption == HTTP_ENCRYPTION_REQUIRED && !http->tls_upgrade) return (http_tls_upgrade(http)); #endif /* HAVE_SSL */ DEBUG_printf(("1httpReconnect2: Connected to %s:%d...", httpAddrString(http->hostaddr, temp, sizeof(temp)), httpAddrPort(http->hostaddr))); return (0); } /* * 'httpSetAuthString()' - Set the current authorization string. * * This function just stores a copy of the current authorization string in * the HTTP connection object. You must still call httpSetField() to set * HTTP_FIELD_AUTHORIZATION prior to issuing a HTTP request using httpGet(), * httpHead(), httpOptions(), httpPost, or httpPut(). * * @since CUPS 1.3/macOS 10.5@ */ void httpSetAuthString(http_t *http, /* I - HTTP connection */ const char *scheme, /* I - Auth scheme (NULL to clear it) */ const char *data) /* I - Auth data (NULL for none) */ { /* * Range check input... */ if (!http) return; if (http->authstring && http->authstring != http->_authstring) free(http->authstring); http->authstring = http->_authstring; if (scheme) { /* * Set the current authorization string... */ size_t len = strlen(scheme) + (data ? strlen(data) + 1 : 0) + 1; char *temp; if (len > sizeof(http->_authstring)) { if ((temp = malloc(len)) == NULL) len = sizeof(http->_authstring); else http->authstring = temp; } if (data) snprintf(http->authstring, len, "%s %s", scheme, data); else strlcpy(http->authstring, scheme, len); } else { /* * Clear the current authorization string... */ http->_authstring[0] = '\0'; } } /* * 'httpSetCredentials()' - Set the credentials associated with an encrypted * connection. * * @since CUPS 1.5/macOS 10.7@ */ int /* O - Status of call (0 = success) */ httpSetCredentials(http_t *http, /* I - HTTP connection */ cups_array_t *credentials) /* I - Array of credentials */ { if (!http || cupsArrayCount(credentials) < 1) return (-1); #ifdef HAVE_SSL _httpFreeCredentials(http->tls_credentials); http->tls_credentials = _httpCreateCredentials(credentials); #endif /* HAVE_SSL */ return (http->tls_credentials ? 0 : -1); } /* * 'httpSetCookie()' - Set the cookie value(s). * * @since CUPS 1.1.19/macOS 10.3@ */ void httpSetCookie(http_t *http, /* I - Connection */ const char *cookie) /* I - Cookie string */ { if (!http) return; if (http->cookie) free(http->cookie); if (cookie) http->cookie = strdup(cookie); else http->cookie = NULL; } /* * 'httpSetDefaultField()' - Set the default value of an HTTP header. * * Currently only @code HTTP_FIELD_ACCEPT_ENCODING@, @code HTTP_FIELD_SERVER@, * and @code HTTP_FIELD_USER_AGENT@ can be set. * * @since CUPS 1.7/macOS 10.9@ */ void httpSetDefaultField(http_t *http, /* I - HTTP connection */ http_field_t field, /* I - Field index */ const char *value)/* I - Value */ { DEBUG_printf(("httpSetDefaultField(http=%p, field=%d(%s), value=\"%s\")", http, field, http_fields[field], value)); if (!http) return; switch (field) { case HTTP_FIELD_ACCEPT_ENCODING : if (http->default_accept_encoding) free(http->default_accept_encoding); http->default_accept_encoding = value ? strdup(value) : NULL; break; case HTTP_FIELD_SERVER : if (http->default_server) free(http->default_server); http->default_server = value ? strdup(value) : NULL; break; case HTTP_FIELD_USER_AGENT : if (http->default_user_agent) free(http->default_user_agent); http->default_user_agent = value ? strdup(value) : NULL; break; default : DEBUG_puts("1httpSetDefaultField: Ignored."); break; } } /* * 'httpSetExpect()' - Set the Expect: header in a request. * * Currently only @code HTTP_STATUS_CONTINUE@ is supported for the "expect" * argument. * * @since CUPS 1.2/macOS 10.5@ */ void httpSetExpect(http_t *http, /* I - HTTP connection */ http_status_t expect) /* I - HTTP status to expect (@code HTTP_STATUS_CONTINUE@) */ { DEBUG_printf(("httpSetExpect(http=%p, expect=%d)", http, expect)); if (http) http->expect = expect; } /* * 'httpSetField()' - Set the value of an HTTP header. */ void httpSetField(http_t *http, /* I - HTTP connection */ http_field_t field, /* I - Field index */ const char *value) /* I - Value */ { DEBUG_printf(("httpSetField(http=%p, field=%d(%s), value=\"%s\")", http, field, http_fields[field], value)); if (http == NULL || field < HTTP_FIELD_ACCEPT_LANGUAGE || field >= HTTP_FIELD_MAX || value == NULL) return; switch (field) { case HTTP_FIELD_ACCEPT_ENCODING : if (http->accept_encoding) free(http->accept_encoding); http->accept_encoding = strdup(value); break; case HTTP_FIELD_ALLOW : if (http->allow) free(http->allow); http->allow = strdup(value); break; case HTTP_FIELD_SERVER : if (http->server) free(http->server); http->server = strdup(value); break; case HTTP_FIELD_WWW_AUTHENTICATE : /* CUPS STR #4503 - don't override WWW-Authenticate for unknown auth schemes */ if (http->fields[HTTP_FIELD_WWW_AUTHENTICATE][0] && _cups_strncasecmp(value, "Basic ", 6) && _cups_strncasecmp(value, "Digest ", 7) && _cups_strncasecmp(value, "Negotiate ", 10)) { DEBUG_printf(("1httpSetField: Ignoring unknown auth scheme in \"%s\".", value)); return; } /* Fall through to copy */ default : strlcpy(http->fields[field], value, HTTP_MAX_VALUE); break; } if (field == HTTP_FIELD_AUTHORIZATION) { /* * Special case for Authorization: as its contents can be * longer than HTTP_MAX_VALUE */ if (http->field_authorization) free(http->field_authorization); http->field_authorization = strdup(value); } else if (field == HTTP_FIELD_HOST) { /* * Special-case for Host: as we don't want a trailing "." on the hostname and * need to bracket IPv6 numeric addresses. */ char *ptr = strchr(value, ':'); if (value[0] != '[' && ptr && strchr(ptr + 1, ':')) { /* * Bracket IPv6 numeric addresses... * * This is slightly inefficient (basically copying twice), but is an edge * case and not worth optimizing... */ snprintf(http->fields[HTTP_FIELD_HOST], sizeof(http->fields[HTTP_FIELD_HOST]), "[%s]", value); } else { /* * Check for a trailing dot on the hostname... */ ptr = http->fields[HTTP_FIELD_HOST]; if (*ptr) { ptr += strlen(ptr) - 1; if (*ptr == '.') *ptr = '\0'; } } } #ifdef HAVE_LIBZ else if (field == HTTP_FIELD_CONTENT_ENCODING && http->data_encoding != HTTP_ENCODING_FIELDS) { DEBUG_puts("1httpSetField: Calling http_content_coding_start."); http_content_coding_start(http, value); } #endif /* HAVE_LIBZ */ } /* * 'httpSetKeepAlive()' - Set the current Keep-Alive state of a connection. * * @since CUPS 2.0/OS 10.10@ */ void httpSetKeepAlive( http_t *http, /* I - HTTP connection */ http_keepalive_t keep_alive) /* I - New Keep-Alive value */ { if (http) http->keep_alive = keep_alive; } /* * 'httpSetLength()' - Set the content-length and content-encoding. * * @since CUPS 1.2/macOS 10.5@ */ void httpSetLength(http_t *http, /* I - HTTP connection */ size_t length) /* I - Length (0 for chunked) */ { DEBUG_printf(("httpSetLength(http=%p, length=" HTMLDOC_LLFMT ")", http, HTMLDOC_LLCAST length)); if (!http) return; if (!length) { strlcpy(http->fields[HTTP_FIELD_TRANSFER_ENCODING], "chunked", HTTP_MAX_VALUE); http->fields[HTTP_FIELD_CONTENT_LENGTH][0] = '\0'; } else { http->fields[HTTP_FIELD_TRANSFER_ENCODING][0] = '\0'; snprintf(http->fields[HTTP_FIELD_CONTENT_LENGTH], HTTP_MAX_VALUE, HTMLDOC_LLFMT, HTMLDOC_LLCAST length); } } /* * 'httpSetTimeout()' - Set read/write timeouts and an optional callback. * * The optional timeout callback receives both the HTTP connection and a user * data pointer and must return 1 to continue or 0 to error (time) out. * * @since CUPS 1.5/macOS 10.7@ */ void httpSetTimeout( http_t *http, /* I - HTTP connection */ double timeout, /* I - Number of seconds for timeout, must be greater than 0 */ http_timeout_cb_t cb, /* I - Callback function or NULL */ void *user_data) /* I - User data pointer */ { if (!http || timeout <= 0.0) return; http->timeout_cb = cb; http->timeout_data = user_data; http->timeout_value = timeout; if (http->fd >= 0) http_set_timeout(http->fd, timeout); http_set_wait(http); } /* * 'httpShutdown()' - Shutdown one side of an HTTP connection. * * @since CUPS 2.0/OS 10.10@ */ void httpShutdown(http_t *http) /* I - HTTP connection */ { if (!http || http->fd < 0) return; #ifdef HAVE_SSL if (http->tls) _httpTLSStop(http); #endif /* HAVE_SSL */ #ifdef WIN32 shutdown(http->fd, SD_RECEIVE); /* Microsoft-ism... */ #else shutdown(http->fd, SHUT_RD); #endif /* WIN32 */ } /* * 'httpTrace()' - Send an TRACE request to the server. */ int /* O - Status of call (0 = success) */ httpTrace(http_t *http, /* I - HTTP connection */ const char *uri) /* I - URI for trace */ { return (http_send(http, HTTP_STATE_TRACE, uri)); } /* * '_httpUpdate()' - Update the current HTTP status for incoming data. * * Note: Unlike httpUpdate(), this function does not flush pending write data * and only retrieves a single status line from the HTTP connection. */ int /* O - 1 to continue, 0 to stop */ _httpUpdate(http_t *http, /* I - HTTP connection */ http_status_t *status) /* O - Current HTTP status */ { char line[32768], /* Line from connection... */ *value; /* Pointer to value on line */ http_field_t field; /* Field index */ int major, minor; /* HTTP version numbers */ DEBUG_printf(("_httpUpdate(http=%p, status=%p), state=%s", http, status, httpStateString(http->state))); /* * Grab a single line from the connection... */ if (!httpGets(line, sizeof(line), http)) { *status = HTTP_STATUS_ERROR; return (0); } DEBUG_printf(("2_httpUpdate: Got \"%s\"", line)); if (line[0] == '\0') { /* * Blank line means the start of the data section (if any). Return * the result code, too... * * If we get status 100 (HTTP_STATUS_CONTINUE), then we *don't* change * states. Instead, we just return HTTP_STATUS_CONTINUE to the caller and * keep on tryin'... */ if (http->status == HTTP_STATUS_CONTINUE) { *status = http->status; return (0); } if (http->status < HTTP_STATUS_BAD_REQUEST) http->digest_tries = 0; #ifdef HAVE_SSL if (http->status == HTTP_STATUS_SWITCHING_PROTOCOLS && !http->tls) { if (_httpTLSStart(http) != 0) { httpAddrClose(NULL, http->fd); *status = http->status = HTTP_STATUS_ERROR; return (0); } *status = HTTP_STATUS_CONTINUE; return (0); } #endif /* HAVE_SSL */ if (http_set_length(http) < 0) { DEBUG_puts("1_httpUpdate: Bad Content-Length."); http->error = EINVAL; http->status = *status = HTTP_STATUS_ERROR; return (0); } switch (http->state) { case HTTP_STATE_GET : case HTTP_STATE_POST : case HTTP_STATE_POST_RECV : case HTTP_STATE_PUT : http->state ++; DEBUG_printf(("1_httpUpdate: Set state to %s.", httpStateString(http->state))); case HTTP_STATE_POST_SEND : case HTTP_STATE_HEAD : break; default : http->state = HTTP_STATE_WAITING; DEBUG_puts("1_httpUpdate: Reset state to HTTP_STATE_WAITING."); break; } #ifdef HAVE_LIBZ DEBUG_puts("1_httpUpdate: Calling http_content_coding_start."); http_content_coding_start(http, httpGetField(http, HTTP_FIELD_CONTENT_ENCODING)); #endif /* HAVE_LIBZ */ *status = http->status; return (0); } else if (!strncmp(line, "HTTP/", 5) && http->mode == _HTTP_MODE_CLIENT) { /* * Got the beginning of a response... */ int intstatus; /* Status value as an integer */ if (sscanf(line, "HTTP/%d.%d%d", &major, &minor, &intstatus) != 3) { *status = http->status = HTTP_STATUS_ERROR; return (0); } httpClearFields(http); http->version = (http_version_t)(major * 100 + minor); *status = http->status = (http_status_t)intstatus; } else if ((value = strchr(line, ':')) != NULL) { /* * Got a value... */ *value++ = '\0'; while (_cups_isspace(*value)) value ++; DEBUG_printf(("1_httpUpdate: Header %s: %s", line, value)); /* * Be tolerants of servers that send unknown attribute fields... */ if (!_cups_strcasecmp(line, "expect")) { /* * "Expect: 100-continue" or similar... */ http->expect = (http_status_t)atoi(value); } else if (!_cups_strcasecmp(line, "cookie")) { /* * "Cookie: name=value[; name=value ...]" - replaces previous cookies... */ httpSetCookie(http, value); } else if ((field = httpFieldValue(line)) != HTTP_FIELD_UNKNOWN) httpSetField(http, field, value); #ifdef DEBUG else DEBUG_printf(("1_httpUpdate: unknown field %s seen!", line)); #endif /* DEBUG */ } else { DEBUG_printf(("1_httpUpdate: Bad response line \"%s\"!", line)); http->error = EINVAL; http->status = *status = HTTP_STATUS_ERROR; return (0); } return (1); } /* * 'httpUpdate()' - Update the current HTTP state for incoming data. */ http_status_t /* O - HTTP status */ httpUpdate(http_t *http) /* I - HTTP connection */ { http_status_t status; /* Request status */ DEBUG_printf(("httpUpdate(http=%p), state=%s", http, httpStateString(http->state))); /* * Flush pending data, if any... */ if (http->wused) { DEBUG_puts("2httpUpdate: flushing buffer..."); if (httpFlushWrite(http) < 0) return (HTTP_STATUS_ERROR); } /* * If we haven't issued any commands, then there is nothing to "update"... */ if (http->state == HTTP_STATE_WAITING) return (HTTP_STATUS_CONTINUE); /* * Grab all of the lines we can from the connection... */ while (_httpUpdate(http, &status)); /* * See if there was an error... */ if (http->error == EPIPE && http->status > HTTP_STATUS_CONTINUE) { DEBUG_printf(("1httpUpdate: Returning status %d...", http->status)); return (http->status); } if (http->error) { DEBUG_printf(("1httpUpdate: socket error %d - %s", http->error, strerror(http->error))); http->status = HTTP_STATUS_ERROR; return (HTTP_STATUS_ERROR); } /* * Return the current status... */ return (status); } /* * '_httpWait()' - Wait for data available on a connection (no flush). */ int /* O - 1 if data is available, 0 otherwise */ _httpWait(http_t *http, /* I - HTTP connection */ int msec, /* I - Milliseconds to wait */ int usessl) /* I - Use SSL context? */ { #ifdef HAVE_POLL struct pollfd pfd; /* Polled file descriptor */ #else fd_set input_set; /* select() input set */ struct timeval timeout; /* Timeout */ #endif /* HAVE_POLL */ int nfds; /* Result from select()/poll() */ DEBUG_printf(("4_httpWait(http=%p, msec=%d, usessl=%d)", http, msec, usessl)); if (http->fd < 0) { DEBUG_printf(("5_httpWait: Returning 0 since fd=%d", http->fd)); return (0); } /* * Check the SSL/TLS buffers for data first... */ #ifdef HAVE_SSL if (http->tls && _httpTLSPending(http)) { DEBUG_puts("5_httpWait: Return 1 since there is pending TLS data."); return (1); } #endif /* HAVE_SSL */ /* * Then try doing a select() or poll() to poll the socket... */ #ifdef HAVE_POLL pfd.fd = http->fd; pfd.events = POLLIN; do { nfds = poll(&pfd, 1, msec); } while (nfds < 0 && (errno == EINTR || errno == EAGAIN)); #else do { FD_ZERO(&input_set); FD_SET(http->fd, &input_set); DEBUG_printf(("6_httpWait: msec=%d, http->fd=%d", msec, http->fd)); if (msec >= 0) { timeout.tv_sec = msec / 1000; timeout.tv_usec = (msec % 1000) * 1000; nfds = select(http->fd + 1, &input_set, NULL, NULL, &timeout); } else nfds = select(http->fd + 1, &input_set, NULL, NULL, NULL); DEBUG_printf(("6_httpWait: select() returned %d...", nfds)); } # ifdef WIN32 while (nfds < 0 && (WSAGetLastError() == WSAEINTR || WSAGetLastError() == WSAEWOULDBLOCK)); # else while (nfds < 0 && (errno == EINTR || errno == EAGAIN)); # endif /* WIN32 */ #endif /* HAVE_POLL */ DEBUG_printf(("5_httpWait: returning with nfds=%d, errno=%d...", nfds, errno)); return (nfds > 0); } /* * 'httpWait()' - Wait for data available on a connection. * * @since CUPS 1.1.19/macOS 10.3@ */ int /* O - 1 if data is available, 0 otherwise */ httpWait(http_t *http, /* I - HTTP connection */ int msec) /* I - Milliseconds to wait */ { /* * First see if there is data in the buffer... */ DEBUG_printf(("2httpWait(http=%p, msec=%d)", http, msec)); if (http == NULL) return (0); if (http->used) { DEBUG_puts("3httpWait: Returning 1 since there is buffered data ready."); return (1); } #ifdef HAVE_LIBZ if (http->coding >= _HTTP_CODING_GUNZIP && http->stream.avail_in > 0) { DEBUG_puts("3httpWait: Returning 1 since there is buffered data ready."); return (1); } #endif /* HAVE_LIBZ */ /* * Flush pending data, if any... */ if (http->wused) { DEBUG_puts("3httpWait: Flushing write buffer."); if (httpFlushWrite(http) < 0) return (0); } /* * If not, check the SSL/TLS buffers and do a select() on the connection... */ return (_httpWait(http, msec, 1)); } /* * 'httpWrite()' - Write data to a HTTP connection. * * This function is deprecated. Use the httpWrite2() function which can * write more than 2GB of data. * * @deprecated@ */ int /* O - Number of bytes written */ httpWrite(http_t *http, /* I - HTTP connection */ const char *buffer, /* I - Buffer for data */ int length) /* I - Number of bytes to write */ { return ((int)httpWrite2(http, buffer, (size_t)length)); } /* * 'httpWrite2()' - Write data to a HTTP connection. * * @since CUPS 1.2/macOS 10.5@ */ ssize_t /* O - Number of bytes written */ httpWrite2(http_t *http, /* I - HTTP connection */ const char *buffer, /* I - Buffer for data */ size_t length) /* I - Number of bytes to write */ { ssize_t bytes; /* Bytes written */ DEBUG_printf(("httpWrite2(http=%p, buffer=%p, length=" HTMLDOC_LLFMT ")", http, buffer, HTMLDOC_LLCAST length)); /* * Range check input... */ if (!http || !buffer) { DEBUG_puts("1httpWrite2: Returning -1 due to bad input."); return (-1); } /* * Mark activity on the connection... */ http->activity = time(NULL); /* * Buffer small writes for better performance... */ #ifdef HAVE_LIBZ if (http->coding == _HTTP_CODING_GZIP || http->coding == _HTTP_CODING_DEFLATE) { DEBUG_printf(("1httpWrite2: http->coding=%d", http->coding)); if (length == 0) { http_content_coding_finish(http); bytes = 0; } else { size_t slen; /* Bytes to write */ ssize_t sret; /* Bytes written */ http->stream.next_in = (Bytef *)buffer; http->stream.avail_in = (uInt)length; while (deflate(&(http->stream), Z_NO_FLUSH) == Z_OK) { DEBUG_printf(("1httpWrite2: avail_out=%d", http->stream.avail_out)); if (http->stream.avail_out > 0) continue; slen = _HTTP_MAX_SBUFFER - http->stream.avail_out; DEBUG_printf(("1httpWrite2: Writing intermediate chunk, len=%d", (int)slen)); if (slen > 0 && http->data_encoding == HTTP_ENCODING_CHUNKED) sret = http_write_chunk(http, (char *)http->sbuffer, slen); else if (slen > 0) sret = http_write(http, (char *)http->sbuffer, slen); else sret = 0; if (sret < 0) { DEBUG_puts("1httpWrite2: Unable to write, returning -1."); return (-1); } http->stream.next_out = (Bytef *)http->sbuffer; http->stream.avail_out = (uInt)_HTTP_MAX_SBUFFER; } bytes = (ssize_t)length; } } else #endif /* HAVE_LIBZ */ if (length > 0) { if (http->wused && (length + (size_t)http->wused) > sizeof(http->wbuffer)) { DEBUG_printf(("2httpWrite2: Flushing buffer (wused=%d, length=" HTMLDOC_LLFMT ")", http->wused, HTMLDOC_LLCAST length)); httpFlushWrite(http); } if ((length + (size_t)http->wused) <= sizeof(http->wbuffer) && length < sizeof(http->wbuffer)) { /* * Write to buffer... */ DEBUG_printf(("2httpWrite2: Copying " HTMLDOC_LLFMT " bytes to wbuffer...", HTMLDOC_LLCAST length)); memcpy(http->wbuffer + http->wused, buffer, length); http->wused += (int)length; bytes = (ssize_t)length; } else { /* * Otherwise write the data directly... */ DEBUG_printf(("2httpWrite2: Writing " HTMLDOC_LLFMT " bytes to socket...", HTMLDOC_LLCAST length)); if (http->data_encoding == HTTP_ENCODING_CHUNKED) bytes = (ssize_t)http_write_chunk(http, buffer, length); else bytes = (ssize_t)http_write(http, buffer, length); DEBUG_printf(("2httpWrite2: Wrote " HTMLDOC_LLFMT " bytes...", HTMLDOC_LLCAST bytes)); } if (http->data_encoding == HTTP_ENCODING_LENGTH) http->data_remaining -= bytes; } else bytes = 0; /* * Handle end-of-request processing... */ if ((http->data_encoding == HTTP_ENCODING_CHUNKED && length == 0) || (http->data_encoding == HTTP_ENCODING_LENGTH && http->data_remaining == 0)) { /* * Finished with the transfer; unless we are sending POST or PUT * data, go idle... */ #ifdef HAVE_LIBZ if (http->coding == _HTTP_CODING_GZIP || http->coding == _HTTP_CODING_DEFLATE) http_content_coding_finish(http); #endif /* HAVE_LIBZ */ if (http->wused) { if (httpFlushWrite(http) < 0) return (-1); } if (http->data_encoding == HTTP_ENCODING_CHUNKED) { /* * Send a 0-length chunk at the end of the request... */ http_write(http, "0\r\n\r\n", 5); /* * Reset the data state... */ http->data_encoding = HTTP_ENCODING_FIELDS; http->data_remaining = 0; } if (http->state == HTTP_STATE_POST_RECV) http->state ++; else if (http->state == HTTP_STATE_POST_SEND || http->state == HTTP_STATE_GET_SEND) http->state = HTTP_STATE_WAITING; else http->state = HTTP_STATE_STATUS; DEBUG_printf(("2httpWrite2: Changed state to %s.", httpStateString(http->state))); } DEBUG_printf(("1httpWrite2: Returning " HTMLDOC_LLFMT ".", HTMLDOC_LLCAST bytes)); return (bytes); } /* * 'httpWriteResponse()' - Write a HTTP response to a client connection. * * @since CUPS 1.7/macOS 10.9@ */ int /* O - 0 on success, -1 on error */ httpWriteResponse(http_t *http, /* I - HTTP connection */ http_status_t status) /* I - Status code */ { http_encoding_t old_encoding; /* Old data_encoding value */ off_t old_remaining; /* Old data_remaining value */ /* * Range check input... */ DEBUG_printf(("httpWriteResponse(http=%p, status=%d)", http, status)); if (!http || status < HTTP_STATUS_CONTINUE) { DEBUG_puts("1httpWriteResponse: Bad input."); return (-1); } /* * Set the various standard fields if they aren't already... */ if (!http->fields[HTTP_FIELD_DATE][0]) httpSetField(http, HTTP_FIELD_DATE, httpGetDateString(time(NULL))); if (status >= HTTP_STATUS_BAD_REQUEST && http->keep_alive) { http->keep_alive = HTTP_KEEPALIVE_OFF; httpSetField(http, HTTP_FIELD_KEEP_ALIVE, ""); } if (http->version == HTTP_VERSION_1_1) { if (!http->fields[HTTP_FIELD_CONNECTION][0]) { if (http->keep_alive) httpSetField(http, HTTP_FIELD_CONNECTION, "Keep-Alive"); else httpSetField(http, HTTP_FIELD_CONNECTION, "close"); } if (http->keep_alive && !http->fields[HTTP_FIELD_KEEP_ALIVE][0]) httpSetField(http, HTTP_FIELD_KEEP_ALIVE, "timeout=10"); } #ifdef HAVE_SSL if (status == HTTP_STATUS_UPGRADE_REQUIRED || status == HTTP_STATUS_SWITCHING_PROTOCOLS) { if (!http->fields[HTTP_FIELD_CONNECTION][0]) httpSetField(http, HTTP_FIELD_CONNECTION, "Upgrade"); if (!http->fields[HTTP_FIELD_UPGRADE][0]) httpSetField(http, HTTP_FIELD_UPGRADE, "TLS/1.2,TLS/1.1,TLS/1.0"); if (!http->fields[HTTP_FIELD_CONTENT_LENGTH][0]) httpSetField(http, HTTP_FIELD_CONTENT_LENGTH, "0"); } #endif /* HAVE_SSL */ if (!http->server) httpSetField(http, HTTP_FIELD_SERVER, http->default_server ? http->default_server : "HTMLDOC/" SVERSION); /* * Set the Accept-Encoding field if it isn't already... */ if (!http->accept_encoding) httpSetField(http, HTTP_FIELD_ACCEPT_ENCODING, http->default_accept_encoding ? http->default_accept_encoding : #ifdef HAVE_LIBZ "gzip, deflate, identity"); #else "identity"); #endif /* HAVE_LIBZ */ /* * Send the response header... */ old_encoding = http->data_encoding; old_remaining = http->data_remaining; http->data_encoding = HTTP_ENCODING_FIELDS; if (httpPrintf(http, "HTTP/%d.%d %d %s\r\n", http->version / 100, http->version % 100, (int)status, httpStatus(status)) < 0) { http->status = HTTP_STATUS_ERROR; return (-1); } if (status != HTTP_STATUS_CONTINUE) { /* * 100 Continue doesn't have the rest of the response headers... */ int i; /* Looping var */ const char *value; /* Field value */ for (i = 0; i < HTTP_FIELD_MAX; i ++) { if ((value = httpGetField(http, i)) != NULL && *value) { if (httpPrintf(http, "%s: %s\r\n", http_fields[i], value) < 1) { http->status = HTTP_STATUS_ERROR; return (-1); } } } if (http->cookie) { if (strchr(http->cookie, ';')) { if (httpPrintf(http, "Set-Cookie: %s\r\n", http->cookie) < 1) { http->status = HTTP_STATUS_ERROR; return (-1); } } else if (httpPrintf(http, "Set-Cookie: %s; path=/; httponly;%s\r\n", http->cookie, http->tls ? " secure;" : "") < 1) { http->status = HTTP_STATUS_ERROR; return (-1); } } /* * "Click-jacking" defense (STR #4492)... */ if (httpPrintf(http, "X-Frame-Options: DENY\r\n" "Content-Security-Policy: frame-ancestors 'none'\r\n") < 1) { http->status = HTTP_STATUS_ERROR; return (-1); } } if (httpWrite2(http, "\r\n", 2) < 2) { http->status = HTTP_STATUS_ERROR; return (-1); } if (httpFlushWrite(http) < 0) { http->status = HTTP_STATUS_ERROR; return (-1); } if (status == HTTP_STATUS_CONTINUE || status == HTTP_STATUS_SWITCHING_PROTOCOLS) { /* * Restore the old data_encoding and data_length values... */ http->data_encoding = old_encoding; http->data_remaining = old_remaining; if (old_remaining <= INT_MAX) http->_data_remaining = (int)old_remaining; else http->_data_remaining = INT_MAX; } else if (http->state == HTTP_STATE_OPTIONS || http->state == HTTP_STATE_HEAD || http->state == HTTP_STATE_PUT || http->state == HTTP_STATE_TRACE || http->state == HTTP_STATE_CONNECT || http->state == HTTP_STATE_STATUS) { DEBUG_printf(("1httpWriteResponse: Resetting state to HTTP_STATE_WAITING, " "was %s.", httpStateString(http->state))); http->state = HTTP_STATE_WAITING; } else { /* * Force data_encoding and data_length to be set according to the response * headers... */ http_set_length(http); if (http->data_encoding == HTTP_ENCODING_LENGTH && http->data_remaining == 0) { DEBUG_printf(("1httpWriteResponse: Resetting state to HTTP_STATE_WAITING, " "was %s.", httpStateString(http->state))); http->state = HTTP_STATE_WAITING; return (0); } #ifdef HAVE_LIBZ /* * Then start any content encoding... */ DEBUG_puts("1httpWriteResponse: Calling http_content_coding_start."); http_content_coding_start(http, httpGetField(http, HTTP_FIELD_CONTENT_ENCODING)); #endif /* HAVE_LIBZ */ } return (0); } #ifdef HAVE_LIBZ /* * 'http_content_coding_finish()' - Finish doing any content encoding. */ static void http_content_coding_finish( http_t *http) /* I - HTTP connection */ { int zerr; /* Compression status */ Byte dummy[1]; /* Dummy read buffer */ size_t bytes; /* Number of bytes to write */ DEBUG_printf(("http_content_coding_finish(http=%p)", http)); DEBUG_printf(("1http_content_coding_finishing: http->coding=%d", http->coding)); switch (http->coding) { case _HTTP_CODING_DEFLATE : case _HTTP_CODING_GZIP : http->stream.next_in = dummy; http->stream.avail_in = 0; do { zerr = deflate(&(http->stream), Z_FINISH); bytes = _HTTP_MAX_SBUFFER - http->stream.avail_out; if (bytes > 0) { DEBUG_printf(("1http_content_coding_finish: Writing trailing chunk, len=%d", (int)bytes)); if (http->data_encoding == HTTP_ENCODING_CHUNKED) http_write_chunk(http, (char *)http->sbuffer, bytes); else http_write(http, (char *)http->sbuffer, bytes); } http->stream.next_out = (Bytef *)http->sbuffer; http->stream.avail_out = (uInt)_HTTP_MAX_SBUFFER; } while (zerr == Z_OK); deflateEnd(&(http->stream)); free(http->sbuffer); http->sbuffer = NULL; if (http->wused) httpFlushWrite(http); break; case _HTTP_CODING_INFLATE : case _HTTP_CODING_GUNZIP : inflateEnd(&(http->stream)); free(http->sbuffer); http->sbuffer = NULL; break; default : break; } http->coding = _HTTP_CODING_IDENTITY; } /* * 'http_content_coding_start()' - Start doing content encoding. */ static void http_content_coding_start( http_t *http, /* I - HTTP connection */ const char *value) /* I - Value of Content-Encoding */ { int zerr; /* Error/status */ _http_coding_t coding; /* Content coding value */ DEBUG_printf(("http_content_coding_start(http=%p, value=\"%s\")", http, value)); if (http->coding != _HTTP_CODING_IDENTITY) { DEBUG_printf(("1http_content_coding_start: http->coding already %d.", http->coding)); return; } else if (!strcmp(value, "x-gzip") || !strcmp(value, "gzip")) { if (http->state == HTTP_STATE_GET_SEND || http->state == HTTP_STATE_POST_SEND) coding = http->mode == _HTTP_MODE_SERVER ? _HTTP_CODING_GZIP : _HTTP_CODING_GUNZIP; else if (http->state == HTTP_STATE_POST_RECV || http->state == HTTP_STATE_PUT_RECV) coding = http->mode == _HTTP_MODE_CLIENT ? _HTTP_CODING_GZIP : _HTTP_CODING_GUNZIP; else { DEBUG_puts("1http_content_coding_start: Not doing content coding."); return; } } else if (!strcmp(value, "x-deflate") || !strcmp(value, "deflate")) { if (http->state == HTTP_STATE_GET_SEND || http->state == HTTP_STATE_POST_SEND) coding = http->mode == _HTTP_MODE_SERVER ? _HTTP_CODING_DEFLATE : _HTTP_CODING_INFLATE; else if (http->state == HTTP_STATE_POST_RECV || http->state == HTTP_STATE_PUT_RECV) coding = http->mode == _HTTP_MODE_CLIENT ? _HTTP_CODING_DEFLATE : _HTTP_CODING_INFLATE; else { DEBUG_puts("1http_content_coding_start: Not doing content coding."); return; } } else { DEBUG_puts("1http_content_coding_start: Not doing content coding."); return; } memset(&(http->stream), 0, sizeof(http->stream)); switch (coding) { case _HTTP_CODING_DEFLATE : case _HTTP_CODING_GZIP : if (http->wused) httpFlushWrite(http); if ((http->sbuffer = malloc(_HTTP_MAX_SBUFFER)) == NULL) { http->status = HTTP_STATUS_ERROR; http->error = errno; return; } /* * Window size for compression is 11 bits - optimal based on PWG Raster * sample files on pwg.org. -11 is raw deflate, 27 is gzip, per ZLIB * documentation. */ if ((zerr = deflateInit2(&(http->stream), Z_DEFAULT_COMPRESSION, Z_DEFLATED, coding == _HTTP_CODING_DEFLATE ? -11 : 27, 7, Z_DEFAULT_STRATEGY)) < Z_OK) { http->status = HTTP_STATUS_ERROR; http->error = zerr == Z_MEM_ERROR ? ENOMEM : EINVAL; return; } http->stream.next_out = (Bytef *)http->sbuffer; http->stream.avail_out = (uInt)_HTTP_MAX_SBUFFER; break; case _HTTP_CODING_INFLATE : case _HTTP_CODING_GUNZIP : if ((http->sbuffer = malloc(_HTTP_MAX_SBUFFER)) == NULL) { http->status = HTTP_STATUS_ERROR; http->error = errno; return; } /* * Window size for decompression is up to 15 bits (maximum supported). * -15 is raw inflate, 31 is gunzip, per ZLIB documentation. */ if ((zerr = inflateInit2(&(http->stream), coding == _HTTP_CODING_INFLATE ? -15 : 31)) < Z_OK) { free(http->sbuffer); http->sbuffer = NULL; http->status = HTTP_STATUS_ERROR; http->error = zerr == Z_MEM_ERROR ? ENOMEM : EINVAL; return; } http->stream.avail_in = 0; http->stream.next_in = http->sbuffer; break; default : break; } http->coding = coding; DEBUG_printf(("1http_content_coding_start: http->coding now %d.", http->coding)); } #endif /* HAVE_LIBZ */ /* * 'http_create()' - Create an unconnected HTTP connection. */ static http_t * /* O - HTTP connection */ http_create( const char *host, /* I - Hostname */ int port, /* I - Port number */ http_addrlist_t *addrlist, /* I - Address list or NULL */ int family, /* I - Address family or AF_UNSPEC */ http_encryption_t encryption, /* I - Encryption to use */ int blocking, /* I - 1 for blocking mode */ _http_mode_t mode) /* I - _HTTP_MODE_CLIENT or _SERVER */ { http_t *http; /* New HTTP connection */ char service[255]; /* Service name */ http_addrlist_t *myaddrlist = NULL; /* My address list */ DEBUG_printf(("4http_create(host=\"%s\", port=%d, addrlist=%p, family=%d, " "encryption=%d, blocking=%d, mode=%d)", host, port, addrlist, family, encryption, blocking, mode)); if (!host && mode == _HTTP_MODE_CLIENT) return (NULL); httpInitialize(); /* * Lookup the host... */ if (addrlist) { myaddrlist = httpAddrCopyList(addrlist); } else { snprintf(service, sizeof(service), "%d", port); myaddrlist = httpAddrGetList(host, family, service); } if (!myaddrlist) return (NULL); /* * Allocate memory for the structure... */ if ((http = calloc(sizeof(http_t), 1)) == NULL) { _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(errno), 0); httpAddrFreeList(addrlist); return (NULL); } /* * Initialize the HTTP data... */ http->mode = mode; http->activity = time(NULL); http->addrlist = myaddrlist; http->blocking = blocking; http->fd = -1; #ifdef HAVE_GSSAPI http->gssctx = GSS_C_NO_CONTEXT; http->gssname = GSS_C_NO_NAME; #endif /* HAVE_GSSAPI */ http->status = HTTP_STATUS_CONTINUE; http->version = HTTP_VERSION_1_1; if (host) strlcpy(http->hostname, host, sizeof(http->hostname)); if (port == 443) /* Always use encryption for https */ http->encryption = HTTP_ENCRYPTION_ALWAYS; else http->encryption = encryption; http_set_wait(http); /* * Return the new structure... */ return (http); } #ifdef DEBUG /* * 'http_debug_hex()' - Do a hex dump of a buffer. */ static void http_debug_hex(const char *prefix, /* I - Prefix for line */ const char *buffer, /* I - Buffer to dump */ int bytes) /* I - Bytes to dump */ { int i, j, /* Looping vars */ ch; /* Current character */ char line[255], /* Line buffer */ *start, /* Start of line after prefix */ *ptr; /* Pointer into line */ // if (_cups_debug_fd < 0 || _cups_debug_level < 6) // return; DEBUG_printf(("6%s: %d bytes:", prefix, bytes)); snprintf(line, sizeof(line), "6%s: ", prefix); start = line + strlen(line); for (i = 0; i < bytes; i += 16) { for (j = 0, ptr = start; j < 16 && (i + j) < bytes; j ++, ptr += 2) snprintf(ptr, 3, "%02X", buffer[i + j] & 255); while (j < 16) { memcpy(ptr, " ", 3); ptr += 2; j ++; } memcpy(ptr, " ", 3); ptr += 2; for (j = 0; j < 16 && (i + j) < bytes; j ++) { ch = buffer[i + j] & 255; if (ch < ' ' || ch >= 127) ch = '.'; *ptr++ = (char)ch; } *ptr = '\0'; DEBUG_puts(line); } } #endif /* DEBUG */ /* * 'http_read()' - Read a buffer from a HTTP connection. * * This function does the low-level read from the socket, retrying and timing * out as needed. */ static ssize_t /* O - Number of bytes read or -1 on error */ http_read(http_t *http, /* I - HTTP connection */ char *buffer, /* I - Buffer */ size_t length) /* I - Maximum bytes to read */ { ssize_t bytes; /* Bytes read */ DEBUG_printf(("http_read(http=%p, buffer=%p, length=" HTMLDOC_LLFMT ")", http, buffer, HTMLDOC_LLCAST length)); if (!http->blocking) { while (!httpWait(http, http->wait_value)) { if (http->timeout_cb && (*http->timeout_cb)(http, http->timeout_data)) continue; DEBUG_puts("2http_read: Timeout."); return (0); } } DEBUG_printf(("2http_read: Reading %d bytes into buffer.", (int)length)); do { #ifdef HAVE_SSL if (http->tls) bytes = _httpTLSRead(http, buffer, (int)length); else #endif /* HAVE_SSL */ bytes = recv(http->fd, buffer, length, 0); if (bytes < 0) { #ifdef WIN32 if (WSAGetLastError() != WSAEINTR) { http->error = WSAGetLastError(); return (-1); } else if (WSAGetLastError() == WSAEWOULDBLOCK) { if (!http->timeout_cb || !(*http->timeout_cb)(http, http->timeout_data)) { http->error = WSAEWOULDBLOCK; return (-1); } } #else DEBUG_printf(("2http_read: %s", strerror(errno))); if (errno == EWOULDBLOCK || errno == EAGAIN) { if (http->timeout_cb && !(*http->timeout_cb)(http, http->timeout_data)) { http->error = errno; return (-1); } else if (!http->timeout_cb && errno != EAGAIN) { http->error = errno; return (-1); } } else if (errno != EINTR) { http->error = errno; return (-1); } #endif /* WIN32 */ } } while (bytes < 0); DEBUG_printf(("2http_read: Read " HTMLDOC_LLFMT " bytes into buffer.", HTMLDOC_LLCAST bytes)); #ifdef DEBUG if (bytes > 0) http_debug_hex("http_read", buffer, (int)bytes); #endif /* DEBUG */ if (bytes < 0) { #ifdef WIN32 if (WSAGetLastError() == WSAEINTR) bytes = 0; else http->error = WSAGetLastError(); #else if (errno == EINTR || (errno == EAGAIN && !http->timeout_cb)) bytes = 0; else http->error = errno; #endif /* WIN32 */ } else if (bytes == 0) { http->error = EPIPE; return (0); } return (bytes); } /* * 'http_read_buffered()' - Do a buffered read from a HTTP connection. * * This function reads data from the HTTP buffer or from the socket, as needed. */ static ssize_t /* O - Number of bytes read or -1 on error */ http_read_buffered(http_t *http, /* I - HTTP connection */ char *buffer, /* I - Buffer */ size_t length) /* I - Maximum bytes to read */ { ssize_t bytes; /* Bytes read */ DEBUG_printf(("http_read_buffered(http=%p, buffer=%p, length=" HTMLDOC_LLFMT ") used=%d", http, buffer, HTMLDOC_LLCAST length, http->used)); if (http->used > 0) { if (length > (size_t)http->used) bytes = (ssize_t)http->used; else bytes = (ssize_t)length; DEBUG_printf(("2http_read: Grabbing %d bytes from input buffer.", (int)bytes)); memcpy(buffer, http->buffer, (size_t)bytes); http->used -= (int)bytes; if (http->used > 0) memmove(http->buffer, http->buffer + bytes, (size_t)http->used); } else bytes = http_read(http, buffer, length); return (bytes); } /* * 'http_read_chunk()' - Read a chunk from a HTTP connection. * * This function reads and validates the chunk length, then does a buffered read * returning the number of bytes placed in the buffer. */ static ssize_t /* O - Number of bytes read or -1 on error */ http_read_chunk(http_t *http, /* I - HTTP connection */ char *buffer, /* I - Buffer */ size_t length) /* I - Maximum bytes to read */ { DEBUG_printf(("http_read_chunk(http=%p, buffer=%p, length=" HTMLDOC_LLFMT ")", http, buffer, HTMLDOC_LLCAST length)); if (http->data_remaining <= 0) { char len[32]; /* Length string */ if (!httpGets(len, sizeof(len), http)) { DEBUG_puts("1http_read_chunk: Could not get chunk length."); return (0); } if (!len[0]) { DEBUG_puts("1http_read_chunk: Blank chunk length, trying again..."); if (!httpGets(len, sizeof(len), http)) { DEBUG_puts("1http_read_chunk: Could not get chunk length."); return (0); } } http->data_remaining = strtoll(len, NULL, 16); if (http->data_remaining < 0) { DEBUG_printf(("1http_read_chunk: Negative chunk length \"%s\" (" HTMLDOC_LLFMT ")", len, HTMLDOC_LLCAST http->data_remaining)); return (0); } DEBUG_printf(("2http_read_chunk: Got chunk length \"%s\" (" HTMLDOC_LLFMT ")", len, HTMLDOC_LLCAST http->data_remaining)); if (http->data_remaining == 0) { /* * 0-length chunk, grab trailing blank line... */ httpGets(len, sizeof(len), http); } } DEBUG_printf(("2http_read_chunk: data_remaining=" HTMLDOC_LLFMT, HTMLDOC_LLCAST http->data_remaining)); if (http->data_remaining <= 0) return (0); else if (length > (size_t)http->data_remaining) length = (size_t)http->data_remaining; return (http_read_buffered(http, buffer, length)); } /* * 'http_send()' - Send a request with all fields and the trailing blank line. */ static int /* O - 0 on success, non-zero on error */ http_send(http_t *http, /* I - HTTP connection */ http_state_t request, /* I - Request code */ const char *uri) /* I - URI */ { int i; /* Looping var */ char buf[1024]; /* Encoded URI buffer */ const char *value; /* Field value */ static const char * const codes[] = /* Request code strings */ { NULL, "OPTIONS", "GET", NULL, "HEAD", "POST", NULL, NULL, "PUT", NULL, "DELETE", "TRACE", "CLOSE", NULL, NULL }; DEBUG_printf(("4http_send(http=%p, request=HTTP_%s, uri=\"%s\")", http, codes[request], uri)); if (http == NULL || uri == NULL) return (-1); /* * Set the User-Agent field if it isn't already... */ if (!http->fields[HTTP_FIELD_USER_AGENT][0]) { if (http->default_user_agent) httpSetField(http, HTTP_FIELD_USER_AGENT, http->default_user_agent); else httpSetField(http, HTTP_FIELD_USER_AGENT, "HTMLDOC/" SVERSION); } /* * Set the Accept-Encoding field if it isn't already... */ if (!http->accept_encoding && http->default_accept_encoding) httpSetField(http, HTTP_FIELD_ACCEPT_ENCODING, http->default_accept_encoding); /* * Encode the URI as needed... */ _httpEncodeURI(buf, uri, sizeof(buf)); /* * See if we had an error the last time around; if so, reconnect... */ if (http->fd < 0 || http->status == HTTP_STATUS_ERROR || http->status >= HTTP_STATUS_BAD_REQUEST) { DEBUG_printf(("5http_send: Reconnecting, fd=%d, status=%d, tls_upgrade=%d", http->fd, http->status, http->tls_upgrade)); if (httpReconnect2(http, 30000, NULL)) return (-1); } /* * Flush any written data that is pending... */ if (http->wused) { if (httpFlushWrite(http) < 0) if (httpReconnect2(http, 30000, NULL)) return (-1); } /* * Send the request header... */ http->state = request; http->data_encoding = HTTP_ENCODING_FIELDS; if (request == HTTP_STATE_POST || request == HTTP_STATE_PUT) http->state ++; http->status = HTTP_STATUS_CONTINUE; #ifdef HAVE_SSL if (http->encryption == HTTP_ENCRYPTION_REQUIRED && !http->tls) { httpSetField(http, HTTP_FIELD_CONNECTION, "Upgrade"); httpSetField(http, HTTP_FIELD_UPGRADE, "TLS/1.2,TLS/1.1,TLS/1.0"); } #endif /* HAVE_SSL */ if (httpPrintf(http, "%s %s HTTP/1.1\r\n", codes[request], buf) < 1) { http->status = HTTP_STATUS_ERROR; return (-1); } for (i = 0; i < HTTP_FIELD_MAX; i ++) if ((value = httpGetField(http, i)) != NULL && *value) { DEBUG_printf(("5http_send: %s: %s", http_fields[i], value)); if (i == HTTP_FIELD_HOST) { if (httpPrintf(http, "Host: %s:%d\r\n", value, httpAddrPort(http->hostaddr)) < 1) { http->status = HTTP_STATUS_ERROR; return (-1); } } else if (httpPrintf(http, "%s: %s\r\n", http_fields[i], value) < 1) { http->status = HTTP_STATUS_ERROR; return (-1); } } if (http->cookie) if (httpPrintf(http, "Cookie: $Version=0; %s\r\n", http->cookie) < 1) { http->status = HTTP_STATUS_ERROR; return (-1); } DEBUG_printf(("5http_send: expect=%d, mode=%d, state=%d", http->expect, http->mode, http->state)); if (http->expect == HTTP_STATUS_CONTINUE && http->mode == _HTTP_MODE_CLIENT && (http->state == HTTP_STATE_POST_RECV || http->state == HTTP_STATE_PUT_RECV)) if (httpPrintf(http, "Expect: 100-continue\r\n") < 1) { http->status = HTTP_STATUS_ERROR; return (-1); } if (httpPrintf(http, "\r\n") < 1) { http->status = HTTP_STATUS_ERROR; return (-1); } if (httpFlushWrite(http) < 0) return (-1); http_set_length(http); httpClearFields(http); /* * The Kerberos and AuthRef authentication strings can only be used once... */ if (http->field_authorization && http->authstring && (!strncmp(http->authstring, "Negotiate", 9) || !strncmp(http->authstring, "AuthRef", 7))) { http->_authstring[0] = '\0'; if (http->authstring != http->_authstring) free(http->authstring); http->authstring = http->_authstring; } return (0); } /* * 'http_set_length()' - Set the data_encoding and data_remaining values. */ static off_t /* O - Remainder or -1 on error */ http_set_length(http_t *http) /* I - Connection */ { off_t remaining; /* Remainder */ DEBUG_printf(("http_set_length(http=%p) mode=%d state=%s", http, http->mode, httpStateString(http->state))); if ((remaining = httpGetLength2(http)) >= 0) { if (http->mode == _HTTP_MODE_SERVER && http->state != HTTP_STATE_GET_SEND && http->state != HTTP_STATE_PUT && http->state != HTTP_STATE_POST && http->state != HTTP_STATE_POST_SEND) { DEBUG_puts("1http_set_length: Not setting data_encoding/remaining."); return (remaining); } if (!_cups_strcasecmp(http->fields[HTTP_FIELD_TRANSFER_ENCODING], "chunked")) { DEBUG_puts("1http_set_length: Setting data_encoding to " "HTTP_ENCODING_CHUNKED."); http->data_encoding = HTTP_ENCODING_CHUNKED; } else { DEBUG_puts("1http_set_length: Setting data_encoding to " "HTTP_ENCODING_LENGTH."); http->data_encoding = HTTP_ENCODING_LENGTH; } DEBUG_printf(("1http_set_length: Setting data_remaining to " HTMLDOC_LLFMT ".", HTMLDOC_LLCAST remaining)); http->data_remaining = remaining; if (remaining <= INT_MAX) http->_data_remaining = (int)remaining; else http->_data_remaining = INT_MAX; } return (remaining); } /* * 'http_set_timeout()' - Set the socket timeout values. */ static void http_set_timeout(int fd, /* I - File descriptor */ double timeout) /* I - Timeout in seconds */ { #ifdef WIN32 DWORD tv = (DWORD)(timeout * 1000); /* Timeout in milliseconds */ setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, CUPS_SOCAST &tv, sizeof(tv)); setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, CUPS_SOCAST &tv, sizeof(tv)); #else struct timeval tv; /* Timeout in secs and usecs */ tv.tv_sec = (int)timeout; tv.tv_usec = (int)(1000000 * fmod(timeout, 1.0)); setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, CUPS_SOCAST &tv, sizeof(tv)); setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, CUPS_SOCAST &tv, sizeof(tv)); #endif /* WIN32 */ } /* * 'http_set_wait()' - Set the default wait value for reads. */ static void http_set_wait(http_t *http) /* I - HTTP connection */ { if (http->blocking) { http->wait_value = (int)(http->timeout_value * 1000); if (http->wait_value <= 0) http->wait_value = 60000; } else http->wait_value = 10000; } #ifdef HAVE_SSL /* * 'http_tls_upgrade()' - Force upgrade to TLS encryption. */ static int /* O - Status of connection */ http_tls_upgrade(http_t *http) /* I - HTTP connection */ { int ret; /* Return value */ http_t myhttp; /* Local copy of HTTP data */ DEBUG_printf(("7http_tls_upgrade(%p)", http)); /* * Flush the connection to make sure any previous "Upgrade" message * has been read. */ httpFlush(http); /* * Copy the HTTP data to a local variable so we can do the OPTIONS * request without interfering with the existing request data... */ memcpy(&myhttp, http, sizeof(myhttp)); /* * Send an OPTIONS request to the server, requiring SSL or TLS * encryption on the link... */ http->tls_upgrade = 1; http->field_authorization = NULL; /* Don't free the auth string */ httpClearFields(http); httpSetField(http, HTTP_FIELD_CONNECTION, "upgrade"); httpSetField(http, HTTP_FIELD_UPGRADE, "TLS/1.2,TLS/1.1,TLS/1.0"); if ((ret = httpOptions(http, "*")) == 0) { /* * Wait for the secure connection... */ while (httpUpdate(http) == HTTP_STATUS_CONTINUE); } /* * Restore the HTTP request data... */ memcpy(http->fields, myhttp.fields, sizeof(http->fields)); http->data_encoding = myhttp.data_encoding; http->data_remaining = myhttp.data_remaining; http->_data_remaining = myhttp._data_remaining; http->expect = myhttp.expect; http->field_authorization = myhttp.field_authorization; http->digest_tries = myhttp.digest_tries; http->tls_upgrade = 0; /* * See if we actually went secure... */ if (!http->tls) { /* * Server does not support HTTP upgrade... */ DEBUG_puts("8http_tls_upgrade: Server does not support HTTP upgrade!"); _cupsSetError(IPP_STATUS_ERROR_HTMLDOC_PKI, _("Encryption is not supported."), 1); httpAddrClose(NULL, http->fd); http->fd = -1; return (-1); } else return (ret); } #endif /* HAVE_SSL */ /* * 'http_write()' - Write a buffer to a HTTP connection. */ static ssize_t /* O - Number of bytes written */ http_write(http_t *http, /* I - HTTP connection */ const char *buffer, /* I - Buffer for data */ size_t length) /* I - Number of bytes to write */ { ssize_t tbytes, /* Total bytes sent */ bytes; /* Bytes sent */ DEBUG_printf(("2http_write(http=%p, buffer=%p, length=" HTMLDOC_LLFMT ")", http, buffer, HTMLDOC_LLCAST length)); http->error = 0; tbytes = 0; while (length > 0) { DEBUG_printf(("3http_write: About to write %d bytes.", (int)length)); if (http->timeout_cb) { #ifdef HAVE_POLL struct pollfd pfd; /* Polled file descriptor */ #else fd_set output_set; /* Output ready for write? */ struct timeval timeout; /* Timeout value */ #endif /* HAVE_POLL */ int nfds; /* Result from select()/poll() */ do { #ifdef HAVE_POLL pfd.fd = http->fd; pfd.events = POLLOUT; while ((nfds = poll(&pfd, 1, http->wait_value)) < 0 && (errno == EINTR || errno == EAGAIN)) /* do nothing */; #else do { FD_ZERO(&output_set); FD_SET(http->fd, &output_set); timeout.tv_sec = http->wait_value / 1000; timeout.tv_usec = 1000 * (http->wait_value % 1000); nfds = select(http->fd + 1, NULL, &output_set, NULL, &timeout); } # ifdef WIN32 while (nfds < 0 && (WSAGetLastError() == WSAEINTR || WSAGetLastError() == WSAEWOULDBLOCK)); # else while (nfds < 0 && (errno == EINTR || errno == EAGAIN)); # endif /* WIN32 */ #endif /* HAVE_POLL */ if (nfds < 0) { http->error = errno; return (-1); } else if (nfds == 0 && !(*http->timeout_cb)(http, http->timeout_data)) { #ifdef WIN32 http->error = WSAEWOULDBLOCK; #else http->error = EWOULDBLOCK; #endif /* WIN32 */ return (-1); } } while (nfds <= 0); } #ifdef HAVE_SSL if (http->tls) bytes = _httpTLSWrite(http, buffer, (int)length); else #endif /* HAVE_SSL */ bytes = send(http->fd, buffer, length, 0); DEBUG_printf(("3http_write: Write of " HTMLDOC_LLFMT " bytes returned " HTMLDOC_LLFMT ".", HTMLDOC_LLCAST length, HTMLDOC_LLCAST bytes)); if (bytes < 0) { #ifdef WIN32 if (WSAGetLastError() == WSAEINTR) continue; else if (WSAGetLastError() == WSAEWOULDBLOCK) { if (http->timeout_cb && (*http->timeout_cb)(http, http->timeout_data)) continue; http->error = WSAGetLastError(); } else if (WSAGetLastError() != http->error && WSAGetLastError() != WSAECONNRESET) { http->error = WSAGetLastError(); continue; } #else if (errno == EINTR) continue; else if (errno == EWOULDBLOCK || errno == EAGAIN) { if (http->timeout_cb && (*http->timeout_cb)(http, http->timeout_data)) continue; else if (!http->timeout_cb && errno == EAGAIN) continue; http->error = errno; } else if (errno != http->error && errno != ECONNRESET) { http->error = errno; continue; } #endif /* WIN32 */ DEBUG_printf(("3http_write: error writing data (%s).", strerror(http->error))); return (-1); } buffer += bytes; tbytes += bytes; length -= (size_t)bytes; } #ifdef DEBUG http_debug_hex("http_write", buffer - tbytes, (int)tbytes); #endif /* DEBUG */ DEBUG_printf(("3http_write: Returning " HTMLDOC_LLFMT ".", HTMLDOC_LLCAST tbytes)); return (tbytes); } /* * 'http_write_chunk()' - Write a chunked buffer. */ static ssize_t /* O - Number bytes written */ http_write_chunk(http_t *http, /* I - HTTP connection */ const char *buffer, /* I - Buffer to write */ size_t length) /* I - Length of buffer */ { char header[16]; /* Chunk header */ ssize_t bytes; /* Bytes written */ DEBUG_printf(("7http_write_chunk(http=%p, buffer=%p, length=" HTMLDOC_LLFMT ")", http, buffer, HTMLDOC_LLCAST length)); /* * Write the chunk header, data, and trailer. */ snprintf(header, sizeof(header), "%x\r\n", (unsigned)length); if (http_write(http, header, strlen(header)) < 0) { DEBUG_puts("8http_write_chunk: http_write of length failed."); return (-1); } if ((bytes = http_write(http, buffer, length)) < 0) { DEBUG_puts("8http_write_chunk: http_write of buffer failed."); return (-1); } if (http_write(http, "\r\n", 2) < 0) { DEBUG_puts("8http_write_chunk: http_write of CR LF failed."); return (-1); } return (bytes); } htmldoc-1.9.7/htmldoc/http.h000066400000000000000000000720571354715574200157740ustar00rootroot00000000000000/* * Hyper-Text Transport Protocol definitions for HTMLDOC. * * Copyright 2007-2014 by Apple Inc. * Copyright 1997-2007 by Easy Software Products, all rights reserved. * * This program is free software. Distribution and use rights are outlined in * the file "COPYING". */ #ifndef _CUPS_HTTP_H_ # define _CUPS_HTTP_H_ /* * Include necessary headers... */ # include "array.h" # include # include # include # ifdef WIN32 # ifndef __CUPS_SSIZE_T_DEFINED # define __CUPS_SSIZE_T_DEFINED /* Windows does not support the ssize_t type, so map it to off_t... */ typedef off_t ssize_t; /* @private@ */ # endif /* !__CUPS_SSIZE_T_DEFINED */ # include # include # else # include # include # include # include # include # include # include # include # if !defined(__APPLE__) || !defined(TCP_NODELAY) # include # endif /* !__APPLE__ || !TCP_NODELAY */ # if defined(AF_UNIX) && !defined(AF_LOCAL) # define AF_LOCAL AF_UNIX /* Older UNIX's have old names... */ # endif /* AF_UNIX && !AF_LOCAL */ # ifdef AF_LOCAL # include # endif /* AF_LOCAL */ # if defined(LOCAL_PEERCRED) && !defined(SO_PEERCRED) # define SO_PEERCRED LOCAL_PEERCRED # endif /* LOCAL_PEERCRED && !SO_PEERCRED */ # endif /* WIN32 */ /* * C++ magic... */ # ifdef __cplusplus extern "C" { # endif /* __cplusplus */ /* * Oh, the wonderful world of IPv6 compatibility. Apparently some * implementations expose the (more logical) 32-bit address parts * to everyone, while others only expose it to kernel code... To * make supporting IPv6 even easier, each vendor chose different * core structure and union names, so the same defines or code * can't be used on all platforms. * * The following will likely need tweaking on new platforms that * support IPv6 - the "s6_addr32" define maps to the 32-bit integer * array in the in6_addr union, which is named differently on various * platforms. */ #if defined(AF_INET6) && !defined(s6_addr32) # if defined(__sun) # define s6_addr32 _S6_un._S6_u32 # elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__APPLE__)|| defined(__DragonFly__) # define s6_addr32 __u6_addr.__u6_addr32 # elif defined(WIN32) /* * Windows only defines byte and 16-bit word members of the union and * requires special casing of all raw address code... */ # define s6_addr32 error_need_win32_specific_code # endif /* __sun */ #endif /* AF_INET6 && !s6_addr32 */ /* * Limits... */ # define HTTP_MAX_URI 1024 /* Max length of URI string */ # define HTTP_MAX_HOST 256 /* Max length of hostname string */ # define HTTP_MAX_BUFFER 2048 /* Max length of data buffer */ # define HTTP_MAX_VALUE 256 /* Max header field value length */ /* * Types and structures... */ typedef enum http_auth_e /**** HTTP authentication types ****/ { HTTP_AUTH_NONE, /* No authentication in use */ HTTP_AUTH_BASIC, /* Basic authentication in use */ HTTP_AUTH_MD5, /* Digest authentication in use */ HTTP_AUTH_MD5_SESS, /* MD5-session authentication in use */ HTTP_AUTH_MD5_INT, /* Digest authentication in use for body */ HTTP_AUTH_MD5_SESS_INT, /* MD5-session authentication in use for body */ HTTP_AUTH_NEGOTIATE /* GSSAPI authentication in use @since CUPS 1.3/macOS 10.5@ */ } http_auth_t; typedef enum http_encoding_e /**** HTTP transfer encoding values ****/ { HTTP_ENCODING_LENGTH, /* Data is sent with Content-Length */ HTTP_ENCODING_CHUNKED, /* Data is chunked */ HTTP_ENCODING_FIELDS /* Sending HTTP fields */ # ifndef _CUPS_NO_DEPRECATED # define HTTP_ENCODE_LENGTH HTTP_ENCODING_LENGTH # define HTTP_ENCODE_CHUNKED HTTP_ENCODING_CHUNKED # define HTTP_ENCODE_FIELDS HTTP_ENCODING_FIELDS # endif /* !_CUPS_NO_DEPRECATED */ } http_encoding_t; typedef enum http_encryption_e /**** HTTP encryption values ****/ { HTTP_ENCRYPTION_IF_REQUESTED, /* Encrypt if requested (TLS upgrade) */ HTTP_ENCRYPTION_NEVER, /* Never encrypt */ HTTP_ENCRYPTION_REQUIRED, /* Encryption is required (TLS upgrade) */ HTTP_ENCRYPTION_ALWAYS /* Always encrypt (SSL) */ # ifndef _CUPS_NO_DEPRECATED # define HTTP_ENCRYPT_IF_REQUESTED HTTP_ENCRYPTION_IF_REQUESTED # define HTTP_ENCRYPT_NEVER HTTP_ENCRYPTION_NEVER # define HTTP_ENCRYPT_REQUIRED HTTP_ENCRYPTION_REQUIRED # define HTTP_ENCRYPT_ALWAYS HTTP_ENCRYPTION_ALWAYS # endif /* !_CUPS_NO_DEPRECATED */ } http_encryption_t; typedef enum http_field_e /**** HTTP field names ****/ { HTTP_FIELD_UNKNOWN = -1, /* Unknown field */ HTTP_FIELD_ACCEPT_LANGUAGE, /* Accept-Language field */ HTTP_FIELD_ACCEPT_RANGES, /* Accept-Ranges field */ HTTP_FIELD_AUTHORIZATION, /* Authorization field */ HTTP_FIELD_CONNECTION, /* Connection field */ HTTP_FIELD_CONTENT_ENCODING, /* Content-Encoding field */ HTTP_FIELD_CONTENT_LANGUAGE, /* Content-Language field */ HTTP_FIELD_CONTENT_LENGTH, /* Content-Length field */ HTTP_FIELD_CONTENT_LOCATION, /* Content-Location field */ HTTP_FIELD_CONTENT_MD5, /* Content-MD5 field */ HTTP_FIELD_CONTENT_RANGE, /* Content-Range field */ HTTP_FIELD_CONTENT_TYPE, /* Content-Type field */ HTTP_FIELD_CONTENT_VERSION, /* Content-Version field */ HTTP_FIELD_DATE, /* Date field */ HTTP_FIELD_HOST, /* Host field */ HTTP_FIELD_IF_MODIFIED_SINCE, /* If-Modified-Since field */ HTTP_FIELD_IF_UNMODIFIED_SINCE, /* If-Unmodified-Since field */ HTTP_FIELD_KEEP_ALIVE, /* Keep-Alive field */ HTTP_FIELD_LAST_MODIFIED, /* Last-Modified field */ HTTP_FIELD_LINK, /* Link field */ HTTP_FIELD_LOCATION, /* Location field */ HTTP_FIELD_RANGE, /* Range field */ HTTP_FIELD_REFERER, /* Referer field */ HTTP_FIELD_RETRY_AFTER, /* Retry-After field */ HTTP_FIELD_TRANSFER_ENCODING, /* Transfer-Encoding field */ HTTP_FIELD_UPGRADE, /* Upgrade field */ HTTP_FIELD_USER_AGENT, /* User-Agent field */ HTTP_FIELD_WWW_AUTHENTICATE, /* WWW-Authenticate field */ HTTP_FIELD_ACCEPT_ENCODING, /* Accepting-Encoding field @since CUPS 1.7/macOS 10.9@ */ HTTP_FIELD_ALLOW, /* Allow field @since CUPS 1.7/macOS 10.9@ */ HTTP_FIELD_SERVER, /* Server field @since CUPS 1.7/macOS 10.9@ */ HTTP_FIELD_MAX /* Maximum field index */ } http_field_t; typedef enum http_keepalive_e /**** HTTP keep-alive values ****/ { HTTP_KEEPALIVE_OFF = 0, /* No keep alive support */ HTTP_KEEPALIVE_ON /* Use keep alive */ } http_keepalive_t; typedef enum http_state_e /**** HTTP state values; states **** are server-oriented... ****/ { HTTP_STATE_ERROR = -1, /* Error on socket */ HTTP_STATE_WAITING, /* Waiting for command */ HTTP_STATE_OPTIONS, /* OPTIONS command, waiting for blank line */ HTTP_STATE_GET, /* GET command, waiting for blank line */ HTTP_STATE_GET_SEND, /* GET command, sending data */ HTTP_STATE_HEAD, /* HEAD command, waiting for blank line */ HTTP_STATE_POST, /* POST command, waiting for blank line */ HTTP_STATE_POST_RECV, /* POST command, receiving data */ HTTP_STATE_POST_SEND, /* POST command, sending data */ HTTP_STATE_PUT, /* PUT command, waiting for blank line */ HTTP_STATE_PUT_RECV, /* PUT command, receiving data */ HTTP_STATE_DELETE, /* DELETE command, waiting for blank line */ HTTP_STATE_TRACE, /* TRACE command, waiting for blank line */ HTTP_STATE_CONNECT, /* CONNECT command, waiting for blank line */ HTTP_STATE_STATUS, /* Command complete, sending status */ HTTP_STATE_UNKNOWN_METHOD, /* Unknown request method, waiting for blank line @since CUPS 1.7/macOS 10.9@ */ HTTP_STATE_UNKNOWN_VERSION /* Unknown request method, waiting for blank line @since CUPS 1.7/macOS 10.9@ */ # ifndef _CUPS_NO_DEPRECATED # define HTTP_WAITING HTTP_STATE_WAITING # define HTTP_OPTIONS HTTP_STATE_OPTIONS # define HTTP_GET HTTP_STATE_GET # define HTTP_GET_SEND HTTP_STATE_GET_SEND # define HTTP_HEAD HTTP_STATE_HEAD # define HTTP_POST HTTP_STATE_POST # define HTTP_POST_RECV HTTP_STATE_POST_RECV # define HTTP_POST_SEND HTTP_STATE_POST_SEND # define HTTP_PUT HTTP_STATE_PUT # define HTTP_PUT_RECV HTTP_STATE_PUT_RECV # define HTTP_DELETE HTTP_STATE_DELETE # define HTTP_TRACE HTTP_STATE_TRACE # define HTTP_CLOSE HTTP_STATE_CONNECT # define HTTP_STATUS HTTP_STATE_STATUS # endif /* !_CUPS_NO_DEPRECATED */ } http_state_t; typedef enum http_status_e /**** HTTP status codes ****/ { HTTP_STATUS_ERROR = -1, /* An error response from httpXxxx() */ HTTP_STATUS_NONE = 0, /* No Expect value @since CUPS 1.7/macOS 10.9@ */ HTTP_STATUS_CONTINUE = 100, /* Everything OK, keep going... */ HTTP_STATUS_SWITCHING_PROTOCOLS, /* HTTP upgrade to TLS/SSL */ HTTP_STATUS_OK = 200, /* OPTIONS/GET/HEAD/POST/TRACE command was successful */ HTTP_STATUS_CREATED, /* PUT command was successful */ HTTP_STATUS_ACCEPTED, /* DELETE command was successful */ HTTP_STATUS_NOT_AUTHORITATIVE, /* Information isn't authoritative */ HTTP_STATUS_NO_CONTENT, /* Successful command, no new data */ HTTP_STATUS_RESET_CONTENT, /* Content was reset/recreated */ HTTP_STATUS_PARTIAL_CONTENT, /* Only a partial file was received/sent */ HTTP_STATUS_MULTIPLE_CHOICES = 300, /* Multiple files match request */ HTTP_STATUS_MOVED_PERMANENTLY, /* Document has moved permanently */ HTTP_STATUS_MOVED_TEMPORARILY, /* Document has moved temporarily */ HTTP_STATUS_SEE_OTHER, /* See this other link... */ HTTP_STATUS_NOT_MODIFIED, /* File not modified */ HTTP_STATUS_USE_PROXY, /* Must use a proxy to access this URI */ HTTP_STATUS_BAD_REQUEST = 400, /* Bad request */ HTTP_STATUS_UNAUTHORIZED, /* Unauthorized to access host */ HTTP_STATUS_PAYMENT_REQUIRED, /* Payment required */ HTTP_STATUS_FORBIDDEN, /* Forbidden to access this URI */ HTTP_STATUS_NOT_FOUND, /* URI was not found */ HTTP_STATUS_METHOD_NOT_ALLOWED, /* Method is not allowed */ HTTP_STATUS_NOT_ACCEPTABLE, /* Not Acceptable */ HTTP_STATUS_PROXY_AUTHENTICATION, /* Proxy Authentication is Required */ HTTP_STATUS_REQUEST_TIMEOUT, /* Request timed out */ HTTP_STATUS_CONFLICT, /* Request is self-conflicting */ HTTP_STATUS_GONE, /* Server has gone away */ HTTP_STATUS_LENGTH_REQUIRED, /* A content length or encoding is required */ HTTP_STATUS_PRECONDITION, /* Precondition failed */ HTTP_STATUS_REQUEST_TOO_LARGE, /* Request entity too large */ HTTP_STATUS_URI_TOO_LONG, /* URI too long */ HTTP_STATUS_UNSUPPORTED_MEDIATYPE, /* The requested media type is unsupported */ HTTP_STATUS_REQUESTED_RANGE, /* The requested range is not satisfiable */ HTTP_STATUS_EXPECTATION_FAILED, /* The expectation given in an Expect header field was not met */ HTTP_STATUS_UPGRADE_REQUIRED = 426, /* Upgrade to SSL/TLS required */ HTTP_STATUS_SERVER_ERROR = 500, /* Internal server error */ HTTP_STATUS_NOT_IMPLEMENTED, /* Feature not implemented */ HTTP_STATUS_BAD_GATEWAY, /* Bad gateway */ HTTP_STATUS_SERVICE_UNAVAILABLE, /* Service is unavailable */ HTTP_STATUS_GATEWAY_TIMEOUT, /* Gateway connection timed out */ HTTP_STATUS_NOT_SUPPORTED, /* HTTP version not supported */ HTTP_STATUS_CUPS_AUTHORIZATION_CANCELED = 1000, /* User canceled authorization @since CUPS 1.4@ */ HTTP_STATUS_CUPS_PKI_ERROR, /* Error negotiating a secure connection @since CUPS 1.5/macOS 10.7@ */ HTTP_STATUS_CUPS_WEBIF_DISABLED /* Web interface is disabled @private@ */ # ifndef _CUPS_NO_DEPRECATED /* Old names for this enumeration */ # define HTTP_ERROR HTTP_STATUS_ERROR # define HTTP_CONTINUE HTTP_STATUS_CONTINUE # define HTTP_SWITCHING_PROTOCOLS HTTP_STATUS_SWITCHING_PROTOCOLS # define HTTP_OK HTTP_STATUS_OK # define HTTP_CREATED HTTP_STATUS_CREATED # define HTTP_ACCEPTED HTTP_STATUS_ACCEPTED # define HTTP_NOT_AUTHORITATIVE HTTP_STATUS_NOT_AUTHORITATIVE # define HTTP_NO_CONTENT HTTP_STATUS_NO_CONTENT # define HTTP_RESET_CONTENT HTTP_STATUS_RESET_CONTENT # define HTTP_PARTIAL_CONTENT HTTP_STATUS_PARTIAL_CONTENT # define HTTP_MULTIPLE_CHOICES HTTP_STATUS_MULTIPLE_CHOICES # define HTTP_MOVED_PERMANENTLY HTTP_STATUS_MOVED_PERMANENTLY # define HTTP_MOVED_TEMPORARILY HTTP_STATUS_MOVED_TEMPORARILY # define HTTP_SEE_OTHER HTTP_STATUS_SEE_OTHER # define HTTP_NOT_MODIFIED HTTP_STATUS_NOT_MODIFIED # define HTTP_USE_PROXY HTTP_STATUS_USE_PROXY # define HTTP_BAD_REQUEST HTTP_STATUS_BAD_REQUEST # define HTTP_UNAUTHORIZED HTTP_STATUS_UNAUTHORIZED # define HTTP_PAYMENT_REQUIRED HTTP_STATUS_PAYMENT_REQUIRED # define HTTP_FORBIDDEN HTTP_STATUS_FORBIDDEN # define HTTP_NOT_FOUND HTTP_STATUS_NOT_FOUND # define HTTP_METHOD_NOT_ALLOWED HTTP_STATUS_METHOD_NOT_ALLOWED # define HTTP_NOT_ACCEPTABLE HTTP_STATUS_NOT_ACCEPTABLE # define HTTP_PROXY_AUTHENTICATION HTTP_STATUS_PROXY_AUTHENTICATION # define HTTP_REQUEST_TIMEOUT HTTP_STATUS_REQUEST_TIMEOUT # define HTTP_CONFLICT HTTP_STATUS_CONFLICT # define HTTP_GONE HTTP_STATUS_GONE # define HTTP_LENGTH_REQUIRED HTTP_STATUS_LENGTH_REQUIRED # define HTTP_PRECONDITION HTTP_STATUS_PRECONDITION # define HTTP_REQUEST_TOO_LARGE HTTP_STATUS_REQUEST_TOO_LARGE # define HTTP_URI_TOO_LONG HTTP_STATUS_URI_TOO_LONG # define HTTP_UNSUPPORTED_MEDIATYPE HTTP_STATUS_UNSUPPORTED_MEDIATYPE # define HTTP_REQUESTED_RANGE HTTP_STATUS_REQUESTED_RANGE # define HTTP_EXPECTATION_FAILED HTTP_STATUS_EXPECTATION_FAILED # define HTTP_UPGRADE_REQUIRED HTTP_STATUS_UPGRADE_REQUIRED # define HTTP_SERVER_ERROR HTTP_STATUS_SERVER_ERROR # define HTTP_NOT_IMPLEMENTED HTTP_STATUS_NOT_IMPLEMENTED # define HTTP_BAD_GATEWAY HTTP_STATUS_BAD_GATEWAY # define HTTP_SERVICE_UNAVAILABLE HTTP_STATUS_SERVICE_UNAVAILABLE # define HTTP_GATEWAY_TIMEOUT HTTP_STATUS_GATEWAY_TIMEOUT # define HTTP_NOT_SUPPORTED HTTP_STATUS_NOT_SUPPORTED # define HTTP_AUTHORIZATION_CANCELED HTTP_STATUS_CUPS_AUTHORIZATION_CANCELED # define HTTP_PKI_ERROR HTTP_STATUS_CUPS_PKI_ERROR # define HTTP_WEBIF_DISABLED HTTP_STATUS_CUPS_WEBIF_DISABLED # endif /* !_CUPS_NO_DEPRECATED */ } http_status_t; typedef enum http_trust_e /**** Level of trust for credentials @since CUPS 2.0/OS 10.10@ */ { HTTP_TRUST_OK = 0, /* Credentials are OK/trusted */ HTTP_TRUST_INVALID, /* Credentials are invalid */ HTTP_TRUST_CHANGED, /* Credentials have changed */ HTTP_TRUST_EXPIRED, /* Credentials are expired */ HTTP_TRUST_RENEWED, /* Credentials have been renewed */ HTTP_TRUST_UNKNOWN, /* Credentials are unknown/new */ } http_trust_t; typedef enum http_uri_status_e /**** URI separation status @since CUPS 1.2@ ****/ { HTTP_URI_STATUS_OVERFLOW = -8, /* URI buffer for httpAssembleURI is too small */ HTTP_URI_STATUS_BAD_ARGUMENTS = -7, /* Bad arguments to function (error) */ HTTP_URI_STATUS_BAD_RESOURCE = -6, /* Bad resource in URI (error) */ HTTP_URI_STATUS_BAD_PORT = -5, /* Bad port number in URI (error) */ HTTP_URI_STATUS_BAD_HOSTNAME = -4, /* Bad hostname in URI (error) */ HTTP_URI_STATUS_BAD_USERNAME = -3, /* Bad username in URI (error) */ HTTP_URI_STATUS_BAD_SCHEME = -2, /* Bad scheme in URI (error) */ HTTP_URI_STATUS_BAD_URI = -1, /* Bad/empty URI (error) */ HTTP_URI_STATUS_OK = 0, /* URI decoded OK */ HTTP_URI_STATUS_MISSING_SCHEME, /* Missing scheme in URI (warning) */ HTTP_URI_STATUS_UNKNOWN_SCHEME, /* Unknown scheme in URI (warning) */ HTTP_URI_STATUS_MISSING_RESOURCE /* Missing resource in URI (warning) */ # ifndef _CUPS_NO_DEPRECATED # define HTTP_URI_OVERFLOW HTTP_URI_STATUS_OVERFLOW # define HTTP_URI_BAD_ARGUMENTS HTTP_URI_STATUS_BAD_ARGUMENTS # define HTTP_URI_BAD_RESOURCE HTTP_URI_STATUS_BAD_RESOURCE # define HTTP_URI_BAD_PORT HTTP_URI_STATUS_BAD_PORT # define HTTP_URI_BAD_HOSTNAME HTTP_URI_STATUS_BAD_HOSTNAME # define HTTP_URI_BAD_USERNAME HTTP_URI_STATUS_BAD_USERNAME # define HTTP_URI_BAD_SCHEME HTTP_URI_STATUS_BAD_SCHEME # define HTTP_URI_BAD_URI HTTP_URI_STATUS_BAD_URI # define HTTP_URI_OK HTTP_URI_STATUS_OK # define HTTP_URI_MISSING_SCHEME HTTP_URI_STATUS_MISSING_SCHEME # define HTTP_URI_UNKNOWN_SCHEME HTTP_URI_STATUS_UNKNOWN_SCHEME # define HTTP_URI_MISSING_RESOURCE HTTP_URI_STATUS_MISSING_RESOURCE # endif /* !_CUPS_NO_DEPRECATED */ } http_uri_status_t; typedef enum http_uri_coding_e /**** URI en/decode flags ****/ { HTTP_URI_CODING_NONE = 0, /* Don't en/decode anything */ HTTP_URI_CODING_USERNAME = 1, /* En/decode the username portion */ HTTP_URI_CODING_HOSTNAME = 2, /* En/decode the hostname portion */ HTTP_URI_CODING_RESOURCE = 4, /* En/decode the resource portion */ HTTP_URI_CODING_MOST = 7, /* En/decode all but the query */ HTTP_URI_CODING_QUERY = 8, /* En/decode the query portion */ HTTP_URI_CODING_ALL = 15, /* En/decode everything */ HTTP_URI_CODING_RFC6874 = 16 /* Use RFC 6874 address format */ } http_uri_coding_t; typedef enum http_version_e /**** HTTP version numbers ****/ { HTTP_VERSION_0_9 = 9, /* HTTP/0.9 */ HTTP_VERSION_1_0 = 100, /* HTTP/1.0 */ HTTP_VERSION_1_1 = 101 /* HTTP/1.1 */ # ifndef _CUPS_NO_DEPRECATED # define HTTP_0_9 HTTP_VERSION_0_9 # define HTTP_1_0 HTTP_VERSION_1_0 # define HTTP_1_1 HTTP_VERSION_1_1 # endif /* !_CUPS_NO_DEPRECATED */ } http_version_t; typedef union _http_addr_u /**** Socket address union, which **** makes using IPv6 and other **** address types easier and **** more portable. @since CUPS 1.2/macOS 10.5@ ****/ { struct sockaddr addr; /* Base structure for family value */ struct sockaddr_in ipv4; /* IPv4 address */ #ifdef AF_INET6 struct sockaddr_in6 ipv6; /* IPv6 address */ #endif /* AF_INET6 */ #ifdef AF_LOCAL struct sockaddr_un un; /* Domain socket file */ #endif /* AF_LOCAL */ char pad[256]; /* Padding to ensure binary compatibility */ } http_addr_t; typedef struct http_addrlist_s /**** Socket address list, which is **** used to enumerate all of the **** addresses that are associated **** with a hostname. @since CUPS 1.2/macOS 10.5@ ****/ { struct http_addrlist_s *next; /* Pointer to next address in list */ http_addr_t addr; /* Address */ } http_addrlist_t; typedef struct _http_s http_t; /**** HTTP connection type ****/ typedef struct http_credential_s /**** HTTP credential data @since CUPS 1.5/macOS 10.7@ ****/ { void *data; /* Pointer to credential data */ size_t datalen; /* Credential length */ } http_credential_t; typedef int (*http_timeout_cb_t)(http_t *http, void *user_data); /**** HTTP timeout callback @since CUPS 1.5/macOS 10.7@ ****/ /* * Prototypes... */ extern void httpBlocking(http_t *http, int b); extern int httpCheck(http_t *http); extern void httpClearFields(http_t *http); extern void httpClose(http_t *http); extern http_t *httpConnect(const char *host, int port) _CUPS_DEPRECATED_1_7_MSG("Use httpConnect2 instead."); extern http_t *httpConnectEncrypt(const char *host, int port, http_encryption_t encryption) _CUPS_DEPRECATED_1_7_MSG("Use httpConnect2 instead."); extern int httpDelete(http_t *http, const char *uri); extern int httpEncryption(http_t *http, http_encryption_t e); extern int httpError(http_t *http); extern void httpFlush(http_t *http); extern int httpGet(http_t *http, const char *uri); extern char *httpGets(char *line, int length, http_t *http); extern const char *httpGetDateString(time_t t); extern time_t httpGetDateTime(const char *s); extern const char *httpGetField(http_t *http, http_field_t field); extern struct hostent *httpGetHostByName(const char *name); extern char *httpGetSubField(http_t *http, http_field_t field, const char *name, char *value); extern int httpHead(http_t *http, const char *uri); extern void httpInitialize(void); extern int httpOptions(http_t *http, const char *uri); extern int httpPost(http_t *http, const char *uri); extern int httpPrintf(http_t *http, const char *format, ...) __attribute__ ((__format__ (__printf__, 2, 3))); extern int httpPut(http_t *http, const char *uri); extern int httpRead(http_t *http, char *buffer, int length) _CUPS_DEPRECATED_MSG("Use httpRead2 instead."); extern int httpReconnect(http_t *http) _CUPS_DEPRECATED_1_6_MSG("Use httpReconnect2 instead."); extern void httpSeparate(const char *uri, char *method, char *username, char *host, int *port, char *resource) _CUPS_DEPRECATED_MSG("Use httpSeparateURI instead."); extern void httpSetField(http_t *http, http_field_t field, const char *value); extern const char *httpStatus(http_status_t status); extern int httpTrace(http_t *http, const char *uri); extern http_status_t httpUpdate(http_t *http); extern int httpWrite(http_t *http, const char *buffer, int length) _CUPS_DEPRECATED_MSG("Use httpWrite2 instead."); extern char *httpEncode64(char *out, const char *in) _CUPS_DEPRECATED_MSG("Use httpEncode64_2 instead."); extern char *httpDecode64(char *out, const char *in) _CUPS_DEPRECATED_MSG("Use httpDecode64_2 instead."); extern int httpGetLength(http_t *http) _CUPS_DEPRECATED_MSG("Use httpGetLength2 instead."); extern char *httpMD5(const char *, const char *, const char *, char [33]); extern char *httpMD5Final(const char *, const char *, const char *, char [33]); extern char *httpMD5String(const unsigned char *, char [33]); /**** New in CUPS 1.1.19 ****/ extern void httpClearCookie(http_t *http) _CUPS_API_1_1_19; extern const char *httpGetCookie(http_t *http) _CUPS_API_1_1_19; extern void httpSetCookie(http_t *http, const char *cookie) _CUPS_API_1_1_19; extern int httpWait(http_t *http, int msec) _CUPS_API_1_1_19; /**** New in CUPS 1.1.21 ****/ extern char *httpDecode64_2(char *out, int *outlen, const char *in) _CUPS_API_1_1_21; extern char *httpEncode64_2(char *out, int outlen, const char *in, int inlen) _CUPS_API_1_1_21; extern void httpSeparate2(const char *uri, char *method, int methodlen, char *username, int usernamelen, char *host, int hostlen, int *port, char *resource, int resourcelen) _CUPS_DEPRECATED_MSG("Use httpSeparateURI instead."); /**** New in CUPS 1.2/macOS 10.5 ****/ extern int httpAddrAny(const http_addr_t *addr) _CUPS_API_1_2; extern http_addrlist_t *httpAddrConnect(http_addrlist_t *addrlist, int *sock) _CUPS_API_1_2; extern int httpAddrEqual(const http_addr_t *addr1, const http_addr_t *addr2) _CUPS_API_1_2; extern void httpAddrFreeList(http_addrlist_t *addrlist) _CUPS_API_1_2; extern http_addrlist_t *httpAddrGetList(const char *hostname, int family, const char *service) _CUPS_API_1_2; extern int httpAddrLength(const http_addr_t *addr) _CUPS_API_1_2; extern int httpAddrLocalhost(const http_addr_t *addr) _CUPS_API_1_2; extern char *httpAddrLookup(const http_addr_t *addr, char *name, int namelen) _CUPS_API_1_2; extern char *httpAddrString(const http_addr_t *addr, char *s, int slen) _CUPS_API_1_2; extern http_uri_status_t httpAssembleURI(http_uri_coding_t encoding, char *uri, int urilen, const char *scheme, const char *username, const char *host, int port, const char *resource) _CUPS_API_1_2; extern http_uri_status_t httpAssembleURIf(http_uri_coding_t encoding, char *uri, int urilen, const char *scheme, const char *username, const char *host, int port, const char *resourcef, ...) _CUPS_API_1_2; extern int httpFlushWrite(http_t *http) _CUPS_API_1_2; extern int httpGetBlocking(http_t *http) _CUPS_API_1_2; extern const char *httpGetDateString2(time_t t, char *s, int slen) _CUPS_API_1_2; extern int httpGetFd(http_t *http) _CUPS_API_1_2; extern const char *httpGetHostname(http_t *http, char *s, int slen) _CUPS_API_1_2; extern off_t httpGetLength2(http_t *http) _CUPS_API_1_2; extern http_status_t httpGetStatus(http_t *http) _CUPS_API_1_2; extern char *httpGetSubField2(http_t *http, http_field_t field, const char *name, char *value, int valuelen) _CUPS_API_1_2; extern ssize_t httpRead2(http_t *http, char *buffer, size_t length) _CUPS_API_1_2; extern http_uri_status_t httpSeparateURI(http_uri_coding_t decoding, const char *uri, char *scheme, int schemelen, char *username, int usernamelen, char *host, int hostlen, int *port, char *resource, int resourcelen) _CUPS_API_1_2; extern void httpSetExpect(http_t *http, http_status_t expect) _CUPS_API_1_2; extern void httpSetLength(http_t *http, size_t length) _CUPS_API_1_2; extern ssize_t httpWrite2(http_t *http, const char *buffer, size_t length) _CUPS_API_1_2; /**** New in CUPS 1.3/macOS 10.5 ****/ extern char *httpGetAuthString(http_t *http) _CUPS_API_1_3; extern void httpSetAuthString(http_t *http, const char *scheme, const char *data) _CUPS_API_1_3; /**** New in CUPS 1.5/macOS 10.7 ****/ extern int httpAddCredential(cups_array_t *credentials, const void *data, size_t datalen) _CUPS_API_1_5; extern int httpCopyCredentials(http_t *http, cups_array_t **credentials) _CUPS_API_1_5; extern void httpFreeCredentials(cups_array_t *certs) _CUPS_API_1_5; extern int httpSetCredentials(http_t *http, cups_array_t *certs) _CUPS_API_1_5; extern void httpSetTimeout(http_t *http, double timeout, http_timeout_cb_t cb, void *user_data) _CUPS_API_1_5; /**** New in CUPS 1.6/macOS 10.8 ****/ extern http_addrlist_t *httpAddrConnect2(http_addrlist_t *addrlist, int *sock, int msec, int *cancel) _CUPS_API_1_6; extern http_state_t httpGetState(http_t *http) _CUPS_API_1_6; extern http_version_t httpGetVersion(http_t *http) _CUPS_API_1_6; extern int httpReconnect2(http_t *http, int msec, int *cancel) _CUPS_API_1_6; /**** New in CUPS 1.7/macOS 10.9 ****/ extern http_t *httpAcceptConnection(int fd, int blocking) _CUPS_API_1_7; extern http_addrlist_t *httpAddrCopyList(http_addrlist_t *src) _CUPS_API_1_7; extern int httpAddrListen(http_addr_t *addr, int port) _CUPS_API_1_7; extern int httpAddrPort(http_addr_t *addr) _CUPS_API_1_7; extern char *httpAssembleUUID(const char *server, int port, const char *name, int number, char *buffer, size_t bufsize) _CUPS_API_1_7; extern http_t *httpConnect2(const char *host, int port, http_addrlist_t *addrlist, int family, http_encryption_t encryption, int blocking, int msec, int *cancel) _CUPS_API_1_7; extern const char *httpGetContentEncoding(http_t *http) _CUPS_API_1_7; extern http_status_t httpGetExpect(http_t *http) _CUPS_API_1_7; extern ssize_t httpPeek(http_t *http, char *buffer, size_t length) _CUPS_API_1_7; extern http_state_t httpReadRequest(http_t *http, char *resource, size_t resourcelen) _CUPS_API_1_7; extern void httpSetDefaultField(http_t *http, http_field_t field, const char *value) _CUPS_API_1_7; extern http_state_t httpWriteResponse(http_t *http, http_status_t status) _CUPS_API_1_7; /* New in CUPS 2.0/macOS 10.10 */ extern int httpAddrClose(http_addr_t *addr, int fd) _CUPS_API_2_0; extern int httpAddrFamily(http_addr_t *addr) _CUPS_API_2_0; extern int httpCompareCredentials(cups_array_t *cred1, cups_array_t *cred2) _CUPS_API_2_0; extern int httpCredentialsAreValidForName(cups_array_t *credentials, const char *common_name); extern time_t httpCredentialsGetExpiration(cups_array_t *credentials) _CUPS_API_2_0; extern http_trust_t httpCredentialsGetTrust(cups_array_t *credentials, const char *common_name) _CUPS_API_2_0; extern size_t httpCredentialsString(cups_array_t *credentials, char *buffer, size_t bufsize) _CUPS_API_2_0; extern http_field_t httpFieldValue(const char *name) _CUPS_API_2_0; extern time_t httpGetActivity(http_t *http) _CUPS_API_2_0; extern http_addr_t *httpGetAddress(http_t *http) _CUPS_API_2_0; extern http_encryption_t httpGetEncryption(http_t *http) _CUPS_API_2_0; extern http_keepalive_t httpGetKeepAlive(http_t *http) _CUPS_API_2_0; extern size_t httpGetPending(http_t *http) _CUPS_API_2_0; extern size_t httpGetReady(http_t *http) _CUPS_API_2_0; extern size_t httpGetRemaining(http_t *http) _CUPS_API_2_0; extern int httpIsChunked(http_t *http) _CUPS_API_2_0; extern int httpIsEncrypted(http_t *http) _CUPS_API_2_0; extern int httpLoadCredentials(const char *path, cups_array_t **credentials, const char *common_name) _CUPS_API_2_0; extern const char *httpResolveHostname(http_t *http, char *buffer, size_t bufsize) _CUPS_API_2_0; extern int httpSaveCredentials(const char *path, cups_array_t *credentials, const char *common_name) _CUPS_API_2_0; extern void httpSetKeepAlive(http_t *http, http_keepalive_t keep_alive) _CUPS_API_2_0; extern void httpShutdown(http_t *http) _CUPS_API_2_0; extern const char *httpStateString(http_state_t state) _CUPS_API_2_0; extern const char *httpURIStatusString(http_uri_status_t status) _CUPS_API_2_0; /* * C++ magic... */ # ifdef __cplusplus } # endif /* __cplusplus */ #endif /* !_CUPS_HTTP_H_ */ htmldoc-1.9.7/htmldoc/image.cxx000066400000000000000000001161441354715574200164460ustar00rootroot00000000000000/* * Image handling routines for HTMLDOC, a HTML document processing program. * * Copyright 2011-2017 by Michael R Sweet. * Copyright 1997-2010 by Easy Software Products. All rights reserved. * * This program is free software. Distribution and use rights are outlined in * the file "COPYING". */ /* * Include necessary headers. */ #include "htmldoc.h" extern "C" { /* Workaround for JPEG header problems... */ #include /* JPEG/JFIF image definitions */ } #include /* Portable Network Graphics (PNG) definitions */ /* * GIF definitions... */ #define GIF_INTERLACE 0x40 #define GIF_COLORMAP 0x80 typedef uchar gif_cmap_t[256][3]; /* * BMP definitions... */ #ifndef BI_RGB # define BI_RGB 0 /* No compression - straight BGR data */ # define BI_RLE8 1 /* 8-bit run-length compression */ # define BI_RLE4 2 /* 4-bit run-length compression */ # define BI_BITFIELDS 3 /* RGB bitmap with RGB masks */ #endif /* !BI_RGB */ /* * Local globals... */ static size_t num_images = 0, /* Number of images in cache */ alloc_images = 0; /* Allocated images */ static image_t **images = NULL; /* Images in cache */ static int gif_eof = 0; /* Did we hit EOF? */ /* * Local functions... */ static int gif_read_cmap(FILE *fp, int ncolors, gif_cmap_t cmap, int *gray); static int gif_get_block(FILE *fp, uchar *buffer); static int gif_get_code (FILE *fp, int code_size, int first_time); static int gif_read_image(FILE *fp, image_t *img, gif_cmap_t cmap, int interlace, int transparent); static int gif_read_lzw(FILE *fp, int first_time, int input_code_size); static int image_compare(image_t **img1, image_t **img2); static int image_load_bmp(image_t *img, FILE *fp, int gray, int load_data); static int image_load_gif(image_t *img, FILE *fp, int gray, int load_data); static int image_load_jpeg(image_t *img, FILE *fp, int gray, int load_data); static int image_load_png(image_t *img, FILE *fp, int gray, int load_data); static void image_need_mask(image_t *img, int scaling = 1); static void image_set_mask(image_t *img, int x, int y, uchar alpha = 0); static void jpeg_error_handler(j_common_ptr); static int read_long(FILE *fp); static unsigned short read_word(FILE *fp); static unsigned int read_dword(FILE *fp); /* * 'gif_read_cmap()' - Read the colormap from a GIF file... */ static int /* O - 0 on success, -1 on error */ gif_read_cmap(FILE *fp, /* I - File to read from */ int ncolors, /* I - Number of colors */ gif_cmap_t cmap, /* IO - Colormap array */ int *gray) /* IO - 1 = grayscale */ { int i; /* Looping var */ /* * Read the colormap... */ if (fread(cmap, 3, (size_t)ncolors, fp) < (size_t)ncolors) { progress_error(HD_ERROR_READ_ERROR, "Unable to read GIF colormap: %s", strerror(errno)); return (-1); } /* * Check to see if the colormap is a grayscale ramp... */ for (i = 0; i < ncolors; i ++) if (cmap[i][0] != cmap[i][1] || cmap[i][1] != cmap[i][2]) break; if (i == ncolors) { *gray = 1; return (0); } /* * If this needs to be a grayscale image, convert the RGB values to * luminance values... */ if (*gray) for (i = 0; i < ncolors; i ++) cmap[i][0] = (cmap[i][0] * 31 + cmap[i][1] * 61 + cmap[i][2] * 8) / 100; return (0); } /* * 'gif_get_block()' - Read a GIF data block... */ static int /* O - Number characters read */ gif_get_block(FILE *fp, /* I - File to read from */ uchar *buf) /* I - Input buffer */ { int count; /* Number of character to read */ /* * Read the count byte followed by the data from the file... */ if ((count = getc(fp)) == EOF) { gif_eof = 1; return (-1); } else if (count == 0) gif_eof = 1; else if (fread(buf, 1, (size_t)count, fp) < (size_t)count) { progress_error(HD_ERROR_READ_ERROR, "Unable to read GIF block of %d bytes: %s", count, strerror(errno)); gif_eof = 1; return (-1); } else gif_eof = 0; return (count); } /* * 'gif_get_code()' - Get a LZW code from the file... */ static int /* O - LZW code */ gif_get_code(FILE *fp, /* I - File to read from */ int code_size, /* I - Size of code in bits */ int first_time) /* I - 1 = first time, 0 = not first time */ { unsigned i, j, /* Looping vars */ ret; /* Return value */ int count; /* Number of bytes read */ static uchar buf[280]; /* Input buffer */ static unsigned curbit, /* Current bit */ lastbit, /* Last bit in buffer */ done, /* Done with this buffer? */ last_byte; /* Last byte in buffer */ static unsigned bits[8] = /* Bit masks for codes */ { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 }; if (first_time) { /* * Just initialize the input buffer... */ curbit = 0; lastbit = 0; last_byte = 0; done = 0; return (0); } if ((curbit + (unsigned)code_size) >= lastbit) { /* * Don't have enough bits to hold the code... */ if (done) { progress_error(HD_ERROR_READ_ERROR, "Not enough data left to read GIF compression code."); return (-1); /* Sorry, no more... */ } /* * Move last two bytes to front of buffer... */ if (last_byte > 1) { buf[0] = buf[last_byte - 2]; buf[1] = buf[last_byte - 1]; last_byte = 2; } else if (last_byte == 1) { buf[0] = buf[last_byte - 1]; last_byte = 1; } /* * Read in another buffer... */ if ((count = gif_get_block (fp, buf + last_byte)) <= 0) { /* * Whoops, no more data! */ done = 1; return (-1); } /* * Update buffer state... */ curbit = (curbit - lastbit) + 8 * last_byte; last_byte += (unsigned)count; lastbit = last_byte * 8; } for (ret = 0, i = curbit + (unsigned)code_size - 1, j = (unsigned)code_size; j > 0; i --, j --) ret = (ret << 1) | ((buf[i / 8] & bits[i & 7]) != 0); curbit += (unsigned)code_size; return (int)ret; } /* * 'gif_read_image()' - Read a GIF image stream... */ static int /* I - 0 = success, -1 = failure */ gif_read_image(FILE *fp, /* I - Input file */ image_t *img, /* I - Image pointer */ gif_cmap_t cmap, /* I - Colormap */ int interlace, /* I - Non-zero = interlaced image */ int transparent) /* I - Transparent color */ { uchar code_size, /* Code size */ *temp; /* Current pixel */ int xpos, /* Current X position */ ypos, /* Current Y position */ pass; /* Current pass */ int pixel; /* Current pixel */ static int xpasses[4] = { 8, 8, 4, 2 }, ypasses[5] = { 0, 4, 2, 1, 999999 }; xpos = 0; ypos = 0; pass = 0; code_size = (uchar)getc(fp); if (gif_read_lzw(fp, 1, code_size) < 0) return (-1); temp = img->pixels; while ((pixel = gif_read_lzw(fp, 0, code_size)) >= 0) { temp[0] = cmap[pixel][0]; if (img->depth > 1) { temp[1] = cmap[pixel][1]; temp[2] = cmap[pixel][2]; } if (pixel == transparent) image_set_mask(img, xpos, ypos); xpos ++; temp += img->depth; if (xpos == img->width) { xpos = 0; if (interlace) { ypos += xpasses[pass]; temp += (xpasses[pass] - 1) * img->width * img->depth; if (ypos >= img->height) { pass ++; ypos = ypasses[pass]; temp = img->pixels + ypos * img->width * img->depth; } } else ypos ++; } if (ypos >= img->height) break; } return (0); } /* * 'gif_read_lzw()' - Read a byte from the LZW stream... */ static int /* I - Byte from stream */ gif_read_lzw(FILE *fp, /* I - File to read from */ int first_time, /* I - 1 = first time, 0 = not first time */ int input_code_size) /* I - Code size in bits */ { int i, /* Looping var */ code, /* Current code */ incode; /* Input code */ static short fresh = 0, /* 1 = empty buffers */ code_size = 0, /* Current code size */ set_code_size = 0, /* Initial code size set */ max_code = 0, /* Maximum code used */ max_code_size = 0, /* Maximum code size */ firstcode = 0, /* First code read */ oldcode = 0, /* Last code read */ clear_code = 0, /* Clear code for LZW input */ end_code = 0, /* End code for LZW input */ table[2][4096], /* String table */ stack[8192], /* Output stack */ *sp = stack; /* Current stack pointer */ if (first_time) { /* * Setup LZW state... */ set_code_size = (short)input_code_size; code_size = set_code_size + 1; clear_code = (short)(1 << set_code_size); end_code = clear_code + 1; max_code_size = 2 * clear_code; max_code = clear_code + 2; /* * Initialize input buffers... */ gif_get_code(fp, 0, 1); /* * Wipe the decompressor table... */ fresh = 1; for (i = 0; i < clear_code; i ++) { table[0][i] = 0; table[1][i] = (short)i; } for (; i < 4096; i ++) table[0][i] = table[1][0] = 0; sp = stack; return (0); } else if (fresh) { fresh = 0; do firstcode = oldcode = (short)gif_get_code(fp, code_size, 0); while (firstcode == clear_code); return (firstcode); } if (sp > stack) return (*--sp); while ((code = gif_get_code (fp, code_size, 0)) >= 0) { if (code == clear_code) { for (i = 0; i < clear_code; i ++) { table[0][i] = 0; table[1][i] = (short)i; } for (; i < 4096; i ++) table[0][i] = table[1][i] = 0; code_size = set_code_size + 1; max_code_size = 2 * clear_code; max_code = clear_code + 2; sp = stack; firstcode = oldcode = (short)gif_get_code(fp, code_size, 0); return (firstcode); } else if (code == end_code) { uchar buf[260]; if (!gif_eof) while (gif_get_block(fp, buf) > 0); return (-2); } incode = code; if (code >= max_code) { *sp++ = firstcode; code = oldcode; } while (code >= clear_code) { *sp++ = table[1][code]; if (code == table[0][code]) return (255); code = table[0][code]; } *sp++ = firstcode = table[1][code]; code = max_code; if (code < 4096) { table[0][code] = oldcode; table[1][code] = firstcode; max_code ++; if (max_code >= max_code_size && max_code_size < 4096) { max_code_size *= 2; code_size ++; } } oldcode = (short)incode; if (sp > stack) return (*--sp); } return (code); } /* * 'image_compare()' - Compare two image filenames... */ static int /* O - Result of comparison */ image_compare(image_t **img1, /* I - First image */ image_t **img2) /* I - Second image */ { #ifdef WIN32 return (strcasecmp((*img1)->filename, (*img2)->filename)); #else return (strcmp((*img1)->filename, (*img2)->filename)); #endif /* WIN32 */ } /* * 'image_copy()' - Copy image files to the destination directory... */ void image_copy(const char *src, /* I - Source file */ const char *realsrc, /* I - Real source file */ const char *destpath) /* I - Destination path */ { char dest[255]; /* Destination file */ FILE *in, *out; /* Input/output files */ uchar buffer[8192]; /* Data buffer */ int nbytes; /* Number of bytes in buffer */ if (!src || !realsrc || !destpath) return; /* * Figure out the destination filename... */ if (!strcmp(destpath, ".")) strlcpy(dest, file_basename(src), sizeof(dest)); else snprintf(dest, sizeof(dest), "%s/%s", destpath, file_basename(src)); if (!strcmp(dest, realsrc)) return; /* * Open files and copy... */ if ((in = fopen(realsrc, "rb")) == NULL) { progress_error(HD_ERROR_READ_ERROR, "Unable to open \"%s\" - %s", realsrc, strerror(errno)); return; } if ((out = fopen(dest, "wb")) == NULL) { progress_error(HD_ERROR_READ_ERROR, "Unable to create \"%s\" - %s", dest, strerror(errno)); fclose(in); return; } while ((nbytes = fread(buffer, 1, sizeof(buffer), in)) > 0) fwrite(buffer, 1, (size_t)nbytes, out); progress_error(HD_ERROR_NONE, "BYTES: %ld", ftell(out)); fclose(in); fclose(out); } /* * 'image_find()' - Find an image file in memory... */ image_t * /* O - Pointer to image */ image_find(const char *filename,/* I - Name of image file */ int load_data)/* I - 1 = load image data */ { image_t key, /* Search key... */ *keyptr, /* Pointer to search key... */ **match; /* Matching image */ /* * Range check... */ if (filename == NULL) return (NULL); if (filename[0] == '\0') /* Microsoft VC++ runtime bug workaround... */ return (NULL); /* * See if we've already loaded it... */ if (num_images > 0) { strlcpy(key.filename, filename, sizeof(key.filename)); keyptr = &key; match = (image_t **)bsearch(&keyptr, images, (size_t)num_images, sizeof(image_t *), (int (*)(const void *, const void *))image_compare); if (match != NULL) { if (load_data && !(*match)->pixels) return (image_load((*match)->filename, (*match)->depth == 1, 1)); else return (*match); } } return (NULL); } /* * 'image_flush_cache()' - Flush the image cache... */ void image_flush_cache(void) { size_t i; /* Looping var */ /* * Free the memory used by each image... */ for (i = 0; i < num_images; i ++) { if (images[i]->mask) free(images[i]->mask); if (images[i]->pixels) free(images[i]->pixels); free(images[i]); } if (alloc_images) { free(images); alloc_images = 0; } num_images = 0; } /* * 'image_getlist()' - Get the list of images that are loaded. */ int /* O - Number of images in array */ image_getlist(image_t ***ptrs) /* O - Pointer to images array */ { *ptrs = images; return (num_images); } /* * 'image_load()' - Load an image file from disk... */ image_t * /* O - Pointer to image */ image_load(const char *filename,/* I - Name of image file */ int gray, /* I - 0 = color, 1 = grayscale */ int load_data)/* I - 1 = load image data, 0 = just info */ { #ifdef DEBUG int i; /* Looping var */ #endif // DEBUG FILE *fp; /* File pointer */ uchar header[16]; /* First 16 bytes of file */ image_t *img, /* New image buffer */ key, /* Search key... */ *keyptr, /* Pointer to search key... */ **match, /* Matching image */ **temp; /* Temporary array pointer */ int status; /* Status of load... */ const char *realname; /* Real filename */ /* * Range check... */ if (filename == NULL) return (NULL); if (filename[0] == '\0') /* Microsoft VC++ runtime bug workaround... */ return (NULL); DEBUG_printf(("image_load(filename=\"%s\", gray=%d, load_data=%d)\n", filename, gray, load_data)); DEBUG_printf(("Path = \"%s\"\n", Path)); /* * See if we've already loaded it... */ if (num_images > 0) { strlcpy(key.filename, filename, sizeof(key.filename)); keyptr = &key; match = (image_t **)bsearch(&keyptr, images, (size_t)num_images, sizeof(image_t *), (int (*)(const void *, const void *))image_compare); if (match != NULL && (!load_data || (*match)->pixels)) { (*match)->use ++; return (*match); } } else match = NULL; /* * Figure out the file type... */ if ((realname = file_find(Path, filename)) == NULL) { progress_error(HD_ERROR_FILE_NOT_FOUND, "Unable to find image file \"%s\"!", filename); return (NULL); } if ((fp = fopen(realname, "rb")) == NULL) { progress_error(HD_ERROR_FILE_NOT_FOUND, "Unable to open image file \"%s\" (%s) for reading!", filename, realname); return (NULL); } if (fread(header, 1, sizeof(header), fp) == 0) { progress_error(HD_ERROR_READ_ERROR, "Unable to read image file \"%s\"!", filename); fclose(fp); return (NULL); } #ifdef DEBUG printf("Header for \"%s\" (%s): \"", filename, realname); for (i = 0; i < (int)sizeof(header); i ++) if (header[i] < ' ' || header[i] >= 127) printf("\\x%02X", header[i]); else putchar(header[i]); puts("\"\n"); printf("match = %p\n", (void *)match); #endif // DEBUG rewind(fp); // See if the images array needs to be resized... if (!match) { if (num_images >= alloc_images) { // Yes... alloc_images += ALLOC_FILES; if (num_images == 0) temp = (image_t **)malloc(sizeof(image_t *) * alloc_images); else temp = (image_t **)realloc(images, sizeof(image_t *) * alloc_images); if (temp == NULL) { progress_error(HD_ERROR_OUT_OF_MEMORY, "Unable to allocate memory for %d images - %s", alloc_images, strerror(errno)); fclose(fp); return (NULL); } images = temp; } // Allocate memory... img = (image_t *)calloc(sizeof(image_t), 1); if (img == NULL) { progress_error(HD_ERROR_READ_ERROR, "Unable to allocate memory for \"%s\"", filename); fclose(fp); return (NULL); } images[num_images] = img; strlcpy(img->filename, filename, sizeof(img->filename)); img->use = 1; } else img = *match; // Load the image as appropriate... if (memcmp(header, "GIF87a", 6) == 0 || memcmp(header, "GIF89a", 6) == 0) status = image_load_gif(img, fp, gray, load_data); else if (memcmp(header, "BM", 2) == 0) status = image_load_bmp(img, fp, gray, load_data); else if (memcmp(header, "\211PNG", 4) == 0) status = image_load_png(img, fp, gray, load_data); else if (memcmp(header, "\377\330\377", 3) == 0) status = image_load_jpeg(img, fp, gray, load_data); else { progress_error(HD_ERROR_BAD_FORMAT, "Unknown image file format for \"%s\"!", file_rlookup(filename)); fclose(fp); free(img); return (NULL); } fclose(fp); if (status) { progress_error(HD_ERROR_READ_ERROR, "Unable to load image file \"%s\"!", file_rlookup(filename)); if (!match) free(img); return (NULL); } if (!match) { num_images ++; if (num_images > 1) qsort(images, num_images, sizeof(image_t *), (int (*)(const void *, const void *))image_compare); } return (img); } /* * 'image_load_bmp()' - Read a BMP image file. */ static int /* O - 0 = success, -1 = fail */ image_load_bmp(image_t *img, /* I - Image to load into */ FILE *fp, /* I - File to read from */ int gray, /* I - Grayscale image? */ int load_data)/* I - 1 = load image data, 0 = just info */ { int info_size, /* Size of info header */ depth, /* Depth of image (bits) */ compression, /* Type of compression */ colors_used, /* Number of colors used */ x, y, /* Looping vars */ color, /* Color of RLE pixel */ count, /* Number of times to repeat */ temp, /* Temporary color */ align; /* Alignment bytes */ uchar bit, /* Bit in image */ byte; /* Byte in image */ uchar *ptr; /* Pointer into pixels */ uchar colormap[256][4];/* Colormap */ // Get the header... getc(fp); /* Skip "BM" sync chars */ getc(fp); read_dword(fp); /* Skip size */ read_word(fp); /* Skip reserved stuff */ read_word(fp); read_dword(fp); // Then the bitmap information... info_size = (int)read_dword(fp); img->width = read_long(fp); img->height = read_long(fp); read_word(fp); depth = read_word(fp); compression = (int)read_dword(fp); read_dword(fp); read_long(fp); read_long(fp); colors_used = (int)read_dword(fp); read_dword(fp); if (info_size > 40) for (info_size -= 40; info_size > 0; info_size --) getc(fp); // Get colormap... if (colors_used == 0 && depth <= 8) colors_used = 1 << depth; fread(colormap, (size_t)colors_used, 4, fp); // Setup image and buffers... img->depth = gray ? 1 : 3; // If this image is indexed and we are writing an encrypted PDF file, bump the use count so // we create an image object (Acrobat 6 bug workaround) if (depth <= 8 && Encryption) img->use ++; // Return now if we only need the dimensions... if (!load_data) return (0); img->pixels = (uchar *)malloc((size_t)(img->width * img->height * img->depth)); if (img->pixels == NULL) return (-1); if (gray && depth <= 8) { // Convert colormap to grayscale... for (color = colors_used - 1; color >= 0; color --) colormap[color][0] = (colormap[color][2] * 31 + colormap[color][1] * 61 + colormap[color][0] * 8) / 100; } // Read the image data... color = 0; count = 0; align = 0; byte = 0; temp = 0; for (y = img->height - 1; y >= 0; y --) { ptr = img->pixels + y * img->width * img->depth; switch (depth) { case 1 : /* Bitmap */ for (x = img->width, bit = 128; x > 0; x --) { if (bit == 128) byte = (uchar)getc(fp); if (byte & bit) { if (!gray) { *ptr++ = colormap[1][2]; *ptr++ = colormap[1][1]; } *ptr++ = colormap[1][0]; } else { if (!gray) { *ptr++ = colormap[0][2]; *ptr++ = colormap[0][1]; } *ptr++ = colormap[0][0]; } if (bit > 1) bit >>= 1; else bit = 128; } /* * Read remaining bytes to align to 32 bits... */ for (temp = (img->width + 7) / 8; temp & 3; temp ++) getc(fp); break; case 4 : /* 16-color */ for (x = img->width, bit = 0xf0; x > 0; x --) { /* * Get a new count as needed... */ if (compression != BI_RLE4 && count == 0) { count = 2; color = -1; } if (count == 0) { while (align > 0) { align --; getc(fp); } if ((count = getc(fp)) == 0) { if ((count = getc(fp)) == 0) { /* * End of line... */ x ++; continue; } else if (count == 1) { /* * End of image... */ break; } else if (count == 2) { /* * Delta... */ count = getc(fp) * getc(fp) * img->width; color = 0; } else { /* * Absolute... */ color = -1; align = ((4 - (count & 3)) / 2) & 1; } } else color = getc(fp); } /* * Get a new color as needed... */ count --; if (bit == 0xf0) { if (color < 0) temp = getc(fp); else temp = color; /* * Copy the color value... */ if (!gray) { *ptr++ = colormap[temp >> 4][2]; *ptr++ = colormap[temp >> 4][1]; } *ptr++ = colormap[temp >> 4][0]; bit = 0x0f; } else { /* * Copy the color value... */ if (!gray) { *ptr++ = colormap[temp & 15][2]; *ptr++ = colormap[temp & 15][1]; } *ptr++ = colormap[temp & 15][0]; bit = 0xf0; } } break; case 8 : /* 256-color */ for (x = img->width; x > 0; x --) { /* * Get a new count as needed... */ if (compression != BI_RLE8) { count = 1; color = -1; } if (count == 0) { while (align > 0) { align --; getc(fp); } if ((count = getc(fp)) == 0) { if ((count = getc(fp)) == 0) { /* * End of line... */ x ++; continue; } else if (count == 1) { /* * End of image... */ break; } else if (count == 2) { /* * Delta... */ count = getc(fp) * getc(fp) * img->width; color = 0; } else { /* * Absolute... */ color = -1; align = (2 - (count & 1)) & 1; } } else color = getc(fp); } /* * Get a new color as needed... */ if (color < 0) temp = getc(fp); else temp = color; count --; /* * Copy the color value... */ if (!gray) { *ptr++ = colormap[temp][2]; *ptr++ = colormap[temp][1]; } *ptr++ = colormap[temp][0]; } break; case 24 : /* 24-bit RGB */ if (gray) { for (x = img->width; x > 0; x --) { temp = getc(fp) * 8; temp += getc(fp) * 61; temp += getc(fp) * 31; *ptr++ = (uchar)(temp / 100); } } else { for (x = img->width; x > 0; x --, ptr += 3) { ptr[2] = (uchar)getc(fp); ptr[1] = (uchar)getc(fp); ptr[0] = (uchar)getc(fp); } } /* * Read remaining bytes to align to 32 bits... */ for (temp = img->width * 3; temp & 3; temp ++) getc(fp); break; } } return (0); } /* * 'image_load_gif()' - Load a GIF image file... */ static int /* O - 0 = success, -1 = fail */ image_load_gif(image_t *img, /* I - Image pointer */ FILE *fp, /* I - File to load from */ int gray, /* I - 0 = color, 1 = grayscale */ int load_data)/* I - 1 = load image data, 0 = just info */ { uchar buf[1024]; /* Input buffer */ gif_cmap_t cmap; /* Colormap */ int ncolors, /* Bits per pixel */ transparent; /* Transparent color index */ /* * Read the header; we already know it is a GIF file... */ fread(buf, 13, 1, fp); img->width = (buf[7] << 8) | buf[6]; img->height = (buf[9] << 8) | buf[8]; ncolors = 2 << (buf[10] & 0x07); // If we are writing an encrypted PDF file, bump the use count so we create // an image object (Acrobat 6 bug workaround) if (Encryption) img->use ++; if (buf[10] & GIF_COLORMAP) if (gif_read_cmap(fp, ncolors, cmap, &gray)) return (-1); transparent = -1; while (1) { switch (getc(fp)) { case ';' : /* End of image */ return (-1); /* Early end of file */ case '!' : /* Extension record */ buf[0] = (uchar)getc(fp); if (buf[0] == 0xf9) /* Graphic Control Extension */ { gif_get_block(fp, buf); if (buf[0] & 1) /* Get transparent color index */ transparent = buf[3]; } while (gif_get_block(fp, buf) != 0); break; case ',' : /* Image data */ fread(buf, 9, 1, fp); if (buf[8] & GIF_COLORMAP) { ncolors = 2 << (buf[8] & 0x07); if (gif_read_cmap(fp, ncolors, cmap, &gray)) return (-1); } if (transparent >= 0) { /* * Map transparent color to background color... */ if (BodyColor[0]) { float rgb[3]; /* RGB color */ get_color((uchar *)BodyColor, rgb); cmap[transparent][0] = (uchar)(rgb[0] * 255.0f + 0.5f); cmap[transparent][1] = (uchar)(rgb[1] * 255.0f + 0.5f); cmap[transparent][2] = (uchar)(rgb[2] * 255.0f + 0.5f); } else { cmap[transparent][0] = 255; cmap[transparent][1] = 255; cmap[transparent][2] = 255; } /* * Allocate a mask image... */ image_need_mask(img); } img->width = (buf[5] << 8) | buf[4]; img->height = (buf[7] << 8) | buf[6]; img->depth = gray ? 1 : 3; if (!load_data) return (0); img->pixels = (uchar *)malloc((size_t)(img->width * img->height * img->depth)); if (img->pixels == NULL) return (-1); return (gif_read_image(fp, img, cmap, buf[8] & GIF_INTERLACE, transparent)); } } } /* * 'image_load_jpeg()' - Load a JPEG image file. */ static int /* O - 0 = success, -1 = fail */ image_load_jpeg(image_t *img, /* I - Image pointer */ FILE *fp, /* I - File to load from */ int gray, /* I - 0 = color, 1 = grayscale */ int load_data)/* I - 1 = load image data, 0 = just info */ { struct jpeg_decompress_struct cinfo; /* Decompressor info */ struct jpeg_error_mgr jerr; /* Error handler info */ JSAMPROW row; /* Sample row pointer */ jpeg_std_error(&jerr); jerr.error_exit = jpeg_error_handler; cinfo.err = &jerr; jpeg_create_decompress(&cinfo); jpeg_stdio_src(&cinfo, fp); jpeg_read_header(&cinfo, (boolean)1); cinfo.quantize_colors = FALSE; if (gray || cinfo.num_components == 1) { cinfo.out_color_space = JCS_GRAYSCALE; cinfo.out_color_components = 1; cinfo.output_components = 1; } else if (cinfo.num_components != 3) { jpeg_destroy_decompress(&cinfo); progress_error(HD_ERROR_BAD_FORMAT, "CMYK JPEG files are not supported! (%s)", file_rlookup(img->filename)); return (-1); } else { cinfo.out_color_space = JCS_RGB; cinfo.out_color_components = 3; cinfo.output_components = 3; } jpeg_calc_output_dimensions(&cinfo); img->width = (int)cinfo.output_width; img->height = (int)cinfo.output_height; img->depth = (int)cinfo.output_components; if (!load_data) { jpeg_destroy_decompress(&cinfo); return (0); } img->pixels = (uchar *)malloc((size_t)(img->width * img->height * img->depth)); if (img->pixels == NULL) { jpeg_destroy_decompress(&cinfo); return (-1); } jpeg_start_decompress(&cinfo); while (cinfo.output_scanline < cinfo.output_height) { row = (JSAMPROW)(img->pixels + (size_t)cinfo.output_scanline * (size_t)cinfo.output_width * (size_t)cinfo.output_components); jpeg_read_scanlines(&cinfo, &row, (JDIMENSION)1); } jpeg_finish_decompress(&cinfo); jpeg_destroy_decompress(&cinfo); return (0); } /* * 'image_load_png()' - Load a PNG image file. */ static int /* O - 0 = success, -1 = fail */ image_load_png(image_t *img, /* I - Image pointer */ FILE *fp, /* I - File to read from */ int gray, /* I - 0 = color, 1 = grayscale */ int load_data)/* I - 1 = load image data, 0 = just info */ { int i, j; /* Looping vars */ png_structp pp; /* PNG read pointer */ png_infop info; /* PNG info pointers */ int depth; /* Input image depth */ png_bytep *rows; /* PNG row pointers */ uchar *inptr, /* Input pixels */ *outptr; /* Output pixels */ int color_type, /* PNG color mode */ bit_depth; /* PNG bit depth */ /* * Setup the PNG data structures... */ pp = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (!pp) { progress_error(HD_ERROR_OUT_OF_MEMORY, "Unable to allocate memory for PNG file: %s", strerror(errno)); return (-1); } info = png_create_info_struct(pp); if (!info) { progress_error(HD_ERROR_OUT_OF_MEMORY, "Unable to allocate memory for PNG info: %s", strerror(errno)); png_destroy_read_struct(&pp, NULL, NULL); return (-1); } rows = NULL; if (setjmp(png_jmpbuf(pp))) { progress_error(HD_ERROR_BAD_FORMAT, "PNG file contains errors!"); png_destroy_read_struct(&pp, &info, NULL); if (img != NULL && img->pixels != NULL) free(img->pixels); if (rows != NULL) free(rows); return (-1); } /* * Initialize the PNG read "engine"... */ png_init_io(pp, fp); /* * Get the image dimensions and convert to grayscale or RGB... */ png_read_info(pp, info); bit_depth = png_get_bit_depth(pp, info); color_type = png_get_color_type(pp, info); if (png_get_valid(pp, info, PNG_INFO_tRNS)) { png_set_tRNS_to_alpha(pp); color_type |= PNG_COLOR_MASK_ALPHA; } if (color_type & PNG_COLOR_MASK_PALETTE) { png_set_palette_to_rgb(pp); // If we are writing an encrypted PDF file, bump the use count so we create // an image object (Acrobat 6 bug workaround) if (Encryption) img->use ++; } else if (!(color_type & PNG_COLOR_MASK_COLOR) && bit_depth < 8) { png_set_expand_gray_1_2_4_to_8(pp); } else if (bit_depth == 16) { #if PNG_LIBPNG_VER >= 10504 png_set_scale_16(pp); #else png_set_strip_16(pp); #endif // PNG_LIBPNG_VER >= 10504 } if (color_type & PNG_COLOR_MASK_COLOR) { depth = 3; img->depth = gray ? 1 : 3; } else { depth = 1; img->depth = 1; } img->width = (int)png_get_image_width(pp, info); img->height = (int)png_get_image_height(pp, info); if (color_type & PNG_COLOR_MASK_ALPHA) { if ((PSLevel == 0 && PDFVersion >= 14) || PSLevel == 3) image_need_mask(img, 8); else if (PSLevel == 0 && PDFVersion == 13) image_need_mask(img, 2); else image_need_mask(img); depth ++; } #ifdef DEBUG printf("bit_depth=%d, color_type=0x%04x, depth=%d, img->width=%d, img->height=%d, img->depth=%d\n", bit_depth, color_type, depth, img->width, img->height, img->depth); if (color_type & PNG_COLOR_MASK_COLOR) puts(" COLOR"); else puts(" GRAYSCALE"); if (color_type & PNG_COLOR_MASK_ALPHA) puts(" ALPHA"); if (color_type & PNG_COLOR_MASK_PALETTE) puts(" PALETTE"); #endif // DEBUG if (!load_data) { png_destroy_read_struct(&pp, &info, NULL); return (0); } img->pixels = (uchar *)calloc(1,(size_t)(img->width * img->height * depth)); /* * Allocate pointers... */ rows = (png_bytep *)calloc(png_get_image_height(pp, info), sizeof(png_bytep)); for (i = 0; i < (int)png_get_image_height(pp, info); i ++) rows[i] = img->pixels + i * img->width * depth; /* * Read the image, handling interlacing as needed... */ for (i = png_set_interlace_handling(pp); i > 0; i --) png_read_rows(pp, rows, NULL, (png_uint_32)img->height); /* * Generate the alpha mask as necessary... */ if (color_type & PNG_COLOR_MASK_ALPHA) { #ifdef DEBUG for (inptr = img->pixels, i = 0; i < img->height; i ++) { for (j = 0; j < img->width; j ++, inptr += depth) switch (depth) { case 2 : printf(" %02X%02X", inptr[0], inptr[1]); break; case 4 : printf(" %02X%02X%02X%02X", inptr[0], inptr[1], inptr[2], inptr[3]); break; } putchar('\n'); } #endif // DEBUG for (inptr = img->pixels + depth - 1, i = 0; i < img->height; i ++) for (j = 0; j < img->width; j ++, inptr += depth) image_set_mask(img, j, i, *inptr); } /* * Reformat the data as necessary for the reader... */ if (gray && (color_type & PNG_COLOR_MASK_COLOR)) { /* * Grayscale output needed... */ for (inptr = img->pixels, outptr = img->pixels, i = img->width * img->height; i > 0; inptr += depth, outptr ++, i --) *outptr = (31 * inptr[0] + 61 * inptr[1] + 8 * inptr[2]) / 100; } else if (img->depth != depth) { /* * Remove alpha from final array... */ if (depth == 4) { for (inptr = img->pixels, outptr = img->pixels, i = img->width * img->height; i > 0; inptr ++, i --) { *outptr++ = *inptr++; *outptr++ = *inptr++; *outptr++ = *inptr++; } } else { for (inptr = img->pixels, outptr = img->pixels, i = img->width * img->height; i > 0; inptr ++, i --) *outptr++ = *inptr++; } } /* * Free memory and return... */ free(rows); png_read_end(pp, info); png_destroy_read_struct(&pp, &info, NULL); return (0); } /* * 'image_need_mask()' - Allocate memory for the image mask... */ static void image_need_mask(image_t *img, /* I - Image to add mask to */ int scaling) /* I - Scaling for mask image */ { size_t size; /* Byte size of mask image */ if (img == NULL || img->mask != NULL) return; /* * Figure out the size of the mask image, and then allocate and set all the * bits needed... */ img->maskscale = scaling; if (scaling == 8) { // Alpha image img->maskwidth = img->width; size = (size_t)(img->width * img->height); } else { // Alpha mask img->maskwidth = (img->width * scaling + 7) / 8; size = (size_t)(img->maskwidth * img->height * scaling + 1); } img->mask = (uchar *)calloc(size, 1); } /* * 'image_set_mask()' - Set a bit in the image mask. */ static void image_set_mask(image_t *img, /* I - Image to operate on */ int x, /* I - X coordinate */ int y, /* I - Y coordinate */ uchar alpha) /* I - Alpha value */ { int i, j; /* Looping vars */ uchar *maskptr; /* Pointer into mask image */ static uchar masks[8] = /* Masks for each bit */ { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 }; static uchar dither[4][4] = // Simple 4x4 clustered-dot dither { { 0, 2, 15, 6 }, { 4, 12, 9, 11 }, { 14, 7, 1, 3 }, { 8, 10, 5, 13 } }; if (img == NULL || img->mask == NULL || x < 0 || x >= img->width || y < 0 || y > img->height) return; if (img->maskscale == 8) { // Store the alpha value directly... if (PSLevel) img->mask[y * img->maskwidth + x] = 255 - alpha; else img->mask[y * img->maskwidth + x] = alpha; } else { // Store an alpha mask... x *= img->maskscale; y *= img->maskscale; alpha >>= 4; for (i = 0; i < img->maskscale; i ++, y ++, x -= img->maskscale) for (j = 0; j < img->maskscale; j ++, x ++) { maskptr = img->mask + y * img->maskwidth + x / 8; if (alpha <= dither[x & 3][y & 3]) *maskptr |= masks[x & 7]; } } } /* * 'image_unload()' - Unload an image from memory. */ void image_unload(image_t *img) // I - Image { if (!img) return; if (!img->use || !img->pixels) return; if (img->obj) img->use = 0; else img->use --; if (img->use) return; free(img->pixels); img->pixels = NULL; } /* * 'jpeg_error_handler()' - Handle JPEG errors by not exiting. */ static void jpeg_error_handler(j_common_ptr) { return; } /* * 'read_word()' - Read a 16-bit unsigned integer. */ static unsigned short /* O - 16-bit unsigned integer */ read_word(FILE *fp) /* I - File to read from */ { unsigned char b0, b1; /* Bytes from file */ b0 = (uchar)getc(fp); b1 = (uchar)getc(fp); return (unsigned short)((b1 << 8) | b0); } /* * 'read_dword()' - Read a 32-bit unsigned integer. */ static unsigned int /* O - 32-bit unsigned integer */ read_dword(FILE *fp) /* I - File to read from */ { unsigned char b0, b1, b2, b3; /* Bytes from file */ b0 = (uchar)getc(fp); b1 = (uchar)getc(fp); b2 = (uchar)getc(fp); b3 = (uchar)getc(fp); return (unsigned)((((((b3 << 8) | b2) << 8) | b1) << 8) | b0); } /* * 'read_long()' - Read a 32-bit signed integer. */ static int /* O - 32-bit signed integer */ read_long(FILE *fp) /* I - File to read from */ { unsigned char b0, b1, b2, b3; /* Bytes from file */ b0 = (uchar)getc(fp); b1 = (uchar)getc(fp); b2 = (uchar)getc(fp); b3 = (uchar)getc(fp); return ((int)(((((b3 << 8) | b2) << 8) | b1) << 8) | b0); } htmldoc-1.9.7/htmldoc/image.h000066400000000000000000000030221354715574200160610ustar00rootroot00000000000000/* * Image management definitions for HTMLDOC, a HTML document processing * program. * * Copyright 2011 by Michael R Sweet. * Copyright 1997-2010 by Easy Software Products. All rights reserved. * * This program is free software. Distribution and use rights are outlined in * the file "COPYING". */ #ifndef _IMAGE_H_ # define _IMAGE_H_ /* * Include necessary headers. */ # include # include # include "hdstring.h" # include "types.h" # ifdef __cplusplus extern "C" { # endif /* __cplusplus */ /* * Image structure... */ typedef struct /**** Image structure ****/ { char filename[1024]; /* Name of image file (for caching of images */ int width, /* Width of image in pixels */ height, /* Height of image in pixels */ depth, /* 1 for grayscale, 3 for RGB */ use, /* Number of times this image was used */ obj; /* Object number */ uchar *pixels; /* 8-bit pixel data */ uchar *mask; /* 1-bit mask data, if any */ int maskwidth, /* Byte width of mask data */ maskscale; /* Scaling of mask data */ } image_t; /* * Prototypes... */ extern void image_copy(const char *src, const char *realsrc, const char *destpath); extern image_t *image_find(const char *filename, int load_data = 0); extern void image_flush_cache(void); extern int image_getlist(image_t ***ptrs); extern image_t *image_load(const char *filename, int gray, int load_data = 0); extern void image_unload(image_t *img); # ifdef __cplusplus } # endif /* __cplusplus */ #endif /* !_IMAGE_H_ */ htmldoc-1.9.7/htmldoc/iso8859.cxx000066400000000000000000000263711354715574200165160ustar00rootroot00000000000000/* * ISO-8859-1 conversion routines for HTMLDOC, an HTML document * processing program. * * Copyright 2011-2019 by Michael R Sweet. * Copyright 1997-2010 by Easy Software Products. All rights reserved. * * This program is free software. Distribution and use rights are outlined in * the file "COPYING". */ /* * Include necessary headers. */ #include #include #include "html.h" #include "types.h" /* * Lookup table structure... */ typedef struct { uchar name[12]; int value; } lut_t; static lut_t iso8859_numbers[] = { { "AElig", 198 }, { "Aacute", 193 }, { "Acirc", 194 }, { "Agrave", 192 }, { "Alpha", 913 }, { "Aring", 197 }, { "Atilde", 195 }, { "Auml", 196 }, { "Beta", 914 }, { "Ccedil", 199 }, { "Chi", 935 }, { "Dagger", 8225 }, { "Delta", 916 }, { "ETH", 208 }, { "Eacute", 201 }, { "Ecirc", 202 }, { "Egrave", 200 }, { "Epsilon", 917 }, { "Eta", 919 }, { "Euml", 203 }, { "Gamma", 915 }, { "Iacute", 205 }, { "Icirc", 206 }, { "Igrave", 204 }, { "Iota", 921 }, { "Iuml", 207 }, { "Kappa", 922 }, { "Lambda", 923 }, { "Mu", 924 }, { "Ntilde", 209 }, { "Nu", 925 }, { "OElig", 338 }, { "Oacute", 211 }, { "Ocirc", 212 }, { "Ograve", 210 }, { "Omega", 937 }, { "Omicron", 927 }, { "Oslash", 216 }, { "Otilde", 213 }, { "Ouml", 214 }, { "Phi", 934 }, { "Pi", 928 }, { "Prime", 8243 }, { "Psi", 936 }, { "Rho", 929 }, { "Scaron", 352 }, { "Sigma", 931 }, { "THORN", 222 }, { "Tau", 932 }, { "Theta", 920 }, { "Uacute", 218 }, { "Ucirc", 219 }, { "Ugrave", 217 }, { "Upsilon", 933 }, { "Uuml", 220 }, { "Xi", 926 }, { "Yacute", 221 }, { "Yuml", 376 }, { "Zeta", 918 }, { "aacute", 225 }, { "acirc", 226 }, { "acute", 180 }, { "aelig", 230 }, { "agrave", 224 }, { "alefsym", 8501 }, { "alpha", 945 }, { "amp", 38 }, { "and", 8743 }, { "ang", 8736 }, { "aring", 229 }, { "asymp", 8776 }, { "atilde", 227 }, { "auml", 228 }, { "bdquo", 8222 }, { "beta", 946 }, { "brvbar", 166 }, { "bull", 8226 }, { "cap", 8745 }, { "ccedil", 231 }, { "cedil", 184 }, { "cent", 162 }, { "chi", 967 }, { "circ", 710 }, { "clubs", 9827 }, { "cong", 8773 }, { "copy", 169 }, { "crarr", 8629 }, { "cup", 8746 }, { "curren", 164 }, { "dArr", 8659 }, { "dagger", 8224 }, { "darr", 8595 }, { "deg", 176 }, { "delta", 948 }, { "diams", 9830 }, { "divide", 247 }, { "eacute", 233 }, { "ecirc", 234 }, { "egrave", 232 }, { "empty", 8709 }, { "emsp", 8195 }, { "ensp", 8194 }, { "epsilon", 949 }, { "equiv", 8801 }, { "eta", 951 }, { "eth", 240 }, { "euml", 235 }, { "euro", 8364 }, { "exist", 8707 }, { "fnof", 402 }, { "forall", 8704 }, { "frac12", 189 }, { "frac14", 188 }, { "frac34", 190 }, { "frasl", 8260 }, { "gamma", 947 }, { "ge", 8805 }, { "gt", 62 }, { "hArr", 8660 }, { "harr", 8596 }, { "hearts", 9829 }, { "hellip", 8230 }, { "iacute", 237 }, { "icirc", 238 }, { "iexcl", 161 }, { "igrave", 236 }, { "image", 8465 }, { "infin", 8734 }, { "int", 8747 }, { "iota", 953 }, { "iquest", 191 }, { "isin", 8712 }, { "iuml", 239 }, { "kappa", 954 }, { "lArr", 8656 }, { "lambda", 955 }, { "lang", 9001 }, { "laquo", 171 }, { "larr", 8592 }, { "lceil", 8968 }, { "ldquo", 8220 }, { "le", 8804 }, { "lfloor", 8970 }, { "lowast", 8727 }, { "loz", 9674 }, { "lrm", 8206 }, { "lsaquo", 8249 }, { "lsquo", 8216 }, { "lt", 60 }, { "macr", 175 }, { "mdash", 8212 }, { "micro", 181 }, { "middot", 183 }, { "minus", 8722 }, { "mu", 956 }, { "nabla", 8711 }, { "nbsp", 160 }, { "ndash", 8211 }, { "ne", 8800 }, { "ni", 8715 }, { "not", 172 }, { "notin", 8713 }, { "nsub", 8836 }, { "ntilde", 241 }, { "nu", 957 }, { "oacute", 243 }, { "ocirc", 244 }, { "oelig", 339 }, { "ograve", 242 }, { "oline", 8254 }, { "omega", 969 }, { "omicron", 959 }, { "oplus", 8853 }, { "or", 8744 }, { "ordf", 170 }, { "ordm", 186 }, { "oslash", 248 }, { "otilde", 245 }, { "otimes", 8855 }, { "ouml", 246 }, { "para", 182 }, { "part", 8706 }, { "permil", 8240 }, { "perp", 8869 }, { "phi", 966 }, { "pi", 960 }, { "piv", 982 }, { "plusmn", 177 }, { "pound", 163 }, { "prime", 8242 }, { "prod", 8719 }, { "prop", 8733 }, { "psi", 968 }, { "quot", 34 }, { "rArr", 8658 }, { "radic", 8730 }, { "rang", 9002 }, { "raquo", 187 }, { "rarr", 8594 }, { "rceil", 8969 }, { "rdquo", 8221 }, { "real", 8476 }, { "reg", 174 }, { "rfloor", 8971 }, { "rho", 961 }, { "rlm", 8207 }, { "rsaquo", 8250 }, { "rsquo", 8217 }, { "sbquo", 8218 }, { "scaron", 353 }, { "sdot", 8901 }, { "sect", 167 }, { "shy", 173 }, { "sigma", 963 }, { "sigmaf", 962 }, { "sim", 8764 }, { "spades", 9824 }, { "sub", 8834 }, { "sube", 8838 }, { "sum", 8721 }, { "sup", 8835 }, { "sup1", 185 }, { "sup2", 178 }, { "sup3", 179 }, { "supe", 8839 }, { "szlig", 223 }, { "tau", 964 }, { "there4", 8756 }, { "theta", 952 }, { "thetasym", 977 }, { "thinsp", 8201 }, { "thorn", 254 }, { "tilde", 732 }, { "times", 215 }, { "trade", 8482 }, { "uArr", 8657 }, { "uacute", 250 }, { "uarr", 8593 }, { "ucirc", 251 }, { "ugrave", 249 }, { "uml", 168 }, { "upsih", 978 }, { "upsilon", 965 }, { "uuml", 252 }, { "weierp", 8472 }, { "xi", 958 }, { "yacute", 253 }, { "yen", 165 }, { "yuml", 255 }, { "zeta", 950 }, { "zwj", 8205 }, { "zwnj", 8204 } }; static lut_t *iso8859_names[256]; static int compare_lut(lut_t *, lut_t *); /* * 'iso8859()' - Return the 8-bit character value of a glyph name. */ uchar /* O - ISO-8859-1 equivalent */ iso8859(uchar *name) /* I - Glyph name */ { lut_t key, /* Lookup table key */ *match; /* Matching entry pointer */ int ch; /* Character */ if (strlen((char *)name) == 1) return (name[0]); else if (name[0] == '#') { // Return a decimal or hex character... if (name[1] == 'x') ch = strtol((char *)name + 2, NULL, 16); else ch = strtol((char *)name + 1, NULL, 10); if (ch > 0xffff || ch <= 0) return (0); } else { strlcpy((char *)key.name, (char *)name, sizeof(key.name)); match = (lut_t *)bsearch(&key, iso8859_numbers, sizeof(iso8859_numbers) / sizeof(iso8859_numbers[0]), sizeof(iso8859_numbers[0]), (int (*)(const void *, const void *))compare_lut); if (match == NULL) return (0); else ch = match->value; } if (ch > 0x7f) { // Lookup Unicode value in the current charset... const char *glyph; char uniglyph[32]; int newch; if (!_htmlInitialized) htmlSetCharSet("iso-8859-1"); if ((glyph = _htmlGlyphsAll[ch]) == NULL) { snprintf(uniglyph, sizeof(uniglyph), "uni%04x", ch); glyph = uniglyph; } for (newch = 128; newch < 256; newch ++) if (_htmlGlyphs[newch] && !strcmp(_htmlGlyphs[newch], glyph)) break; if (newch >= 256) { // Not part of the standard charset, see if we have room for a // few extras... for (newch = 128; newch < 256; newch ++) if (!_htmlGlyphs[newch]) { // Yes, assign this character to it... if (glyph == uniglyph) _htmlGlyphsAll[ch] = _htmlGlyphs[newch] = strdup(glyph); else _htmlGlyphs[newch] = glyph; _htmlUnicode[newch] = ch; // Update font widths... for (int typeface = 0; typeface < TYPE_MAX; typeface ++) { for (int style = 0; style < STYLE_MAX; style ++) { if (_htmlWidthsLoaded[typeface][style]) { _htmlWidths[typeface][style][newch] = _htmlWidthsAll[typeface][style][ch]; } } } // Return the new character... return ((uchar)newch); } // No room, return nul... return (0); } else ch = newch; } return ((uchar)ch); } /* * 'iso8859()' - Return the glyph name of an 8-bit character value. */ uchar * /* O - Glyph name */ iso8859(uchar value) /* I - ISO-8859-1 equivalent */ { int i; /* Looping var */ int ch; /* Current character */ static int first_time = 1; /* First time called? */ static uchar buf[255]; /* Character buffer */ if (first_time) { memset(iso8859_names, 0, sizeof(iso8859_names)); for (i = 0; i < (int)(sizeof(iso8859_numbers) / sizeof(iso8859_numbers[0])); i ++) if ((ch = iso8859_numbers[i].value) < 128) iso8859_names[ch] = iso8859_numbers + i; else { // Lookup Unicode value in the current charset... const char *glyph; char uniglyph[32]; if ((glyph = _htmlGlyphsAll[ch]) == NULL) { snprintf(uniglyph, sizeof(uniglyph), "uni%04x", ch); glyph = uniglyph; } for (ch = 128; ch < 256; ch ++) if (_htmlGlyphs[ch] && !strcmp(_htmlGlyphs[ch], glyph)) { iso8859_names[ch] = iso8859_numbers + i; break; } } first_time = 0; } if (iso8859_names[value] == NULL) { buf[0] = value; buf[1] = '\0'; } else snprintf((char *)buf, sizeof(buf), "&%s;", iso8859_names[value]->name); return (buf); } /* * 'xhtml_entity()' - Return the UTF-8 character or XHTML entity. */ const uchar * /* O - XHTML string */ xhtml_entity(uchar ch) /* I - Character */ { static uchar buf[5]; /* UTF-8 character buffer */ if (ch == '&') return ((uchar *)"&"); else if (ch == '<') return ((uchar *)"<"); else if (ch == '>') return ((uchar *)">"); else if (ch == '\"') return ((uchar *)"""); else if (ch >= ' ' && ch < 0x7f) { // US ASCII buf[0] = ch; buf[1] = '\0'; return (buf); } else { // Unicode -> UTF-8 int unich = _htmlUnicode[ch]; if (unich < 0x80) { // 1-byte US ASCII buf[0] = (uchar)unich; buf[1] = '\0'; } else if (unich < 0x800) { // 2-byte UTF-8 buf[0] = (uchar)(0xc0 | (unich >> 6)); buf[1] = (uchar)(0x80 | (unich & 0x3f)); buf[2] = '\0'; } else if (unich < 0x10000) { // 3-byte UTF-8 buf[0] = (uchar)(0xe0 | (unich >> 12)); buf[1] = (uchar)(0x80 | ((unich >> 6) & 0x3f)); buf[2] = (uchar)(0x80 | (unich & 0x3f)); buf[3] = '\0'; } else { // 4-byte UTF-8 buf[0] = (uchar)(0xf0 | (unich >> 18)); buf[1] = (uchar)(0x80 | ((unich >> 12) & 0x3f)); buf[2] = (uchar)(0x80 | ((unich >> 6) & 0x3f)); buf[3] = (uchar)(0x80 | (unich & 0x3f)); buf[4] = '\0'; } return (buf); } } /* * 'compare_lut()' - Compare two glyphs. */ static int /* O - 0 if equal, -1 if ab */ compare_lut(lut_t *a, /* I - First glyph */ lut_t *b) /* I - Second glyph */ { return (strcmp((char *)a->name, (char *)b->name)); } htmldoc-1.9.7/htmldoc/iso8859.h000066400000000000000000000011211354715574200161250ustar00rootroot00000000000000/* * ISO-8859-1 definitions for HTMLDOC, an HTML document processing program. * * Copyright 2011-2017 by Michael R Sweet. * Copyright 1997-2010 by Easy Software Products. All rights reserved. * * This program is free software. Distribution and use rights are outlined in * the file "COPYING". */ #ifndef _ISO8859_H_ # define _ISO8859_H_ /* * Include necessary headers. */ # include "types.h" /* * Prototypes... */ extern uchar iso8859(uchar *name); extern uchar *iso8859(uchar value); extern const uchar *xhtml_entity(uchar ch); #endif /* !_ISO8859_H_ */ htmldoc-1.9.7/htmldoc/license.cxx000066400000000000000000000533601354715574200170060ustar00rootroot00000000000000// // GUI license dialog routines for HTMLDOC, an HTML document processing // program. // // Copyright 2011-2017 by Michael R Sweet. // Copyright 1997-2010 by Easy Software Products. All rights reserved. // // This program is free software. Distribution and use rights are outlined in // the file "COPYING". // #include "htmldoc.h" #ifdef HAVE_LIBFLTK // // Include necessary headers. // # include # include # include # include # include // // Local functions... // static void closeLicenseCB(Fl_Widget *w); // // 'GUI::showLicenseCB()' - Show the current license. // void GUI::showLicenseCB(void) { Fl_Window *dialog; // Dialog window Fl_Group *group; // Raised area Fl_Help_View *help; // License agreement viewer Fl_Button *button; // Button Fl_Box *box; // Text box // Create the window complete with the license agreement and // button to add a new license... dialog = new Fl_Window(640, 480, "HTMLDOC " SVERSION " License"); dialog->set_modal(); dialog->hotspot(dialog); group = new Fl_Group(10, 10, 620, 425, "HTMLDOC " SVERSION " License"); group->align((Fl_Align)(FL_ALIGN_LEFT | FL_ALIGN_TOP | FL_ALIGN_INSIDE)); group->box(FL_THIN_UP_BOX); group->labelcolor(FL_BLUE); group->labelfont(FL_HELVETICA_BOLD); group->labelsize(18); box = new Fl_Box(20, 45, 600, 110, "Copyright (c) 2011-2017 by Michael R Sweet.\n\n" "HTMLDOC is provided under the terms of the GNU General Public License and " "comes with absolutely no warranty. Please report problems on the Github " "issues page at:\n\n" " https://github.com/michaelrsweet/htmldoc/issues\n" ); box->align((Fl_Align)(FL_ALIGN_TOP_LEFT | FL_ALIGN_INSIDE | FL_ALIGN_WRAP)); help = new Fl_Help_View(20, 190, 600, 235, "Software License Agreement:"); help->align(FL_ALIGN_TOP_LEFT); help->value( "

    GNU GENERAL PUBLIC LICENSE

    \n" "

    Version 2, June 1991 " "

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

    Preamble

    \n" "

    The licenses for most software are designed to take away your " "freedom to share and change it. By contrast, the GNU General Public " "License is intended to guarantee your freedom to share and change free " "software--to make sure the software is free for all its users. This " "General Public License applies to most of the Free Software " "Foundation's software and to any other program whose authors commit to " "using it. (Some other Free Software Foundation software is covered by " "the GNU Library General Public License instead.) You can apply it to " "your programs, too. " "

    When we speak of free software, we are referring to freedom, not " "price. Our General Public Licenses are designed to make sure that you " "have the freedom to distribute copies of free software (and charge for " "this service if you wish), that you receive source code or can get it " "if you want it, that you can change the software or use pieces of it " "in new free programs; and that you know you can do these things. " "

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

    For example, if you distribute copies of such a program, whether " "gratis or for a fee, you must give the recipients all the rights that " "you have. You must make sure that they, too, receive or can get the " "source code. And you must show them these terms so they know their " "rights. " "

    We protect your rights with two steps: (1) copyright the software, and " "(2) offer you this license which gives you legal permission to copy, " "distribute and/or modify the software. " "

    Also, for each author's protection and ours, we want to make certain " "that everyone understands that there is no warranty for this free " "software. If the software is modified by someone else and passed on, we " "want its recipients to know that what they have is not the original, so " "that any problems introduced by others will not reflect on the original " "authors' reputations. " "

    Finally, any free program is threatened constantly by software " "patents. We wish to avoid the danger that redistributors of a free " "program will individually obtain patent licenses, in effect making the " "program proprietary. To prevent this, we have made it clear that any " "patent must be licensed for everyone's free use or not licensed at all. " "

    The precise terms and conditions for copying, distribution and " "modification follow. " "

    GNU GENERAL PUBLIC LICENSE
    \n" "TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION

    \n" "

    0. This License applies to any program or other work which contains " "a notice placed by the copyright holder saying it may be distributed " "under the terms of this General Public License. The \"Program\", below, " "refers to any such program or work, and a \"work based on the Program\" " "means either the Program or any derivative work under copyright law: " "that is to say, a work containing the Program or a portion of it, " "either verbatim or with modifications and/or translated into another " "language. (Hereinafter, translation is included without limitation in " "the term \"modification\".) Each licensee is addressed as \"you\". " "

    Activities other than copying, distribution and modification are not " "covered by this License; they are outside its scope. The act of " "running the Program is not restricted, and the output from the Program " "is covered only if its contents constitute a work based on the " "Program (independent of having been made by running the Program). " "Whether that is true depends on what the Program does. " "

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

    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 Program or any portion " "of it, thus forming a work based on the Program, 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. You must cause the modified files to carry prominent notices " "stating that you changed the files and the date of any change. " "

    b. You must cause any work that you distribute or publish, that in " "whole or in part contains or is derived from the Program or any " "part thereof, to be licensed as a whole at no charge to all third " "parties under the terms of this License. " "

    c. if the modified program normally reads commands interactively " "when run, you must cause it, when started running for such " "interactive use in the most ordinary way, to print or display an " "announcement including an appropriate copyright notice and a " "notice that there is no warranty (or else, saying that you provide " "a warranty) and that users may redistribute the program under " "these conditions, and telling the user how to view a copy of this " "License. (Exception: if the Program itself is interactive but " "does not normally print such an announcement, your work based on " "the Program is not required to print an announcement.) " "

    These requirements apply to the modified work as a whole. If " "identifiable sections of that work are not derived from the Program, " "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 Program, 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 Program. " "

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

    3. You may copy and distribute the Program (or a work based on it, " "under Section 2) in object code or executable form under the terms of " "Sections 1 and 2 above provided that you also do one of the following: " "

    a. 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; or, " "

    b. Accompany it with a written offer, valid for at least three " "years, to give any third party, for a charge no more than your " "cost of physically performing source distribution, a complete " "machine-readable copy of the corresponding source code, to be " "distributed under the terms of Sections 1 and 2 above on a medium " "customarily used for software interchange; or, " "

    c. Accompany it with the information you received as to the offer " "to distribute corresponding source code. (This alternative is " "allowed only for noncommercial distribution and only if you " "received the program in object code or executable form with such " "an offer, in accord with Subsection b above.) " "

    The source code for a work means the preferred form of the work for " "making modifications to it. For an executable work, 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 executable. However, as a " "special exception, the source code 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. " "

    If distribution of executable or 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 counts as " "distribution of the source code, even though third parties are not " "compelled to copy the source along with the object code. " "

    4. You may not copy, modify, sublicense, or distribute the Program " "except as expressly provided under this License. Any attempt " "otherwise to copy, modify, sublicense or distribute the Program 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. " "

    5. 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 Program or its derivative works. These actions are " "prohibited by law if you do not accept this License. Therefore, by " "modifying or distributing the Program (or any work based on the " "Program), you indicate your acceptance of this License to do so, and " "all its terms and conditions for copying, distributing or modifying " "the Program or works based on it. " "

    6. Each time you redistribute the Program (or any work based on the " "Program), the recipient automatically receives a license from the " "original licensor to copy, distribute or modify the Program 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 to " "this License. " "

    7. 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 Program at all. For example, if a patent " "license would not permit royalty-free redistribution of the Program 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 Program. " "

    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. " "

    8. If the distribution and/or use of the Program is restricted in " "certain countries either by patents or by copyrighted interfaces, the " "original copyright holder who places the Program 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. " "

    9. The Free Software Foundation may publish revised and/or new versions " "of the General Public License from time to time. Such new versions will " "be similar in spirit to the present version, but may differ in detail to " "address new problems or concerns. " "

    Each version is given a distinguishing version number. If the Program " "specifies 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 Program does not specify a version number of " "this License, you may choose any version ever published by the Free Software " "Foundation. " "

    10. If you wish to incorporate parts of the Program into other free " "programs whose distribution conditions are different, 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

    \n" "

    11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY " "FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN " "OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES " "PROVIDE THE PROGRAM \"AS IS\" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED " "OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF " "MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS " "TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE " "PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, " "REPAIR OR CORRECTION. " "

    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 PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, " "INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING " "OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED " "TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY " "YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER " "PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE " "POSSIBILITY OF SUCH DAMAGES. " "

    END OF TERMS AND CONDITIONS

    \n" "

    How to Apply These Terms to Your New Programs

    \n" "\n" "

    If you develop a new program, and you want it to be of the greatest\n" "possible use to the public, the best way to achieve this is to make it\n" "free software which everyone can redistribute and change under these terms.\n" "\n" "

    To do so, attach the following notices to the program. It is safest\n" "to attach them to the start of each source file to most effectively\n" "convey the exclusion of warranty; and each file should have at least\n" "the \"copyright\" line and a pointer to where the full notice is found.\n" "\n" "

    \n"
        "one line to give the program's name and an idea of what it does.\n"
        "Copyright (C) yyyy  name of author\n"
        "\n"
        "This program is free software; you can redistribute it and/or\n"
        "modify it under the terms of the GNU General Public License\n"
        "as published by the Free Software Foundation; either version 2\n"
        "of the License, or (at your option) any later version.\n"
        "\n"
        "This program is distributed in the hope that it will be useful,\n"
        "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
        "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n"
        "GNU General Public License for more details.\n"
        "\n"
        "You should have received a copy of the GNU General Public License\n"
        "along with this program; if not, write to the Free Software\n"
        "Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.\n"
        "
    \n" "\n" "

    Also add information on how to contact you by electronic and paper mail.\n" "\n" "

    If the program is interactive, make it output a short notice like this\n" "when it starts in an interactive mode:\n" "\n" "

    \n"
        "Gnomovision version 69, Copyright (C) year name of author\n"
        "Gnomovision comes with ABSOLUTELY NO WARRANTY; for details\n"
        "type `show w'.  This is free software, and you are welcome\n"
        "to redistribute it under certain conditions; type `show c' \n"
        "for details.\n"
        "
    \n" "\n" "

    The hypothetical commands `show w' and `show c' should show\n" "the appropriate parts of the General Public License. Of course, the\n" "commands you use may be called something other than `show w' and\n" "`show c'; they could even be mouse-clicks or menu items--whatever\n" "suits your program.\n" "\n" "

    You should also get your employer (if you work as a programmer) or your\n" "school, if any, to sign a \"copyright disclaimer\" for the program, if\n" "necessary. Here is a sample; alter the names:\n" "\n" "

    \n"
        "Yoyodyne, Inc., hereby disclaims all copyright\n"
        "interest in the program `Gnomovision'\n"
        "(which makes passes at compilers) written \n"
        "by James Hacker.\n"
        "\n"
        "signature of Ty Coon, 1 April 1989\n"
        "Ty Coon, President of Vice\n"
        "
    \n" ); group->end(); button = new Fl_Button(565, 445, 65, 25, "Close"); button->callback((Fl_Callback *)closeLicenseCB); // Show the window and wait... dialog->end(); dialog->show(); while (dialog->shown()) Fl::wait(); delete dialog; } // // 'closeLicenseCB()' - Close the license window. // static void closeLicenseCB(Fl_Widget *w) // I - Close button { if (w && w->window()) w->window()->hide(); } #endif // HAVE_LIBFLTK htmldoc-1.9.7/htmldoc/markdown.cxx000066400000000000000000000321141354715574200172000ustar00rootroot00000000000000/* * Markdown parsing definitions for HTMLDOC, a HTML document processing program. * * Copyright © 2017-2019 by Michael R Sweet. * * This program is free software. Distribution and use rights are outlined in * the file "COPYING". */ /* * Include necessary headers... */ # include "markdown.h" # include "mmd.h" # include "progress.h" /* * Local functions... */ static void add_block(tree_t *hparent, mmd_t *parent); static void add_leaf(tree_t *hparent, mmd_t *node); static uchar *get_text(uchar *text); static uchar *make_anchor(mmd_t *block); static uchar *make_anchor(const uchar *text); /* * 'mdReadFile()' - Read a Markdown file. */ tree_t * /* O - HTML document tree */ mdReadFile(tree_t *parent, /* I - Parent node */ FILE *fp, /* I - File to read from */ const char *base) /* I - Base path/URL */ { mmd_t *doc = mmdLoadFile(fp); /* Markdown document */ tree_t *html, /* HTML element */ *head, /* HEAD element */ *temp, /* META/TITLE element */ *body; /* BODY element */ const char *meta; /* Title, author, etc. */ html = htmlAddTree(parent, MARKUP_HTML, NULL); if ((meta = mmdGetMetadata(doc, "lang")) != NULL) htmlSetVariable(html, (uchar *)"lang", get_text((uchar *)meta)); head = htmlAddTree(html, MARKUP_HEAD, NULL); if ((meta = mmdGetMetadata(doc, "title")) != NULL) { temp = htmlAddTree(head, MARKUP_TITLE, NULL); htmlAddTree(temp, MARKUP_NONE, get_text((uchar *)meta)); } if ((meta = mmdGetMetadata(doc, "author")) != NULL) { temp = htmlAddTree(head, MARKUP_META, NULL); htmlSetVariable(temp, (uchar *)"name", (uchar *)"author"); htmlSetVariable(temp, (uchar *)"content", get_text((uchar *)meta)); } if ((meta = mmdGetMetadata(doc, "copyright")) != NULL) { temp = htmlAddTree(head, MARKUP_META, NULL); htmlSetVariable(temp, (uchar *)"name", (uchar *)"copyright"); htmlSetVariable(temp, (uchar *)"content", get_text((uchar *)meta)); } if ((meta = mmdGetMetadata(doc, "version")) != NULL) { temp = htmlAddTree(head, MARKUP_META, NULL); htmlSetVariable(temp, (uchar *)"name", (uchar *)"version"); htmlSetVariable(temp, (uchar *)"content", get_text((uchar *)meta)); } if ((meta = mmdGetMetadata(doc, "language")) != NULL) { htmlSetVariable(html, (uchar *)"lang", get_text((uchar *)meta)); } if ((meta = mmdGetMetadata(doc, "subject")) != NULL) { temp = htmlAddTree(head, MARKUP_META, NULL); htmlSetVariable(temp, (uchar *)"name", (uchar *)"keywords"); htmlSetVariable(temp, (uchar *)"content", get_text((uchar *)meta)); } body = htmlAddTree(html, MARKUP_BODY, NULL); add_block(body, doc); mmdFree(doc); return (html); } /* * 'add_block()' - Add a block node. */ static void add_block(tree_t *html, /* I - Parent HTML node */ mmd_t *parent) /* I - Parent node */ { markup_t element; /* Enclosing element, if any */ mmd_t *node; /* Current child node */ mmd_type_t type; /* Node type */ tree_t *block; /* Block node */ const char *align = NULL; /* Alignment */ switch (type = mmdGetType(parent)) { case MMD_TYPE_BLOCK_QUOTE : element = MARKUP_BLOCKQUOTE; break; case MMD_TYPE_ORDERED_LIST : element = MARKUP_OL; break; case MMD_TYPE_UNORDERED_LIST : element = MARKUP_UL; break; case MMD_TYPE_LIST_ITEM : element = MARKUP_LI; break; case MMD_TYPE_HEADING_1 : element = MARKUP_H1; break; case MMD_TYPE_HEADING_2 : element = MARKUP_H2; break; case MMD_TYPE_HEADING_3 : element = MARKUP_H3; break; case MMD_TYPE_HEADING_4 : element = MARKUP_H4; break; case MMD_TYPE_HEADING_5 : element = MARKUP_H5; break; case MMD_TYPE_HEADING_6 : element = MARKUP_H6; break; case MMD_TYPE_PARAGRAPH : element = MARKUP_P; break; case MMD_TYPE_CODE_BLOCK : block = htmlAddTree(html, MARKUP_PRE, NULL); for (node = mmdGetFirstChild(parent); node; node = mmdGetNextSibling(node)) htmlAddTree(block, MARKUP_NONE, get_text((uchar *)mmdGetText(node))); return; case MMD_TYPE_THEMATIC_BREAK : htmlAddTree(html, MARKUP_HR, NULL); return; case MMD_TYPE_TABLE : element = MARKUP_TABLE; break; case MMD_TYPE_TABLE_HEADER : element = MARKUP_THEAD; break; case MMD_TYPE_TABLE_BODY : element = MARKUP_TBODY; break; case MMD_TYPE_TABLE_ROW : element = MARKUP_TR; break; case MMD_TYPE_TABLE_HEADER_CELL : element = MARKUP_TH; break; case MMD_TYPE_TABLE_BODY_CELL_LEFT : element = MARKUP_TD; break; case MMD_TYPE_TABLE_BODY_CELL_CENTER : element = MARKUP_TD; align = "center"; break; case MMD_TYPE_TABLE_BODY_CELL_RIGHT : element = MARKUP_TD; align = "right"; break; default : element = MARKUP_NONE; break; } if (element != MARKUP_NONE) block = htmlAddTree(html, element, NULL); else block = html; if (align) { htmlSetVariable(block, (uchar *)"align", (uchar *)align); if (!strcmp(align, "center")) block->halignment = ALIGN_CENTER; else block->halignment = ALIGN_RIGHT; } else if (element == MARKUP_TH) { block->halignment = ALIGN_CENTER; htmlSetVariable(block, (uchar *)"bgcolor", (uchar *)"#cccccc"); } else if (element == MARKUP_TABLE) { htmlSetVariable(block, (uchar *)"border", (uchar *)"1"); htmlSetVariable(block, (uchar *)"cellpadding", (uchar *)"2"); } if (type >= MMD_TYPE_HEADING_1 && type <= MMD_TYPE_HEADING_6) { /* * Add an anchor for each heading... */ block = htmlAddTree(block, MARKUP_A, NULL); htmlSetVariable(block, (uchar *)"id", make_anchor(parent)); } if (type >= MMD_TYPE_TABLE_BODY_CELL_LEFT && type <= MMD_TYPE_TABLE_BODY_CELL_RIGHT && !mmdGetFirstChild(parent)) { // Make sure table body cells have at least a non-breaking space... htmlAddTree(block, MARKUP_NONE, (uchar *)" "); } else { for (node = mmdGetFirstChild(parent); node; node = mmdGetNextSibling(node)) { if (mmdIsBlock(node)) add_block(block, node); else add_leaf(block, node); } } } /* * 'add_leaf()' - Add a leaf node. */ static void add_leaf(tree_t *html, /* I - Parent HTML node */ mmd_t *node) /* I - Leaf node */ { tree_t *parent; /* HTML node for this text */ markup_t element; /* HTML element for this text */ uchar buffer[1024], /* Text with any added whitespace */ *text, /* Text to write */ *url; /* URL to write */ int whitespace; /* Whitespace before text? */ text = get_text((uchar *)mmdGetText(node)); url = (uchar *)mmdGetURL(node); whitespace = mmdGetWhitespace(node); switch (mmdGetType(node)) { case MMD_TYPE_EMPHASIZED_TEXT : element = MARKUP_EM; break; case MMD_TYPE_STRONG_TEXT : element = MARKUP_STRONG; break; case MMD_TYPE_STRUCK_TEXT : element = MARKUP_DEL; break; case MMD_TYPE_LINKED_TEXT : element = MARKUP_A; break; case MMD_TYPE_CODE_TEXT : element = MARKUP_CODE; break; case MMD_TYPE_IMAGE : if (mmdGetWhitespace(node)) htmlAddTree(html, MARKUP_NONE, (uchar *)" "); parent = htmlAddTree(html, MARKUP_IMG, NULL); htmlSetVariable(parent, (uchar *)"src", url); if (text) htmlSetVariable(parent, (uchar *)"alt", text); return; case MMD_TYPE_HARD_BREAK : htmlAddTree(html, MARKUP_BR, NULL); return; case MMD_TYPE_SOFT_BREAK : htmlAddTree(html, MARKUP_WBR, NULL); return; case MMD_TYPE_METADATA_TEXT : return; default : element = MARKUP_NONE; break; } if (element == MARKUP_NONE) parent = html; else if ((parent = html->last_child) == NULL || parent->markup != element) { if (whitespace) { htmlAddTree(html, MARKUP_NONE, (uchar *)" "); whitespace = 0; } parent = htmlAddTree(html, element, NULL); if (element == MARKUP_A && url) { if (!strcmp((char *)url, "@")) htmlSetVariable(parent, (uchar *)"href", make_anchor(text)); else htmlSetVariable(parent, (uchar *)"href", url); } } if (whitespace) { buffer[0] = ' '; strlcpy((char *)buffer + 1, (char *)text, sizeof(buffer) - 1); text = buffer; } htmlAddTree(parent, MARKUP_NONE, text); } /* * 'get_text()' - Get Markdown text in HTMLDOC's charset. */ static uchar * /* O - Encoded text */ get_text(uchar *text) /* I - Markdown text */ { uchar *bufptr, /* Pointer into buffer */ *bufend; /* End of buffer */ int unich; /* Unicode character */ static uchar buffer[8192]; /* Temporary buffer */ if (!_htmlUTF8) return (text); bufptr = buffer; bufend = buffer + sizeof(buffer) - 1; while (*text && bufptr < bufend) { if (*text & 0x80) { unich = 0; if ((*text & 0xe0) == 0xc0) { if ((text[1] & 0xc0) != 0x80) { progress_error(HD_ERROR_READ_ERROR, "Bad UTF-8 character sequence %02X %02X.", *text, text[1]); *bufptr++ = '?'; text ++; } else { unich = ((*text & 0x1f) << 6) | (text[1] & 0x3f); text += 2; } } else if ((*text & 0xf0) == 0xe0) { if ((text[1] & 0xc0) != 0x80 || (text[2] & 0xc0) != 0x80) { progress_error(HD_ERROR_READ_ERROR, "Bad UTF-8 character sequence %02X %02X %02X.", *text, text[1], text[2]); *bufptr++ = '?'; text ++; } else { unich = ((*text & 0x0f) << 12) | ((text[1] & 0x3f) << 6) | (text[1] & 0x3f); text += 3; } } else { progress_error(HD_ERROR_READ_ERROR, "Bad UTF-8 character sequence %02X.", *text); *bufptr++ = '?'; text ++; } if (unich) { if (_htmlCharacters[unich]) { *bufptr++ = _htmlCharacters[unich]; } else { uchar ch; /* 8-bit character */ if (_htmlUTF8 >= 0x100) { progress_error(HD_ERROR_READ_ERROR, "Too many Unicode code points."); return (0); } ch = (uchar)_htmlUTF8++; _htmlCharacters[unich] = ch; _htmlUnicode[ch] = unich; _htmlGlyphs[ch] = _htmlGlyphsAll[unich]; for (int i = 0; i < TYPE_MAX; i ++) for (int j = 0; j < STYLE_MAX; j ++) _htmlWidths[i][j][ch] = _htmlWidthsAll[i][j][unich]; *bufptr++ = ch; } } } else *bufptr++ = *text++; } *bufptr = '\0'; return (buffer); } /* * 'make_anchor()' - Make an anchor for internal links from a block node. */ static uchar * /* O - Anchor string */ make_anchor(mmd_t *block) /* I - Block node */ { mmd_t *node; /* Current child node */ const char *text; /* Text from block */ uchar *bufptr; /* Pointer into buffer */ static uchar buffer[1024]; /* Buffer for anchor string */ for (bufptr = buffer, node = mmdGetFirstChild(block); node; node = mmdGetNextSibling(node)) { if (mmdGetWhitespace(node) && bufptr < (buffer + sizeof(buffer) - 1)) *bufptr++ = '-'; for (text = mmdGetText(node); text && *text && bufptr < (buffer + sizeof(buffer) -1); text ++) { if ((*text >= '0' && *text <= '9') || (*text >= 'a' && *text <= 'z') || (*text >= 'A' && *text <= 'Z') || *text == '.' || *text == '-') *bufptr++ = (uchar)tolower(*text); else if (*text == ' ') *bufptr++ = '-'; } } *bufptr = '\0'; return (buffer); } /* * 'make_anchor()' - Make an anchor for internal links from text. */ static uchar * /* O - Anchor string */ make_anchor(const uchar *text) /* I - Text */ { uchar *bufptr; /* Pointer into buffer */ static uchar buffer[1024]; /* Buffer for anchor string */ for (bufptr = buffer; *text && bufptr < (buffer + sizeof(buffer) - 1); text ++) { if ((*text >= '0' && *text <= '9') || (*text >= 'a' && *text <= 'z') || (*text >= 'A' && *text <= 'Z') || *text == '.' || *text == '-') *bufptr++ = (uchar)tolower(*text); else if (*text == ' ') *bufptr++ = '-'; } *bufptr = '\0'; return (buffer); } htmldoc-1.9.7/htmldoc/markdown.h000066400000000000000000000011271354715574200166250ustar00rootroot00000000000000/* * Markdown parsing definitions for HTMLDOC, a HTML document processing program. * * Copyright 2017 by Michael R Sweet. * * This program is free software. Distribution and use rights are outlined in * the file "COPYING". */ #ifndef _MARKDOWN_H_ # define _MARKDOWN_H_ /* * Include necessary headers... */ # include "html.h" # include "mmd.h" # ifdef __cplusplus extern "C" { # endif /* __cplusplus */ /* * Prototypes... */ extern tree_t *mdReadFile(tree_t *parent, FILE *fp, const char *base); # ifdef __cplusplus } # endif /* __cplusplus */ #endif /* !_MARKDOWN_H_ */ htmldoc-1.9.7/htmldoc/md5-private.h000066400000000000000000000050401354715574200171360ustar00rootroot00000000000000/* * Private MD5 definitions for CUPS. * * Copyright 2007-2010 by Apple Inc. * Copyright 2005 by Easy Software Products * * Copyright (C) 1999 Aladdin Enterprises. All rights reserved. * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. * * L. Peter Deutsch * ghost@aladdin.com */ /* Independent implementation of MD5 (RFC 1321). This code implements the MD5 Algorithm defined in RFC 1321. It is derived directly from the text of the RFC and not from the reference implementation. The original and principal author of md5.h is L. Peter Deutsch . Other authors are noted in the change history that follows (in reverse chronological order): 1999-11-04 lpd Edited comments slightly for automatic TOC extraction. 1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5); added conditionalization for C++ compilation from Martin Purschke . 1999-05-03 lpd Original version. */ #ifndef _CUPS_MD5_PRIVATE_H_ # define _CUPS_MD5_PRIVATE_H_ /* Define the state of the MD5 Algorithm. */ typedef struct _cups_md5_state_s { unsigned int count[2]; /* message length in bits, lsw first */ unsigned int abcd[4]; /* digest buffer */ unsigned char buf[64]; /* accumulate block */ } _cups_md5_state_t; # ifdef __cplusplus extern "C" { # endif /* __cplusplus */ /* Initialize the algorithm. */ void _cupsMD5Init(_cups_md5_state_t *pms); /* Append a string to the message. */ void _cupsMD5Append(_cups_md5_state_t *pms, const unsigned char *data, int nbytes); /* Finish the message and return the digest. */ void _cupsMD5Finish(_cups_md5_state_t *pms, unsigned char digest[16]); # ifdef __cplusplus } /* end extern "C" */ # endif /* __cplusplus */ #endif /* !_CUPS_MD5_PRIVATE_H_ */ htmldoc-1.9.7/htmldoc/md5.c000066400000000000000000000232741354715574200154720ustar00rootroot00000000000000/* * Private MD5 implementation for CUPS. * * Copyright 2007-2010 by Apple Inc. * Copyright 2005 by Easy Software Products * * Copyright (C) 1999 Aladdin Enterprises. All rights reserved. * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. * * L. Peter Deutsch * ghost@aladdin.com */ /* Independent implementation of MD5 (RFC 1321). This code implements the MD5 Algorithm defined in RFC 1321. It is derived directly from the text of the RFC and not from the reference implementation. The original and principal author of md5.c is L. Peter Deutsch . Other authors are noted in the change history that follows (in reverse chronological order): 1999-11-04 lpd Edited comments slightly for automatic TOC extraction. 1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5). 1999-05-03 lpd Original version. */ #include "md5-private.h" #include #define T1 0xd76aa478 #define T2 0xe8c7b756 #define T3 0x242070db #define T4 0xc1bdceee #define T5 0xf57c0faf #define T6 0x4787c62a #define T7 0xa8304613 #define T8 0xfd469501 #define T9 0x698098d8 #define T10 0x8b44f7af #define T11 0xffff5bb1 #define T12 0x895cd7be #define T13 0x6b901122 #define T14 0xfd987193 #define T15 0xa679438e #define T16 0x49b40821 #define T17 0xf61e2562 #define T18 0xc040b340 #define T19 0x265e5a51 #define T20 0xe9b6c7aa #define T21 0xd62f105d #define T22 0x02441453 #define T23 0xd8a1e681 #define T24 0xe7d3fbc8 #define T25 0x21e1cde6 #define T26 0xc33707d6 #define T27 0xf4d50d87 #define T28 0x455a14ed #define T29 0xa9e3e905 #define T30 0xfcefa3f8 #define T31 0x676f02d9 #define T32 0x8d2a4c8a #define T33 0xfffa3942 #define T34 0x8771f681 #define T35 0x6d9d6122 #define T36 0xfde5380c #define T37 0xa4beea44 #define T38 0x4bdecfa9 #define T39 0xf6bb4b60 #define T40 0xbebfbc70 #define T41 0x289b7ec6 #define T42 0xeaa127fa #define T43 0xd4ef3085 #define T44 0x04881d05 #define T45 0xd9d4d039 #define T46 0xe6db99e5 #define T47 0x1fa27cf8 #define T48 0xc4ac5665 #define T49 0xf4292244 #define T50 0x432aff97 #define T51 0xab9423a7 #define T52 0xfc93a039 #define T53 0x655b59c3 #define T54 0x8f0ccc92 #define T55 0xffeff47d #define T56 0x85845dd1 #define T57 0x6fa87e4f #define T58 0xfe2ce6e0 #define T59 0xa3014314 #define T60 0x4e0811a1 #define T61 0xf7537e82 #define T62 0xbd3af235 #define T63 0x2ad7d2bb #define T64 0xeb86d391 static void _cups_md5_process(_cups_md5_state_t *pms, const unsigned char *data /*[64]*/) { unsigned int a = pms->abcd[0], b = pms->abcd[1], c = pms->abcd[2], d = pms->abcd[3]; unsigned int t; #ifndef ARCH_IS_BIG_ENDIAN # define ARCH_IS_BIG_ENDIAN 1 /* slower, default implementation */ #endif #if ARCH_IS_BIG_ENDIAN /* * On big-endian machines, we must arrange the bytes in the right * order. (This also works on machines of unknown byte order.) */ unsigned int X[16]; const unsigned char *xp = data; int i; for (i = 0; i < 16; ++i, xp += 4) X[i] = xp[0] + (unsigned)(xp[1] << 8) + (unsigned)(xp[2] << 16) + (unsigned)(xp[3] << 24); #else /* !ARCH_IS_BIG_ENDIAN */ /* * On little-endian machines, we can process properly aligned data * without copying it. */ unsigned int xbuf[16]; const unsigned int *X; if (!((data - (const unsigned char *)0) & 3)) { /* data are properly aligned */ X = (const unsigned int *)data; } else { /* not aligned */ memcpy(xbuf, data, 64); X = xbuf; } #endif #define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n)))) /* Round 1. */ /* Let [abcd k s i] denote the operation a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). */ #define F(x, y, z) (((x) & (y)) | (~(x) & (z))) #define SET(a, b, c, d, k, s, Ti)\ t = a + F(b,c,d) + X[k] + Ti;\ a = ROTATE_LEFT(t, s) + b /* Do the following 16 operations. */ SET(a, b, c, d, 0, 7, T1); SET(d, a, b, c, 1, 12, T2); SET(c, d, a, b, 2, 17, T3); SET(b, c, d, a, 3, 22, T4); SET(a, b, c, d, 4, 7, T5); SET(d, a, b, c, 5, 12, T6); SET(c, d, a, b, 6, 17, T7); SET(b, c, d, a, 7, 22, T8); SET(a, b, c, d, 8, 7, T9); SET(d, a, b, c, 9, 12, T10); SET(c, d, a, b, 10, 17, T11); SET(b, c, d, a, 11, 22, T12); SET(a, b, c, d, 12, 7, T13); SET(d, a, b, c, 13, 12, T14); SET(c, d, a, b, 14, 17, T15); SET(b, c, d, a, 15, 22, T16); #undef SET /* Round 2. */ /* Let [abcd k s i] denote the operation a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */ #define G(x, y, z) (((x) & (z)) | ((y) & ~(z))) #define SET(a, b, c, d, k, s, Ti)\ t = a + G(b,c,d) + X[k] + Ti;\ a = ROTATE_LEFT(t, s) + b /* Do the following 16 operations. */ SET(a, b, c, d, 1, 5, T17); SET(d, a, b, c, 6, 9, T18); SET(c, d, a, b, 11, 14, T19); SET(b, c, d, a, 0, 20, T20); SET(a, b, c, d, 5, 5, T21); SET(d, a, b, c, 10, 9, T22); SET(c, d, a, b, 15, 14, T23); SET(b, c, d, a, 4, 20, T24); SET(a, b, c, d, 9, 5, T25); SET(d, a, b, c, 14, 9, T26); SET(c, d, a, b, 3, 14, T27); SET(b, c, d, a, 8, 20, T28); SET(a, b, c, d, 13, 5, T29); SET(d, a, b, c, 2, 9, T30); SET(c, d, a, b, 7, 14, T31); SET(b, c, d, a, 12, 20, T32); #undef SET /* Round 3. */ /* Let [abcd k s t] denote the operation a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */ #define H(x, y, z) ((x) ^ (y) ^ (z)) #define SET(a, b, c, d, k, s, Ti)\ t = a + H(b,c,d) + X[k] + Ti;\ a = ROTATE_LEFT(t, s) + b /* Do the following 16 operations. */ SET(a, b, c, d, 5, 4, T33); SET(d, a, b, c, 8, 11, T34); SET(c, d, a, b, 11, 16, T35); SET(b, c, d, a, 14, 23, T36); SET(a, b, c, d, 1, 4, T37); SET(d, a, b, c, 4, 11, T38); SET(c, d, a, b, 7, 16, T39); SET(b, c, d, a, 10, 23, T40); SET(a, b, c, d, 13, 4, T41); SET(d, a, b, c, 0, 11, T42); SET(c, d, a, b, 3, 16, T43); SET(b, c, d, a, 6, 23, T44); SET(a, b, c, d, 9, 4, T45); SET(d, a, b, c, 12, 11, T46); SET(c, d, a, b, 15, 16, T47); SET(b, c, d, a, 2, 23, T48); #undef SET /* Round 4. */ /* Let [abcd k s t] denote the operation a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */ #define I(x, y, z) ((y) ^ ((x) | ~(z))) #define SET(a, b, c, d, k, s, Ti)\ t = a + I(b,c,d) + X[k] + Ti;\ a = ROTATE_LEFT(t, s) + b /* Do the following 16 operations. */ SET(a, b, c, d, 0, 6, T49); SET(d, a, b, c, 7, 10, T50); SET(c, d, a, b, 14, 15, T51); SET(b, c, d, a, 5, 21, T52); SET(a, b, c, d, 12, 6, T53); SET(d, a, b, c, 3, 10, T54); SET(c, d, a, b, 10, 15, T55); SET(b, c, d, a, 1, 21, T56); SET(a, b, c, d, 8, 6, T57); SET(d, a, b, c, 15, 10, T58); SET(c, d, a, b, 6, 15, T59); SET(b, c, d, a, 13, 21, T60); SET(a, b, c, d, 4, 6, T61); SET(d, a, b, c, 11, 10, T62); SET(c, d, a, b, 2, 15, T63); SET(b, c, d, a, 9, 21, T64); #undef SET /* Then perform the following additions. (That is increment each of the four registers by the value it had before this block was started.) */ pms->abcd[0] += a; pms->abcd[1] += b; pms->abcd[2] += c; pms->abcd[3] += d; } void _cupsMD5Init(_cups_md5_state_t *pms) { pms->count[0] = pms->count[1] = 0; pms->abcd[0] = 0x67452301; pms->abcd[1] = 0xefcdab89; pms->abcd[2] = 0x98badcfe; pms->abcd[3] = 0x10325476; } void _cupsMD5Append(_cups_md5_state_t *pms, const unsigned char *data, int nbytes) { const unsigned char *p = data; int left = nbytes; int offset = (pms->count[0] >> 3) & 63; unsigned int nbits = (unsigned int)(nbytes << 3); if (nbytes <= 0) return; /* Update the message length. */ pms->count[1] += (unsigned)(nbytes >> 29); pms->count[0] += nbits; if (pms->count[0] < nbits) pms->count[1]++; /* Process an initial partial block. */ if (offset) { int copy = (offset + nbytes > 64 ? 64 - offset : nbytes); memcpy(pms->buf + offset, p, copy); if (offset + copy < 64) return; p += copy; left -= copy; _cups_md5_process(pms, pms->buf); } /* Process full blocks. */ for (; left >= 64; p += 64, left -= 64) _cups_md5_process(pms, p); /* Process a final partial block. */ if (left) memcpy(pms->buf, p, left); } void _cupsMD5Finish(_cups_md5_state_t *pms, unsigned char digest[16]) { static const unsigned char pad[64] = { 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; unsigned char data[8]; int i; /* Save the length before padding. */ for (i = 0; i < 8; ++i) data[i] = (unsigned char)(pms->count[i >> 2] >> ((i & 3) << 3)); /* Pad to 56 bytes mod 64. */ _cupsMD5Append(pms, pad, ((55 - (pms->count[0] >> 3)) & 63) + 1); /* Append the length. */ _cupsMD5Append(pms, data, 8); for (i = 0; i < 16; ++i) digest[i] = (unsigned char)(pms->abcd[i >> 2] >> ((i & 3) << 3)); } htmldoc-1.9.7/htmldoc/mmd.c000066400000000000000000001575241354715574200155700ustar00rootroot00000000000000/* * Implementation of miniature markdown library. * * https://github.com/michaelrsweet/mmd * * Copyright © 2017-2019 by Michael R Sweet. * * Licensed under Apache License v2.0. See the file "LICENSE" for more * information. */ /* * Define DEBUG to get debug printf messages to stderr. */ #define DEBUG 0 #if DEBUG > 0 # define DEBUG_printf(...) fprintf(stderr, __VA_ARGS__) # define DEBUG_puts(s) fputs(s, stderr); #else # define DEBUG_printf(...) # define DEBUG_puts(s) #endif /* DEBUG > 0 */ #if DEBUG > 1 # define DEBUG2_printf(...) fprintf(stderr, __VA_ARGS__) # define DEBUG2_puts(s) fputs(s, stderr); #else # define DEBUG2_printf(...) # define DEBUG2_puts(s) #endif /* DEBUG > 1 */ /* * Beginning with VC2005, Microsoft breaks ISO C and POSIX conformance * by deprecating a number of functions in the name of security, even * when many of the affected functions are otherwise completely secure. * The _CRT_SECURE_NO_DEPRECATE definition ensures that we won't get * warnings from their use... * * Then Microsoft decided that they should ignore this in VC2008 and use * yet another define (_CRT_SECURE_NO_WARNINGS) instead... */ #define _CRT_SECURE_NO_DEPRECATE #define _CRT_SECURE_NO_WARNINGS /* * Include necessary headers... */ #include "mmd.h" #include #include #include /* * Microsoft renames the POSIX functions to _name, and introduces a broken * compatibility layer using the original names. As a result, random crashes * can occur when, for example, strdup() allocates memory from a different heap * than used by malloc() and free(). * * To avoid moronic problems like this, we #define the POSIX function names to * the corresponding non-standard Microsoft names. */ #ifdef _WIN32 # define snprintf _snprintf # define strcasecmp _stricmp # define strdup _strdup #endif /* _WIN32 */ /* * Structures... */ struct _mmd_s { mmd_type_t type; /* Node type */ int whitespace; /* Leading whitespace? */ char *text, /* Text */ *url, /* Reference URL (image/link/etc.) */ *extra; /* Title, language name, etc. */ mmd_t *parent, /* Parent node */ *first_child, /* First child node */ *last_child, /* Last child node */ *prev_sibling, /* Previous sibling node */ *next_sibling; /* Next sibling node */ }; typedef struct _mmd_filebuf_s /**** Buffered file ****/ { FILE *fp; /* File pointer */ char buffer[65536], /* Buffer */ *bufptr, /* Pointer into buffer */ *bufend; /* End of buffer */ } _mmd_filebuf_t; typedef struct _mmd_ref_s /**** Reference link ****/ { char *name, /* Name of reference */ *url, /* Reference URL */ *title; /* Title, if any */ size_t num_pending; /* Number of pending nodes */ mmd_t **pending; /* Pending nodes */ } _mmd_ref_t; typedef struct _mmd_doc_s /**** Markdown document ****/ { mmd_t *root; /* Root node */ size_t num_references; /* Number of references */ _mmd_ref_t *references; /* References */ } _mmd_doc_t; typedef struct _mmd_stack_s /**** Markdown block stack ****/ { mmd_t *parent; /* Parent node */ int indent; /* Indentation */ char fence; /* Code fence character */ size_t fencelen; /* Length of code fence */ } _mmd_stack_t; /* * Local globals... */ static mmd_option_t mmd_options = MMD_OPTION_ALL; /* Markdown extensions to support */ /* * Local functions... */ static mmd_t *mmd_add(mmd_t *parent, mmd_type_t type, int whitespace, char *text, char *url); static void mmd_free(mmd_t *node); static int mmd_has_continuation(const char *line, _mmd_filebuf_t *file, int indent); static size_t mmd_is_chars(const char *lineptr, const char *chars, size_t minchars); static size_t mmd_is_codefence(char *lineptr, char fence, size_t fencelen, char **language); static int mmd_is_table(_mmd_filebuf_t *file, int indent); static void mmd_parse_inline(_mmd_doc_t *doc, mmd_t *parent, char *lineptr); static char *mmd_parse_link(_mmd_doc_t *doc, char *lineptr, char **text, char **url, char **title, char **refname); static void mmd_read_buffer(_mmd_filebuf_t *file); static char *mmd_read_line(_mmd_filebuf_t *file, char *line, size_t linesize); static void mmd_ref_add(_mmd_doc_t *doc, mmd_t *node, const char *name, const char *url, const char *title); static _mmd_ref_t *mmd_ref_find(_mmd_doc_t *doc, const char *name); static void mmd_remove(mmd_t *node); #if DEBUG static const char *mmd_type_string(mmd_type_t type); #endif /* DEBUG */ /* * 'mmdCopyAllText()' - Make a copy of all the text under a given node. * * The returned string must be freed using free(). */ char * /* O - Copied string */ mmdCopyAllText(mmd_t *node) /* I - Parent node */ { char *all = NULL, /* String buffer */ *allptr = NULL, /* Pointer into string buffer */ *temp; /* Temporary pointer */ size_t allsize = 0, /* Size of "all" buffer */ textlen; /* Length of "text" string */ mmd_t *current, /* Current node */ *next; /* Next node */ current = mmdGetFirstChild(node); while (current != node) { if (current->text) { /* * Append this node's text to the string... */ textlen = strlen(current->text); if (allsize == 0) { allsize = textlen + (size_t)current->whitespace + 1; all = malloc(allsize); allptr = all; if (!all) return (NULL); } else { allsize += textlen + (size_t)current->whitespace; temp = realloc(all, allsize); if (!temp) { free(all); return (NULL); } allptr = temp + (allptr - all); all = temp; } if (current->whitespace) *allptr++ = ' '; memcpy(allptr, current->text, textlen); allptr += textlen; } /* * Find the next logical node... */ if ((next = mmdGetNextSibling(current)) == NULL) { next = mmdGetParent(current); while (next && next != node && mmdGetNextSibling(next) == NULL) next = mmdGetParent(next); if (next != node) next = mmdGetNextSibling(next); } current = next; } if (allptr) *allptr = '\0'; return (all); } /* * 'mmdFree()' - Free a markdown tree. */ void mmdFree(mmd_t *node) /* I - First node */ { mmd_t *current, /* Current node */ *next; /* Next node */ mmd_remove(node); for (current = node->first_child; current; current = next) { /* * Get the next node... */ if ((next = current->first_child) != NULL) { /* * Free parent nodes after child nodes have been freed... */ current->first_child = NULL; continue; } if ((next = current->next_sibling) == NULL) { /* * Next node is the parent, which we'll free as needed... */ if ((next = current->parent) == node) next = NULL; } /* * Free child... */ mmd_free(current); } /* * Then free the memory used by the parent node... */ mmd_free(node); } /* * 'mmdGetExtra()' - Get extra text (title, language, etc.) associated with a * node. */ const char * /* O - Extra text or NULL if none */ mmdGetExtra(mmd_t *node) /* I - Node */ { return (node ? node->extra : NULL); } /* * 'mmdGetFirstChild()' - Return the first child of a node, if any. */ mmd_t * /* O - First child or @code NULL@ if none */ mmdGetFirstChild(mmd_t *node) /* I - Node */ { return (node ? node->first_child : NULL); } /* * 'mmdGetLastChild()' - Return the last child of a node, if any. */ mmd_t * /* O - Last child or @code NULL@ if none */ mmdGetLastChild(mmd_t *node) /* I - Node */ { return (node ? node->last_child : NULL); } /* * 'mmdGetMetadata()' - Return the metadata for the given keyword. */ const char * /* O - Value or @code NULL@ if none */ mmdGetMetadata(mmd_t *doc, /* I - Document */ const char *keyword) /* I - Keyword */ { mmd_t *metadata, /* Metadata node */ *current; /* Current node */ char prefix[256]; /* Prefix string */ size_t prefix_len; /* Length of prefix string */ const char *value; /* Pointer to value */ if (!doc || (metadata = doc->first_child) == NULL || metadata->type != MMD_TYPE_METADATA) return (NULL); snprintf(prefix, sizeof(prefix), "%s:", keyword); prefix_len = strlen(prefix); for (current = metadata->first_child; current; current = current->next_sibling) { if (strncmp(current->text, prefix, prefix_len)) continue; value = current->text + prefix_len; while (isspace(*value & 255)) value ++; return (value); } return (NULL); } /* * 'mmdGetNextSibling()' - Return the next sibling of a node, if any. */ mmd_t * /* O - Next sibling or @code NULL@ if none */ mmdGetNextSibling(mmd_t *node) /* I - Node */ { return (node ? node->next_sibling : NULL); } /* * 'mmdGetOptions()' - Get the enabled markdown processing options/extensions. */ mmd_option_t /* O - Enabled options */ mmdGetOptions(void) { return (mmd_options); } /* * 'mmdGetParent()' - Return the parent of a node, if any. */ mmd_t * /* O - Parent node or @code NULL@ if none */ mmdGetParent(mmd_t *node) /* I - Node */ { return (node ? node->parent : NULL); } /* * 'mmdGetPrevSibling()' - Return the previous sibling of a node, if any. */ mmd_t * /* O - Previous sibling or @code NULL@ if none */ mmdGetPrevSibling(mmd_t *node) /* I - Node */ { return (node ? node->prev_sibling : NULL); } /* * 'mmdGetText()' - Return the text associated with a node, if any. */ const char * /* O - Text or @code NULL@ if none */ mmdGetText(mmd_t *node) /* I - Node */ { return (node ? node->text : NULL); } /* * 'mmdGetType()' - Return the type of a node, if any. */ mmd_type_t /* O - Type or @code MMD_TYPE_NONE@ if none */ mmdGetType(mmd_t *node) /* I - Node */ { return (node ? node->type : MMD_TYPE_NONE); } /* * 'mmdGetURL()' - Return the URL associated with a node, if any. */ const char * /* O - URL or @code NULL@ if none */ mmdGetURL(mmd_t *node) /* I - Node */ { return (node ? node->url : NULL); } /* * 'mmdGetWhitespace()' - Return whether whitespace preceded a node. */ int /* O - 1 for whitespace, 0 for none */ mmdGetWhitespace(mmd_t *node) /* I - Node */ { return (node ? node->whitespace : 0); } /* * 'mmdIsBlock()' - Return whether the node is a block. */ int /* O - 1 for block nodes, 0 otherwise */ mmdIsBlock(mmd_t *node) /* I - Node */ { return (node ? node->type < MMD_TYPE_NORMAL_TEXT : 0); } /* * 'mmdLoad()' - Load a markdown file into nodes. */ mmd_t * /* O - First node in markdown */ mmdLoad(const char *filename) /* I - File to load */ { FILE *fp; /* File */ mmd_t *doc; /* Document */ /* * Open the file and create an empty document... */ if ((fp = fopen(filename, "r")) == NULL) return (NULL); doc = mmdLoadFile(fp); fclose(fp); return (doc); } /* * 'mmdLoadFile()' - Load a markdown file into nodes from a stdio file. */ mmd_t * /* O - First node in markdown */ mmdLoadFile(FILE *fp) /* I - File to load */ { size_t i; /* Looping var */ _mmd_doc_t doc; /* Document */ _mmd_ref_t *reference; /* Current reference */ mmd_t *block = NULL; /* Current block */ mmd_type_t type; /* Type for line */ _mmd_filebuf_t file; /* File buffer */ char line[8192], /* Read line */ *linestart, /* Start of line */ *lineptr, /* Pointer into line */ *lineend, /* End of line */ *temp; /* Temporary pointer */ int newindent; /* New indentation */ int blank_code = 0; /* Saved indented blank code line */ mmd_type_t columns[256]; /* Alignment of table columns */ int num_columns = 0, /* Number of columns in table */ rows = 0; /* Number of rows in table */ _mmd_stack_t stack[32], /* Block stack */ *stackptr = stack; /* Pointer to top of stack */ /* * Create an empty document... */ DEBUG_printf("mmdLoadFile: mmd_options=%d%s%s\n", mmd_options, (mmd_options & MMD_OPTION_METADATA) ? " METADATA" : "", (mmd_options & MMD_OPTION_TABLES) ? " TABLES" : ""); memset(&doc, 0, sizeof(doc)); doc.root = mmd_add(NULL, MMD_TYPE_DOCUMENT, 0, NULL, NULL); if (!doc.root) { fclose(fp); return (NULL); } /* * Initialize the block stack... */ memset(stack, 0, sizeof(stack)); stackptr->parent = doc.root; /* * Read lines until end-of-file... */ memset(&file, 0, sizeof(file)); file.fp = fp; while ((lineptr = mmd_read_line(&file, line, sizeof(line))) != NULL) { DEBUG_printf("%03d %-12s %s", stackptr->indent, mmd_type_string(stackptr->parent->type) + 9, lineptr); #if DEBUG if (stackptr->parent->type == MMD_TYPE_CODE_BLOCK) DEBUG2_printf(" blank_code=%d\n", blank_code); #endif /* DEBUG */ linestart = lineptr; while (isspace(*lineptr & 255)) lineptr ++; DEBUG2_printf(" line indent=%d\n", (int)(lineptr - line)); DEBUG2_printf(" stackptr=%d\n", (int)(stackptr - stack)); if (*lineptr == '>' && (lineptr - linestart) < 4) { /* * Block quote. See if there is an existing blockquote... */ DEBUG_printf(" BLOCKQUOTE (stackptr=%ld)\n", stackptr - stack); if (stackptr == stack || stack[1].parent->type != MMD_TYPE_BLOCK_QUOTE) { block = NULL; stackptr = stack + 1; stackptr->parent = mmd_add(doc.root, MMD_TYPE_BLOCK_QUOTE, 0, NULL, NULL); stackptr->indent = 2; stackptr->fence = '\0'; } /* * Skip whitespace after the ">"... */ lineptr ++; if (isspace(*lineptr & 255)) lineptr ++; linestart = lineptr; while (isspace(*lineptr & 255)) lineptr ++; } else if (*lineptr != '>' && stackptr > stack && stack[1].parent->type == MMD_TYPE_BLOCK_QUOTE && (!block || *lineptr == '\n' || mmd_is_chars(lineptr, "- \t", 3) || mmd_is_chars(lineptr, "_ \t", 3) || mmd_is_chars(lineptr, "* \t", 3))) { /* * Not a lazy continuation so terminate this block quote... */ DEBUG_puts(" Terminating BLOCKQUOTE\n"); block = NULL; stackptr = stack; } /* * Now handle all other markup not related to block quotes... */ DEBUG2_printf(" stackptr=%d (%s), block=%p (%s)\n", (int)(stackptr - stack), mmd_type_string(stackptr->parent->type) + 9, block, block ? mmd_type_string(block->type) + 9 : ""); DEBUG2_printf(" strchr(lineptr, '|')=%p, mmd_is_table(&file, stackptr->indent)=%d\n", strchr(lineptr, '|'), mmd_is_table(&file, stackptr->indent)); DEBUG2_printf(" linestart=%d, lineptr=%d\n", (int)(linestart - line), (int)(lineptr - line)); DEBUG2_printf(" mmd_is_chars(lineptr, \"-\", 1)=%d\n", (int)mmd_is_chars(lineptr, "-", 1)); DEBUG2_printf(" mmd_is_chars(lineptr, \"=\", 1)=%d\n", (int)mmd_is_chars(lineptr, "=", 1)); if ((lineptr - line - stackptr->indent) < 4 && ((stackptr->parent->type != MMD_TYPE_CODE_BLOCK && !stackptr->fence && mmd_is_codefence(lineptr, '\0', 0, NULL)) || (stackptr->fence && mmd_is_codefence(lineptr, stackptr->fence, stackptr->fencelen, NULL)))) { /* * Code fence... */ DEBUG2_printf("stackptr->indent=%d, fence='%c', fencelen=%d\n", stackptr->indent, stackptr->fence, (int)stackptr->fencelen); if (stackptr->parent->type == MMD_TYPE_CODE_BLOCK) { DEBUG2_puts("Ending code block...\n"); stackptr --; } else if (stackptr < (stack + sizeof(stack) / sizeof(stack[0]) - 1)) { char *language; /* Language name, if any */ DEBUG2_printf("Starting code block with fence '%c'.\n", *lineptr); block = NULL; stackptr[1].parent = mmd_add(stackptr->parent, MMD_TYPE_CODE_BLOCK, 0, NULL, NULL); stackptr[1].indent = lineptr - line; stackptr[1].fence = *lineptr; stackptr[1].fencelen = mmd_is_codefence(lineptr, '\0', 0, &language); stackptr ++; DEBUG2_printf("Code language=\"%s\"\n", language); if (language) stackptr->parent->extra = strdup(language); blank_code = 0; } continue; } else if (stackptr->parent->type == MMD_TYPE_CODE_BLOCK && (lineptr - line) >= stackptr->indent) { if (line[stackptr->indent] == '\n') { blank_code ++; } else { while (blank_code > 0) { mmd_add(stackptr->parent, MMD_TYPE_CODE_TEXT, 0, "\n", NULL); blank_code --; } mmd_add(stackptr->parent, MMD_TYPE_CODE_TEXT, 0, line + stackptr->indent, NULL); } continue; } else if (stackptr->parent->type == MMD_TYPE_CODE_BLOCK && stackptr->fence) { DEBUG2_printf(" fence='%c'\n", stackptr->fence); if (!*lineptr) { blank_code ++; } else { while (blank_code > 0) { mmd_add(stackptr->parent, MMD_TYPE_CODE_TEXT, 0, "\n", NULL); blank_code --; } mmd_add(stackptr->parent, MMD_TYPE_CODE_TEXT, 0, lineptr, NULL); } continue; } else if (!strncmp(lineptr, "---", 3) && doc.root->first_child == NULL && (mmd_options & MMD_OPTION_METADATA)) { /* * Document metadata... */ block = mmd_add(doc.root, MMD_TYPE_METADATA, 0, NULL, NULL); while ((lineptr = mmd_read_line(&file, line, sizeof(line))) != NULL) { while (isspace(*lineptr & 255)) lineptr ++; if (!strncmp(lineptr, "---", 3) || !strncmp(lineptr, "...", 3)) break; lineend = lineptr + strlen(lineptr) - 1; if (lineend > lineptr && *lineend == '\n') *lineend = '\0'; mmd_add(block, MMD_TYPE_METADATA_TEXT, 0, lineptr, NULL); } continue; } else if (block && block->type == MMD_TYPE_PARAGRAPH && (lineptr - linestart) < 4 && (lineptr - line) >= stackptr->indent && (mmd_is_chars(lineptr, "-", 1) || mmd_is_chars(lineptr, "=", 1))) { int ch = *lineptr; DEBUG_puts(" SETEXT HEADING\n"); lineptr += 3; while (*lineptr == ch) lineptr ++; while (isspace(*lineptr & 255)) lineptr ++; if (!*lineptr) { if (ch == '=') block->type = MMD_TYPE_HEADING_1; else block->type = MMD_TYPE_HEADING_2; block = NULL; continue; } type = MMD_TYPE_PARAGRAPH; } else if ((lineptr - linestart) < 4 && (mmd_is_chars(lineptr, "- \t", 3) || mmd_is_chars(lineptr, "_ \t", 3) || mmd_is_chars(lineptr, "* \t", 3))) { DEBUG_puts(" THEMATIC BREAK\n"); if (line[0] == '>') stackptr = stack + 1; else stackptr = stack; mmd_add(stackptr->parent, MMD_TYPE_THEMATIC_BREAK, 0, NULL, NULL); type = MMD_TYPE_PARAGRAPH; block = NULL; continue; } else if ((*lineptr == '-' || *lineptr == '+' || *lineptr == '*') && (lineptr[1] == '\t' || lineptr[1] == ' ')) { /* * Bulleted list... */ DEBUG_puts(" UNORDERED LIST\n"); lineptr += 2; linestart = lineptr; newindent = linestart - line; while (isspace(*lineptr & 255)) lineptr ++; while (stackptr > stack && stackptr->indent > newindent) stackptr --; if (stackptr->parent->type == MMD_TYPE_LIST_ITEM && stackptr->indent == newindent) stackptr --; if (stackptr->parent->type == MMD_TYPE_ORDERED_LIST && stackptr->indent == newindent) stackptr --; if (stackptr->parent->type == MMD_TYPE_BLOCK_QUOTE && line[0] != '>') stackptr --; if (stackptr->parent->type != MMD_TYPE_UNORDERED_LIST && stackptr < (stack + sizeof(stack) / sizeof(stack[0]) - 1)) { stackptr[1].parent = mmd_add(stackptr->parent, MMD_TYPE_UNORDERED_LIST, 0, NULL, NULL); stackptr[1].indent = linestart - line; stackptr[1].fence = '\0'; stackptr ++; } if (stackptr < (stack + sizeof(stack) / sizeof(stack[0]) - 1)) { stackptr[1].parent = mmd_add(stackptr->parent, MMD_TYPE_LIST_ITEM, 0, NULL, NULL); stackptr[1].indent = linestart - line; stackptr[1].fence = '\0'; stackptr ++; } type = MMD_TYPE_PARAGRAPH; block = NULL; if (mmd_is_chars(lineptr, "- \t", 3) || mmd_is_chars(lineptr, "_ \t", 3) || mmd_is_chars(lineptr, "* \t", 3)) { mmd_add(stackptr->parent, MMD_TYPE_THEMATIC_BREAK, 0, NULL, NULL); continue; } } else if (isdigit(*lineptr & 255)) { /* * Ordered list? */ DEBUG_puts(" ORDERED LIST?\n"); temp = lineptr + 1; while (isdigit(*temp & 255)) temp ++; if ((*temp == '.' || *temp == ')') && (temp[1] == '\t' || temp[1] == ' ')) { /* * Yes, ordered list. */ lineptr = temp + 2; linestart = lineptr; newindent = linestart - line; while (isspace(*lineptr & 255)) lineptr ++; while (stackptr > stack && stackptr->indent > newindent) stackptr --; if (stackptr->parent->type == MMD_TYPE_LIST_ITEM && stackptr->indent == newindent) stackptr --; if (stackptr->parent->type == MMD_TYPE_UNORDERED_LIST && stackptr->indent == newindent) stackptr --; if (stackptr->parent->type == MMD_TYPE_BLOCK_QUOTE && line[0] != '>') stackptr --; if (stackptr->parent->type != MMD_TYPE_ORDERED_LIST && stackptr < (stack + sizeof(stack) / sizeof(stack[0]) - 1)) { stackptr[1].parent = mmd_add(stackptr->parent, MMD_TYPE_ORDERED_LIST, 0, NULL, NULL); stackptr[1].indent = linestart - line; stackptr[1].fence = '\0'; stackptr ++; } if (stackptr < (stack + sizeof(stack) / sizeof(stack[0]) - 1)) { stackptr[1].parent = mmd_add(stackptr->parent, MMD_TYPE_LIST_ITEM, 0, NULL, NULL); stackptr[1].indent = linestart - line; stackptr[1].fence = '\0'; stackptr ++; } type = MMD_TYPE_PARAGRAPH; block = NULL; } else { /* * No, just a regular paragraph... */ type = block ? block->type : MMD_TYPE_PARAGRAPH; } } else if (*lineptr == '#' && (lineptr - linestart) < 4) { /* * Heading, count the number of '#' for the heading level... */ DEBUG_puts(" HEADING?\n"); newindent = lineptr - line; temp = lineptr + 1; while (*temp == '#') temp ++; if ((temp - lineptr) <= 6 && isspace(*temp & 255)) { /* * Heading 1-6... */ type = MMD_TYPE_HEADING_1 + (temp - lineptr - 1); block = NULL; /* * Skip whitespace after "#"... */ lineptr = temp; while (isspace(*lineptr & 255)) lineptr ++; linestart = lineptr; /* * Strip trailing "#" characters and whitespace... */ temp = lineptr + strlen(lineptr) - 1; while (temp > lineptr && isspace(*temp & 255)) *temp-- = '\0'; while (temp > lineptr && *temp == '#') temp --; if (isspace(*temp & 255)) { while (temp > lineptr && isspace(*temp & 255)) *temp-- = '\0'; } else if (temp == lineptr) *temp = '\0'; while (stackptr > stack && stackptr->indent > newindent) stackptr --; block = mmd_add(stackptr->parent, type, 0, NULL, NULL); } else { /* * More than 6 #'s, just treat as a paragraph... */ type = MMD_TYPE_PARAGRAPH; } } else if (block && block->type >= MMD_TYPE_HEADING_1 && block->type <= MMD_TYPE_HEADING_6) { DEBUG_puts(" PARAGRAPH\n"); type = MMD_TYPE_PARAGRAPH; block = NULL; } else if (!block) { type = MMD_TYPE_PARAGRAPH; if (lineptr == line && stackptr->parent->type != MMD_TYPE_TABLE) stackptr = stack; } else type = block->type; if (!*lineptr) { if (stackptr->parent->type == MMD_TYPE_CODE_BLOCK) blank_code ++; else if (stackptr->parent->type == MMD_TYPE_BLOCK_QUOTE && line[0] != '>') stackptr --; block = NULL; continue; } else if (!strcmp(lineptr, "+")) { if (block) { if (block->type == MMD_TYPE_LIST_ITEM) block = mmd_add(block, MMD_TYPE_PARAGRAPH, 0, NULL, NULL); else if (block->parent->type == MMD_TYPE_LIST_ITEM) block = mmd_add(block->parent, MMD_TYPE_PARAGRAPH, 0, NULL, NULL); else block = NULL; } continue; } else if ((mmd_options & MMD_OPTION_TABLES) && strchr(lineptr, '|') && (stackptr->parent->type == MMD_TYPE_TABLE || mmd_is_table(&file, stackptr->indent))) { /* * Table... */ int col; /* Current column */ char *start, /* Start of column/cell */ *end; /* End of column/cell */ mmd_t *row = NULL, /* Current row */ *cell; /* Current cell */ DEBUG2_printf("TABLE stackptr->parent=%p (%d), rows=%d\n", stackptr->parent, stackptr->parent->type, rows); if (stackptr->parent->type != MMD_TYPE_TABLE && stackptr < (stack + sizeof(stack) / sizeof(stack[0]) - 1)) { DEBUG2_printf("ADDING NEW TABLE to %p (%s)\n", stackptr->parent, mmd_type_string(stackptr->parent->type)); stackptr[1].parent = mmd_add(stackptr->parent, MMD_TYPE_TABLE, 0, NULL, NULL); stackptr[1].indent = stackptr->indent; stackptr[1].fence = '\0'; stackptr ++; block = mmd_add(stackptr->parent, MMD_TYPE_TABLE_HEADER, 0, NULL, NULL); for (col = 0; col < (int)(sizeof(columns) / sizeof(columns[0])); col ++) columns[col] = MMD_TYPE_TABLE_BODY_CELL_LEFT; num_columns = 0; rows = -1; } else if (rows > 0) { if (rows == 1) block = mmd_add(stackptr->parent, MMD_TYPE_TABLE_BODY, 0, NULL, NULL); } else block = NULL; if (block) row = mmd_add(block, MMD_TYPE_TABLE_ROW, 0, NULL, NULL); if (*lineptr == '|') lineptr ++; /* Skip leading pipe */ if ((end = lineptr + strlen(lineptr) - 1) > lineptr) { while ((*end == '\n' || *end == 'r') && end > lineptr) end --; if (end > lineptr && *end == '|') *end = '\0'; /* Truncate trailing pipe */ } for (col = 0; lineptr && *lineptr && col < (int)(sizeof(columns) / sizeof(columns[0])); col ++) { /* * Get the bounds of the stackptr->parent cell... */ start = lineptr; if ((lineptr = strchr(lineptr + 1, '|')) != NULL) *lineptr++ = '\0'; if (block) { /* * Add a cell to this row... */ if (block->type == MMD_TYPE_TABLE_HEADER) cell = mmd_add(row, MMD_TYPE_TABLE_HEADER_CELL, 0, NULL, NULL); else cell = mmd_add(row, columns[col], 0, NULL, NULL); mmd_parse_inline(&doc, cell, start); } else { /* * Process separator row for alignment... */ while (isspace(*start & 255)) start ++; for (end = start + strlen(start) - 1; end > start && isspace(*end & 255); end --); if (*start == ':' && *end == ':') columns[col] = MMD_TYPE_TABLE_BODY_CELL_CENTER; else if (*end == ':') columns[col] = MMD_TYPE_TABLE_BODY_CELL_RIGHT; DEBUG2_printf("COLUMN %d SEPARATOR=\"%s\", TYPE=%d\n", col, start, columns[col]); } } /* * Make sure the table is balanced... */ if (col > num_columns) { num_columns = col; } else if (block && block->type != MMD_TYPE_TABLE_HEADER) { while (col < num_columns) { mmd_add(row, columns[col], 0, NULL, NULL); col ++; } } rows ++; continue; } else if (stackptr->parent->type == MMD_TYPE_TABLE) { DEBUG2_puts("END TABLE\n"); stackptr --; block = NULL; } if (stackptr->parent->type != MMD_TYPE_CODE_BLOCK && (!block || block->type == MMD_TYPE_CODE_BLOCK) && (lineptr - linestart) >= (stackptr->indent + 4)) { /* * Indented code block. */ if (stackptr->parent->type != MMD_TYPE_CODE_BLOCK && stackptr < (stack + sizeof(stack) / sizeof(stack[0]) - 1)) { stackptr[1].parent = mmd_add(stackptr->parent, MMD_TYPE_CODE_BLOCK, 0, NULL, NULL); stackptr[1].indent = stackptr->indent + 4; stackptr[1].fence = '\0'; stackptr ++; blank_code = 0; } while (blank_code > 0) { mmd_add(stackptr->parent, MMD_TYPE_CODE_TEXT, 0, "\n", NULL); blank_code --; } mmd_add(stackptr->parent, MMD_TYPE_CODE_TEXT, 0, line + stackptr->indent, NULL); continue; } if (!block || block->type != type) { if (stackptr->parent->type == MMD_TYPE_CODE_BLOCK) stackptr --; block = mmd_add(stackptr->parent, type, 0, NULL, NULL); } /* * Read continuation lines before parsing this... */ while (mmd_has_continuation(line, &file, stackptr->indent)) { char *ptr = line + strlen(line); if (!mmd_read_line(&file, ptr, sizeof(line) - (size_t)(ptr - line))) break; else if (line[0] == '>' && *ptr == '>') memmove(ptr, ptr + 1, strlen(ptr)); } mmd_parse_inline(&doc, block, lineptr); if (block->type == MMD_TYPE_PARAGRAPH && !block->first_child) { mmd_remove(block); mmd_free(block); block = NULL; } } /* * Free any references... */ for (i = doc.num_references, reference = doc.references; i > 0; i --, reference ++) { if (reference->pending) { char text[8192]; /* Reference text */ size_t j; /* Looping var */ DEBUG2_printf("Clearing links for '%s'.\n", reference->name); snprintf(text, sizeof(text), "[%s]", reference->name); for (j = 0; j < reference->num_pending; j ++) { free(reference->pending[j]->text); reference->pending[j]->text = strdup(text); reference->pending[j]->type = MMD_TYPE_NORMAL_TEXT; } free(reference->pending); } free(reference->name); free(reference->url); } free(doc.references); /* * Return the root node... */ return (doc.root); } /* * 'mmdSetOptions()' - Set (enable/disable) support for various markdown options. */ void mmdSetOptions(mmd_option_t options) /* I - Options */ { mmd_options = options; } /* * 'mmd_add()' - Add a new markdown node. */ static mmd_t * /* O - New node */ mmd_add(mmd_t *parent, /* I - Parent node */ mmd_type_t type, /* I - Node type */ int whitespace, /* I - 1 if whitespace precedes this node */ char *text, /* I - Text, if any */ char *url) /* I - URL, if any */ { mmd_t *temp; /* New node */ DEBUG2_printf("Adding %s to %p(%s), whitespace=%d, text=\"%s\", url=\"%s\"\n", mmd_type_string(type), parent, parent ? mmd_type_string(parent->type) : "", whitespace, text ? text : "(null)", url ? url : "(null)"); if ((temp = calloc(1, sizeof(mmd_t))) != NULL) { if (parent) { /* * Add node to the parent... */ temp->parent = parent; if (parent->last_child) { parent->last_child->next_sibling = temp; temp->prev_sibling = parent->last_child; parent->last_child = temp; } else { parent->first_child = parent->last_child = temp; } } /* * Copy the node values... */ temp->type = type; temp->whitespace = whitespace; if (text) temp->text = strdup(text); if (url) temp->url = strdup(url); } return (temp); } /* * 'mmd_free()' - Free memory used by a node. */ static void mmd_free(mmd_t *node) /* I - Node */ { free(node->text); free(node->url); free(node->extra); free(node); } /* * 'mmd_has_continuation()' - Determine whether the next line is a continuation * of the current one. */ static int /* O - 1 if the next line continues, 0 otherwise */ mmd_has_continuation( const char *line, /* I - Current line */ _mmd_filebuf_t *file, /* I - File buffer */ int indent) /* I - Indentation for current block */ { const char *lineptr = line; /* Pointer into current line */ const char *fileptr = file->bufptr;/* Pointer into next line */ if (*fileptr == '\n' || *fileptr == '\r') return (0); do { while (isspace(*lineptr & 255)) lineptr ++; if (*lineptr == '[' && (lineptr - line - indent) < 4 && (*fileptr == ' ' || *fileptr == '\t')) return (1); while (isspace(*fileptr & 255)) fileptr ++; if (*lineptr == '>' && *fileptr == '>') { lineptr ++; fileptr ++; } else if (*fileptr == '>') return (0); if (*fileptr == '\n' || *fileptr == '\r') return (0); } while (isspace(*lineptr & 255) || isspace(*fileptr & 255)); if (*lineptr == '#') return (0); if (strchr("-+*", *fileptr) && isspace(fileptr[1] & 255)) { /* * Bullet list item... */ return (0); } if (isdigit(*fileptr & 255)) { /* * Ordered list item... */ while (*fileptr && isdigit(*fileptr & 255)) fileptr ++; if (*fileptr == '.' || *fileptr == '(') return (0); } if (mmd_is_codefence((char *)fileptr, '\0', 0, NULL)) return (0); if (mmd_is_chars(fileptr, "- \t", 3) || mmd_is_chars(fileptr, "_ \t", 3) || mmd_is_chars(fileptr, "* \t", 3)) { /* * Thematic break... */ return (0); } if (mmd_is_chars(fileptr, "-", 1) || mmd_is_chars(fileptr, "=", 1)) { /* * Heading... */ return (0); } if (*fileptr == '#') { /* * Possible heading... */ int count = 0; while (*fileptr == '#') { fileptr ++; count ++; } if (count <= 6) return (0); } return ((fileptr - file->bufptr) <= indent); } /* * 'mmd_is_chars()' - Determine whether a line consists solely of whitespace * and the specified character. */ static size_t /* O - 1 if as specified, 0 otherwise */ mmd_is_chars(const char *lineptr, /* I - Current line */ const char *chars, /* I - Non-space character */ size_t minchars) /* I - Minimum number of non-space characters */ { size_t found_ch = 0; /* Did we find the specified characters? */ while (*lineptr == *chars) { found_ch ++; lineptr ++; } if (minchars > 1) { while (*lineptr && strchr(chars, *lineptr)) { if (*lineptr == *chars) found_ch ++; lineptr ++; } } while (*lineptr && isspace(*lineptr & 255) && *lineptr != '\n') lineptr ++; if ((*lineptr && *lineptr != '\n') || found_ch < minchars) return (0); else return (found_ch); } /* * 'mmd_is_codefence()' - Determine whether the line contains a code fence. */ static size_t /* O - Length of fence or 0 otherwise */ mmd_is_codefence(char *lineptr, /* I - Line */ char fence, /* I - Current fence character, if any */ size_t fencelen, /* I - Current fence length */ char **language) /* O - Language name, if any */ { char match = fence; /* Character to match */ size_t len = 0; /* Length of fence chars */ if (language) *language = NULL; if (!match) { if (*lineptr == '~' || *lineptr == '`') match = *lineptr; else return (0); } while (*lineptr == match) { lineptr ++; len ++; } if (len < 3 || (fencelen && len < fencelen)) return (0); if (*lineptr && *lineptr != '\n' && fence) return (0); else if (*lineptr && *lineptr != '\n' && !fence) { if (match == '`' && strchr(lineptr, match)) return (0); while (isspace(*lineptr & 255)) lineptr ++; if (*lineptr && language) { *language = lineptr; while (*lineptr && !isspace(*lineptr & 255)) lineptr ++; *lineptr = '\0'; } } return (len); } /* * 'mmd_is_table()' - Look ahead to see if the next line contains a heading * divider for a table. */ static int /* O - 1 if this is a table, 0 otherwise */ mmd_is_table(_mmd_filebuf_t *file, /* I - File to read from */ int indent) /* I - Indentation of table line */ { const char *ptr; /* Pointer into buffer */ ptr = file->bufptr; while (*ptr) { if (!strchr(" \t>", *ptr)) break; ptr ++; } if ((ptr - file->bufptr - indent) >= 4) return (0); while (*ptr) { if (!strchr(" \t:-|", *ptr)) break; ptr ++; } return (*ptr == '\r' || *ptr == '\n'); } /* * 'mmd_parse_inline()' - Parse inline formatting. */ static void mmd_parse_inline(_mmd_doc_t *doc, /* I - Document */ mmd_t *parent, /* I - Parent node */ char *lineptr) /* I - Pointer into line */ { mmd_t *node; /* New node */ mmd_type_t type; /* Current node type */ int whitespace; /* Whitespace precedes? */ char *text, /* Text fragment in line */ *title, /* Link title */ *url, /* URL in link */ *refname; /* Reference name */ const char *delim = NULL; /* Delimiter */ size_t delimlen = 0; /* Length of delimiter */ whitespace = parent->last_child != NULL; for (text = NULL, type = MMD_TYPE_NORMAL_TEXT; *lineptr; lineptr ++) { DEBUG2_printf("mmd_parse_inline: lineptr=\"%s\", type=%d, text=%p, whitespace=%d\n", lineptr, type, text, whitespace); if (isspace(*lineptr & 255) && type != MMD_TYPE_CODE_TEXT) { if (text) { *lineptr = '\0'; mmd_add(parent, type, whitespace, text, NULL); text = NULL; whitespace = 0; } if (!strncmp(lineptr + 1, " \n", 2) && lineptr[3]) { DEBUG2_printf("mmd_parse_inline: Adding hard break to %p(%d)\n", parent, parent->type); mmd_add(parent, MMD_TYPE_HARD_BREAK, 0, NULL, NULL); lineptr += 2; whitespace = 0; } else { whitespace = 1; } } else if (*lineptr == '!' && lineptr[1] == '[' && type != MMD_TYPE_CODE_TEXT) { /* * Image... */ if (text) { mmd_add(parent, type, whitespace, text, NULL); text = NULL; whitespace = 0; } lineptr = mmd_parse_link(doc, lineptr + 1, &text, &url, NULL, &refname); if (url || refname) { node = mmd_add(parent, MMD_TYPE_IMAGE, whitespace, text, url); if (refname) mmd_ref_add(doc, node, refname, NULL, NULL); } if (!*lineptr) return; text = url = NULL; whitespace = 0; lineptr --; } else if (*lineptr == '[' && type != MMD_TYPE_CODE_TEXT) { /* * Link... */ if (text) { mmd_add(parent, type, whitespace, text, NULL); text = NULL; whitespace = 0; } lineptr = mmd_parse_link(doc, lineptr, &text, &url, &title, &refname); if (text && *text == '`') { char *end = text + strlen(text) - 1; text ++; if (end > text && *end == '`') *end = '\0'; node = mmd_add(parent, MMD_TYPE_CODE_TEXT, whitespace, text, url); } else if (text) { node = mmd_add(parent, MMD_TYPE_LINKED_TEXT, whitespace, text, url); if (title) node->extra = strdup(title); } else node = NULL; DEBUG2_printf("mmd_parse_inline: text=\"%s\", refname=\"%s\", node=%p\n", text, refname, node); if (refname && node) mmd_ref_add(doc, node, refname, NULL, title); if (!*lineptr) return; text = url = NULL; whitespace = 0; lineptr --; } else if (*lineptr == '<' && type != MMD_TYPE_CODE_TEXT && strchr(lineptr + 1, '>')) { /* * Autolink... */ *lineptr++ = '\0'; if (text) { mmd_add(parent, type, whitespace, text, NULL); text = NULL; whitespace = 0; } url = lineptr; lineptr = strchr(lineptr, '>'); *lineptr = '\0'; mmd_add(parent, MMD_TYPE_LINKED_TEXT, whitespace, url, url); text = url = NULL; whitespace = 0; } else if ((*lineptr == '*' || *lineptr == '_') && (!text || ispunct(lineptr[-1] & 255) || type != MMD_TYPE_NORMAL_TEXT) && type != MMD_TYPE_CODE_TEXT) { const char *end; /* End delimiter */ if (type != MMD_TYPE_NORMAL_TEXT || !delim) { if (!strncmp(lineptr, "**", 2)) delim = "**"; else if (!strncmp(lineptr, "__", 2)) delim = "__"; else if (*lineptr == '*') delim = "*"; else delim = "_"; delimlen = strlen(delim); } if (type == MMD_TYPE_NORMAL_TEXT && delim && ((end = strstr(lineptr + delimlen, delim)) == NULL || end == (lineptr + delimlen) || isspace(end[-1] & 255))) { if (!text) text = lineptr; delim = NULL; delimlen = 0; continue; } if (text) { char save = *lineptr; *lineptr = '\0'; mmd_add(parent, type, whitespace, text, NULL); *lineptr = save; text = NULL; whitespace = 0; } if (type == MMD_TYPE_NORMAL_TEXT) { if (!strncmp(lineptr, delim, delimlen) && !isspace(lineptr[delimlen] & 255)) { type = delimlen == 2 ? MMD_TYPE_STRONG_TEXT : MMD_TYPE_EMPHASIZED_TEXT; text = lineptr + delimlen; lineptr += delimlen - 1; } else { text = lineptr; } } else if (!strncmp(lineptr, delim, delimlen)) { lineptr += delimlen - 1; type = MMD_TYPE_NORMAL_TEXT; delim = NULL; delimlen = 0; } } else if (lineptr[0] == '~' && lineptr[1] == '~' && type != MMD_TYPE_CODE_TEXT) { if (text) { *lineptr = '\0'; mmd_add(parent, type, whitespace, text, NULL); *lineptr = '~'; text = NULL; whitespace = 0; } if (!isspace(lineptr[2] & 255) && type == MMD_TYPE_NORMAL_TEXT) { type = MMD_TYPE_STRUCK_TEXT; text = lineptr + 2; } else { lineptr ++; type = MMD_TYPE_NORMAL_TEXT; } } else if (*lineptr == '`') { if (type != MMD_TYPE_NORMAL_TEXT || !delim) { if (lineptr[1] == '`') { if (lineptr[2] == '`') { delim = "```"; delimlen = 3; } else { delim = "``"; delimlen = 2; } } else { delim = "`"; delimlen = 1; } } if (type != MMD_TYPE_CODE_TEXT && delim && !strstr(lineptr + delimlen, delim)) { if (!text) text = lineptr; delim = NULL; delimlen = 0; continue; } if (text) { DEBUG2_printf("mmd_parse_inline: text=\"%s\"\n", text); if (!strncmp(lineptr, delim, delimlen)) { char *textptr = lineptr; while (textptr > text && isspace(textptr[-1] & 255)) textptr --; *textptr = '\0'; } if (type == MMD_TYPE_CODE_TEXT) { if (whitespace && !*text) { mmd_add(parent, type, 0, " ", NULL); whitespace = 0; } } mmd_add(parent, type, whitespace, text, NULL); text = NULL; whitespace = 0; } if (type == MMD_TYPE_CODE_TEXT) { DEBUG2_puts("mmd_parse_inline: Reverting to normal text.\n"); type = MMD_TYPE_NORMAL_TEXT; lineptr += delimlen - 1; delim = NULL; delimlen = 0; } else { type = MMD_TYPE_CODE_TEXT; lineptr += delimlen - 1; if (isspace(lineptr[1] & 255)) { whitespace = 1; while (isspace(lineptr[1] & 255)) lineptr ++; } text = lineptr + 1; } } else if (!text) { if (*lineptr == '\\' && lineptr[1] && lineptr[1] != '\n') { /* * Escaped character... */ lineptr ++; } text = lineptr; } else if (*lineptr == '\\' && lineptr[1] && lineptr[1] != '\n') { /* * Escaped character... */ memmove(lineptr, lineptr + 1, strlen(lineptr)); } } if (text) mmd_add(parent, type, whitespace, text, NULL); } /* * 'mmd_parse_link()' - Parse a link. */ static char * /* O - End of link text */ mmd_parse_link(_mmd_doc_t *doc, /* I - Document */ char *lineptr, /* I - Pointer into line */ char **text, /* O - Text */ char **url, /* O - URL */ char **title, /* O - Title, if any */ char **refname) /* O - Reference name */ { lineptr ++; /* skip "[" */ *text = lineptr; *url = NULL; *refname = NULL; if (title) *title = NULL; while (*lineptr && *lineptr != ']') { if (*lineptr == '\"' || *lineptr == '\'') { char quote = *lineptr++; while (*lineptr && *lineptr != quote) lineptr ++; if (!*lineptr) return (lineptr); } lineptr ++; } if (!*lineptr) return (lineptr); *lineptr++ = '\0'; if (*lineptr == '(') { /* * Get URL... */ lineptr ++; *url = lineptr; while (*lineptr && *lineptr != ')') { if (isspace(*lineptr & 255)) *lineptr = '\0'; else if (*lineptr == '\"' || *lineptr == '\'') { char quote = *lineptr++; if (title) *title = lineptr; while (*lineptr && *lineptr != quote) lineptr ++; if (!*lineptr) return (lineptr); else if (title) *lineptr = '\0'; } lineptr ++; } *lineptr++ = '\0'; } else if (*lineptr == '[') { /* * Get reference... */ lineptr ++; *refname = lineptr; while (*lineptr && *lineptr != ']') { if (isspace(*lineptr & 255)) *lineptr = '\0'; else if (*lineptr == '\\' && lineptr[1]) { /* * Remove \ */ memmove(lineptr, lineptr + 1, strlen(lineptr)); } else if (*lineptr == '\"' || *lineptr == '\'') { char quote = *lineptr++; if (title) *title = lineptr; while (*lineptr && *lineptr != quote) lineptr ++; if (!*lineptr) return (lineptr); else *lineptr = '\0'; } lineptr ++; } *lineptr++ = '\0'; if (!**refname) *refname = *text; } else if (*lineptr == ':') { /* * Get reference definition... */ lineptr ++; while (*lineptr && isspace(*lineptr & 255)) lineptr ++; *url = lineptr; while (*lineptr && !isspace(*lineptr & 255)) lineptr ++; if (*lineptr) { *lineptr++ = '\0'; while (*lineptr && isspace(*lineptr & 255)) lineptr ++; if (*lineptr == '\"' || *lineptr == '\'') { char quote = *lineptr++; if (title) *title = lineptr; while (*lineptr && *lineptr != quote) lineptr ++; if (!*lineptr) return (lineptr); else *lineptr = '\0'; } } mmd_ref_add(doc, NULL, *text, *url, title ? *title : NULL); *text = NULL; *url = NULL; if (title) *title = NULL; } else { /* * Shortcut reference... */ *refname = *text; } return (lineptr); } /* * 'mmd_read_buffer()' - Fill the file buffer with more data from a file. */ static void mmd_read_buffer(_mmd_filebuf_t *file) /* I - File buffer */ { size_t bytes; /* Bytes read */ if (file->bufptr && file->bufptr > file->buffer) { /* * Discard previous characters in the buffer. */ memmove(file->buffer, file->bufptr, file->bufend - file->bufptr); file->bufend -= (file->bufptr - file->buffer); } else { /* * Otherwise just clear the buffer... */ file->bufend = file->buffer; } if ((bytes = fread(file->bufend, 1, sizeof(file->buffer) - (size_t)(file->bufend - file->buffer - 1), file->fp)) > 0) file->bufend += bytes; *(file->bufend) = '\0'; file->bufptr = file->buffer; } /* * 'mmd_read_line()' - Read a line from a file in a Markdown-aware way. */ static char * /* O - Pointer to line or `NULL` on EOF */ mmd_read_line(_mmd_filebuf_t *file, /* I - File buffer */ char *line, /* I - Line buffer */ size_t linesize) /* I - Size of line buffer */ { int ch, /* Current character */ column = 0; /* Current column */ char *lineptr = line, /* Pointer into line */ *lineend = line + linesize - 1; /* Pointer to end of buffer */ /* * Fill the buffer as needed... */ if (!file->bufptr || (file->bufptr >= file->bufend) || !strchr(file->bufptr, '\n')) mmd_read_buffer(file); /* * Copy a line out of the file buffer... */ while (file->bufptr < file->bufend) { ch = *(file->bufptr); file->bufptr ++; if (ch == '\t') { /* * Expand tabs since nobody uses the same tab width and Markdown says * 4 columns per tab... */ do { column ++; if (lineptr < lineend) *lineptr++ = ' '; } while (column & 3); } else if (ch != '\r' && lineptr < lineend) { column ++; *lineptr++ = ch; } if (ch == '\n') break; } *lineptr = '\0'; if (file->bufptr == file->bufend && lineptr == line) return (NULL); else if (!strchr(file->bufptr, '\n')) mmd_read_buffer(file); return (line); } /* * 'mmd_ref_add()' - Add or update a reference... */ static void mmd_ref_add(_mmd_doc_t *doc, /* I - Document */ mmd_t *node, /* I - Link node, if any */ const char *name, /* I - Reference name */ const char *url, /* I - Reference URL */ const char *title) /* I - Title, if any */ { size_t i; /* Looping var */ _mmd_ref_t *ref = mmd_ref_find(doc, name); /* Reference */ DEBUG2_printf("mmd_ref_add(doc=%p, node=%p, name=\"%s\", url=\"%s\", title=\"%s\")\n", doc, node, name, url, title); if (ref) { DEBUG2_printf("mmd_ref_add: ref=%p, ref->url=\"%s\"\n", ref, ref->url); if (!ref->url && url) { if (node) node->url = strdup(url); ref->url = strdup(url); if (title) { if (node) node->extra = strdup(title); ref->title = strdup(title); } for (i = 0; i < ref->num_pending; i ++) { ref->pending[i]->url = strdup(url); if (title) ref->pending[i]->extra = strdup(title); } free(ref->pending); ref->num_pending = 0; ref->pending = NULL; return; } } else if ((ref = realloc(doc->references, (doc->num_references + 1) * sizeof(_mmd_ref_t))) != NULL) { doc->references = ref; ref += doc->num_references; doc->num_references ++; ref->name = strdup(name); ref->url = url ? strdup(url) : NULL; ref->title = title ? strdup(title) : NULL; ref->num_pending = 0; ref->pending = NULL; } else return; if (node) { if (ref->url) { node->url = strdup(ref->url); node->extra = ref->title ? strdup(ref->title) : NULL; } else if ((ref->pending = realloc(ref->pending, (ref->num_pending + 1) * sizeof(mmd_t *))) != NULL) { ref->pending[ref->num_pending ++] = node; } } } /* * 'mmd_ref_find()' - Find a reference... */ static _mmd_ref_t * /* O - Reference or NULL */ mmd_ref_find(_mmd_doc_t *doc, /* I - Document */ const char *name) /* I - Reference name */ { size_t i; /* Looping var */ for (i = 0; i < doc->num_references; i ++) if (!strcasecmp(name, doc->references[i].name)) return (doc->references + i); return (NULL); } /* * 'mmd_remove()' - Remove a node from its parent. */ static void mmd_remove(mmd_t *node) /* I - Node */ { if (node->parent) { if (node->prev_sibling) node->prev_sibling->next_sibling = node->next_sibling; else node->parent->first_child = node->next_sibling; if (node->next_sibling) node->next_sibling->prev_sibling = node->prev_sibling; else node->parent->last_child = node->prev_sibling; node->parent = NULL; node->prev_sibling = NULL; node->next_sibling = NULL; } } #if DEBUG /* * 'mmd_type_string()' - Return a string for the specified type enumeration. */ static const char * /* O - String representing the type */ mmd_type_string(mmd_type_t type) /* I - Type value */ { static char unknown[64]; /* Unknown type buffer */ switch (type) { case MMD_TYPE_NONE : return ("MMD_TYPE_NONE"); case MMD_TYPE_DOCUMENT : return "MMD_TYPE_DOCUMENT"; case MMD_TYPE_METADATA : return "MMD_TYPE_METADATA"; case MMD_TYPE_BLOCK_QUOTE : return "MMD_TYPE_BLOCK_QUOTE"; case MMD_TYPE_ORDERED_LIST : return "MMD_TYPE_ORDERED_LIST"; case MMD_TYPE_UNORDERED_LIST : return "MMD_TYPE_UNORDERED_LIST"; case MMD_TYPE_LIST_ITEM : return "MMD_TYPE_LIST_ITEM"; case MMD_TYPE_TABLE : return "MMD_TYPE_TABLE"; case MMD_TYPE_TABLE_HEADER : return "MMD_TYPE_TABLE_HEADER"; case MMD_TYPE_TABLE_BODY : return "MMD_TYPE_TABLE_BODY"; case MMD_TYPE_TABLE_ROW : return "MMD_TYPE_TABLE_ROW"; case MMD_TYPE_HEADING_1 : return "MMD_TYPE_HEADING_1"; case MMD_TYPE_HEADING_2 : return "MMD_TYPE_HEADING_2"; case MMD_TYPE_HEADING_3 : return "MMD_TYPE_HEADING_3"; case MMD_TYPE_HEADING_4 : return "MMD_TYPE_HEADING_4"; case MMD_TYPE_HEADING_5 : return "MMD_TYPE_HEADING_5"; case MMD_TYPE_HEADING_6 : return "MMD_TYPE_HEADING_6"; case MMD_TYPE_PARAGRAPH : return "MMD_TYPE_PARAGRAPH"; case MMD_TYPE_CODE_BLOCK : return "MMD_TYPE_CODE_BLOCK"; case MMD_TYPE_THEMATIC_BREAK : return "MMD_TYPE_THEMATIC_BREAK"; case MMD_TYPE_TABLE_HEADER_CELL : return "MMD_TYPE_TABLE_HEADER_CELL"; case MMD_TYPE_TABLE_BODY_CELL_LEFT : return "MMD_TYPE_TABLE_BODY_CELL_LEFT"; case MMD_TYPE_TABLE_BODY_CELL_CENTER : return "MMD_TYPE_TABLE_BODY_CELL_CENTER"; case MMD_TYPE_TABLE_BODY_CELL_RIGHT : return "MMD_TYPE_TABLE_BODY_CELL_RIGHT"; case MMD_TYPE_NORMAL_TEXT : return "MMD_TYPE_NORMAL_TEXT"; case MMD_TYPE_EMPHASIZED_TEXT : return "MMD_TYPE_EMPHASIZED_TEXT"; case MMD_TYPE_STRONG_TEXT : return "MMD_TYPE_STRONG_TEXT"; case MMD_TYPE_STRUCK_TEXT : return "MMD_TYPE_STRUCK_TEXT"; case MMD_TYPE_LINKED_TEXT : return "MMD_TYPE_LINKED_TEXT"; case MMD_TYPE_CODE_TEXT : return "MMD_TYPE_CODE_TEXT"; case MMD_TYPE_IMAGE : return "MMD_TYPE_IMAGE"; case MMD_TYPE_HARD_BREAK : return "MMD_TYPE_HARD_BREAK"; case MMD_TYPE_SOFT_BREAK : return "MMD_TYPE_SOFT_BREAK"; case MMD_TYPE_METADATA_TEXT : return "MMD_TYPE_METADATA_TEXT"; default : snprintf(unknown, sizeof(unknown), "?? %d ??", (int)type); return (unknown); } } #endif /* DEBUG */ htmldoc-1.9.7/htmldoc/mmd.h000066400000000000000000000062521354715574200155640ustar00rootroot00000000000000/* * Header file for miniature markdown library. * * https://github.com/michaelrsweet/mmd * * Copyright © 2017-2019 by Michael R Sweet. * * Licensed under Apache License v2.0. See the file "LICENSE" for more * information. */ #ifndef MMD_H # define MMD_H /* * Include necessary headers... */ # include /* * Constants... */ enum mmd_option_e { MMD_OPTION_NONE = 0x00, /* No markdown extensions */ MMD_OPTION_METADATA = 0x01, /* Jekyll metadata extension */ MMD_OPTION_TABLES = 0x02, /* Github table extension */ MMD_OPTION_ALL = 0x03 /* All supported markdown extensions */ }; typedef unsigned mmd_option_t; typedef enum mmd_type_e { MMD_TYPE_NONE = -1, MMD_TYPE_DOCUMENT, /* The document root */ MMD_TYPE_METADATA, /* Document metadata */ MMD_TYPE_BLOCK_QUOTE, /*
    */ MMD_TYPE_ORDERED_LIST, /*
      */ MMD_TYPE_UNORDERED_LIST, /*